GUIDATA does not trasfer data in GUIDE with subfunctions.

1 view (last 30 days)
I have a simple GUIDE with 2 pushbuttons. Button #1 plots a sine graph and button #2 adds a "draggable" vertical line to the graph. Idea is based on the link bellow [1]
I'm using guidata to transfer data between subfunctions and callbacks in the `GUIDE`. But one of the shared variables (mousedown) does not transmit between the callbacks. What causes the loss of data transfer between the subfunctions in GUIDE?
Here are the callbacks with their subfunctions (the entire code is attached):
% ######### Callbacl 1: Graph SIN function
function pushbutton_plot_Callback(hObject, eventdata, handles)
clc;
open_figs_h = get(0,'children');
close(open_figs_h(2:end));
x = -pi:0.01:pi;
y = sin(x);
fig_h = figure('units','normalized','outerposition',[0.2 0.2 .5 .5],'WindowButtonMotionFcn', @MouseMove, 'WindowButtonUpFcn', @MouseUp );
axis_h = axes('parent',fig_h,'position',[0.1 0.1 .8 .8]);
line('parent',axis_h,'xdata',x,'ydata',y);
handles.axis_h = axis_h;
guidata(hObject,handles);
% MouseUp and MouseMove subfunctions in callback 1
function MouseUp(h,event) %#ok<*INUSD>
mousedown = false;
end
function MouseMove(h,event)
if isfield(handles,mousedown)
mousedown = handles.mousedown;
else
mousedown = false;
end
if mousedown
cp = get ( axis_h, 'CurrentPoint' );
vertline_h = handles.vertline_h;
set ( vertline_h, 'XData', [cp(1,1) cp(1,1)] );
end
end
end
%######### Callbacl 2: Graph movables vertical line
function pushbutton_vertline_Callback(h, eventdata,handles)
axis_h = handles.axis_h;
vertline_h = line('parent',axis_h,'xdata',[1 1],'ydata',[-1 1], 'ButtonDownFcn', @mouseDown );
handles.vertline_h = vertline_h;
guidata(h,handles)
% MouseMove subfunction in callback 2
function mouseDown(hObject,event)
mousedown = true;
handles.mousedown = mousedown;
guidata(hObject,handles)
end
end

Accepted Answer

Geoff Hayes
Geoff Hayes on 29 Oct 2016
Alborz - your code has interesting approach by assigning the ButtonDownFcn to the line object so that when the user presses down on the line (and only the line), this event will fire. Though instead of calling guidata with hObject which is the handle to the line object, you probably want to call it with the handle to the button, h, since it is a child of the GUI and the handles structure is "associated" with that. So the pushbutton_vertline_Callback code would change to
function pushbutton_vertline_Callback_Callback(hButton, eventdata,handles)
axis_h = handles.axis_h;
vertline_h = line('parent',axis_h,'xdata',[1 1],'ydata',[-1 1], 'ButtonDownFcn', @mouseDown );
handles.vertline_h = vertline_h;
guidata(h,handles)
% MouseMove subfunction in callback 2
function mouseDown(hObject,event)
mousedown = true;
handles.mousedown = mousedown;
guidata(hButton,handles)
end
end
Like Walter has indicated, your mousedown variable is local to the MouseUp function and so setting it to true won't affect the field within the handles structure. So this function should change to
function MouseUp(h,event) %#ok<*INUSD>
handles = guidata(hObject);
handles.mousedown = false;
guidata(hObject,handles);
end
Note how in the above code, we use hObject (the handle to the pushbutton_plot) to get the latest updated version of handles rather than the older copy from the pushbutton_plot_Callback callback. So we get the latest version, change the mousedown field, and then save the updated handles structure.
And the MouseMove is almost correct with the only problem being that the handles of copy being used rather than the latest version. Again, we just need to call guidata as
function MouseMove(h,event)
handles = guidata(hObject);
if isfield(handles,'mousedown')
mousedown = handles.mousedown;
else
mousedown = false;
end
if mousedown
cp = get ( axis_h, 'CurrentPoint' );
vertline_h = handles.vertline_h;
set ( vertline_h, 'XData', [cp(1,1) cp(1,1)] );
end
end
See below for the full code which should work.
% Callbacl 1: Graph SIN function
function pushbutton_plot_Callback(hObject, eventdata, handles)
clc;
open_figs_h = get(0,'children');
close(open_figs_h(2:end));
x = -pi:0.01:pi;
y = sin(x);
fig_h = figure('units','normalized','outerposition',[0.2 0.2 .5 .5],...
'WindowButtonMotionFcn', @MouseMove, 'WindowButtonUpFcn', @MouseUp );
axis_h = axes('parent',fig_h,'position',[0.1 0.1 .8 .8]);
line('parent',axis_h,'xdata',x,'ydata',y);
handles.axis_h = axis_h;
guidata(hObject,handles);
% MouseUp and MouseMove subfunctions in callback 1
function MouseUp(h,event) %#ok<*INUSD>
handles = guidata(hObject);
handles.mousedown = false;
guidata(hObject,handles);
end
function MouseMove(h,event)
handles = guidata(hObject);
if isfield(handles,'mousedown')
mousedown = handles.mousedown;
else
mousedown = false;
end
if mousedown
cp = get ( axis_h, 'CurrentPoint' );
vertline_h = handles.vertline_h;
set ( vertline_h, 'XData', [cp(1,1) cp(1,1)] );
end
end
end
% Callbacl 2: Graph movables vertical line
function pushbutton_vertline_Callback(hButton, eventdata,handles)
axis_h = handles.axis_h;
vertline_h = line('parent',axis_h,'xdata',[1 1],'ydata',[-1 1], 'ButtonDownFcn', @mouseDown );
handles.vertline_h = vertline_h;
guidata(h,handles)
% MouseMove subfunction in callback 2
function mouseDown(hObject,event)
mousedown = true;
handles.mousedown = mousedown;
guidata(hButton,handles)
end
end
  2 Comments
Alborz Sakhaei
Alborz Sakhaei on 29 Oct 2016
Thank you very much Geoff. Appreciate your time. That completely resolved my issue. Just one minor comment: In pushbutton_vertline_Callback the line guidata(h,handles) should be guidata(hButton,handles). Please correct me if I'm mistaken. Thanks again, Alborz
Geoff Hayes
Geoff Hayes on 30 Oct 2016
For sure, Alborz. Yes, you are correct - the line should read
guidata(hButton,handles)

Sign in to comment.

More Answers (1)

Walter Roberson
Walter Roberson on 28 Oct 2016
In order for a variable to be shared it must be initialized in the containing routine before the declaration of the subfunctions that share it. It then becomes shared only with the containing and contained routines.
You are not using the mousedown variable in a shared way. Even if you had initialized it before the subfunctions, in the second subfunction you test whether handles has a field with that name and if so then you grab that value and if not then you force the variable to false. Any shared value would be overwritten. No other routines read the shared value so that is not for the benefit of some other routine.
Consider too that you do not delete out of handles when you poll in the nested function so the next time through you would pull from the handles again. You have no code that sets the handles version to false or removes it, so once set the handles version is going to remain true.

Categories

Find more on Tables in Help Center and File Exchange

Community Treasure Hunt

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

Start Hunting!