How to get an output from a callback function?

74 views (last 30 days)
Mark Golberg
Mark Golberg on 21 Jul 2016
Edited: Guillaume on 21 Jul 2016
Hello,
I am trying to get the CurrentPoint of the mouse extracted outside of my WindowButtonDownFcn for a my figure. I have the following line in my main script:
set(gcf,'WindowButtonDownFcn',@mg_BPP_mouseClick)
Whereas mg_BPP_mouseClick function defined as:
function [C] = mg_BPP_mouseClick(object,eventData)
C = get (gca, 'CurrentPoint');
end
I don't know what's the syntax for output variable in such callback formation?
Note: I DON'T want to use the solution of:
assignin('base','C',C)
inside my mg_BPP_mouseClick function.

Answers (3)

Walter Roberson
Walter Roberson on 21 Jul 2016
The only kind of callbacks that can return values are callbacks that are filters, such as the datacursormode update function. None of the uicontrol callbacks are filters.
You need to save the data to somewhere safe, and have the routine that needs it pull it out from there.

Guillaume
Guillaume on 21 Jul 2016
"I am trying to get the CurrentPoint of the mouse extracted outside of my WindowButtonDownFcn" But what does that mean exactly?
A callback can be triggered at any time. Your program may be in function A when it occurs, or function B. Who should the callback return the value to?
As you can see, it's not possible to return a value from a callback because it does not make sense.
If you want to transmit data from a callback to another part of the program, there are several techniques available (global, assignin) but the cleanest is probably setappdata and getappdata. However, is it really needed? Whatever action should be taken on a mousedown event normally occurs within the callback.
  4 Comments
Walter Roberson
Walter Roberson on 21 Jul 2016
setappdata/getappdata. Or set and fetch UserData. Or create a couple of nested functions to do the work for you, since scripts are permitted to call functions.
Guillaume
Guillaume on 21 Jul 2016
Edited: Guillaume on 21 Jul 2016
Mark, the problem is that the actual steps of the program are:
1. Script opens a figure
2. Script creates callback function for mouse down event
In parallel:
3a. Script continues on its merry way doing whatever it is doing
3b. User clicks on the window. It's unknown which line of the script is currently executing.
The script can of course wait for the callback to be called (but then you may as well use ginput).
Or possibly, the script is in a loop and in each loop iteration, uses whichever last point was last clicked. In that case, use setappdata / getappdata, or the Tag or UserData property of the figure to store the last clicked location.
But in any case, callback and scripts are executing asynchronously.

Sign in to comment.


Adam
Adam on 21 Jul 2016
Edited: Adam on 21 Jul 2016
If you want to get into using object-oriented programming you can do something like this:
Define a class derived from handle (i.e. it will be passed by reference - you can read more about what deriving from handle means in the documentation if you wish, this isn't its only effect):
classdef CurrentPoint < handle
properties
value = [];
end
end
then you can have your main code work something like this:
function doSomeStuff( )
hFig = figure; hAxes = axes;
point = CurrentPoint;
set( hFig, 'WindowButtonDownFcn', @( src, evt ) mouseClick( hAxes, point ) )
pause( 3 )
point.value
end
function mouseClick( hAxes, point )
point.value = get( hAxes, 'CurrentPoint' );
end
Obviously that is just a simple example to show that the current point is stored. I should mention I added the 'pause(3)' instruction to give me enough time to click on the axes in order to test this, then point.value displays the current point after the pause.
I would not program this in precisely this way as obviously it depends what you want to do with the current point. Usually you would want to attach a listener to the CurrentPoint object in order to know when its value changes and then trigger a callback in response to this, but that all depends where you are using it. This example just demonstrates the general idea of passing in an object by reference whose value will then get filled in within the callback and be available outside the callback (wherever you have an instance of the object). But clearly the fact I had to put a pause instruction in and then click on the axes within those 3s in order to test it highlights the need for a listener-type scenario.
Also because I am fussy I would add more to the class to validate things, but if you are interested in that you can read up on Matlab OOP and things like validateattributes which is useful irrespective of whether your function is in a class or standalone.

Categories

Find more on Interactive Control and Callbacks in Help Center and File Exchange

Products

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!