Scope of 'ButtonDownFcn' property of lines in structure [R2017b]
5 views (last 30 days)
Show older comments
Hello,
My question is regarding the scope of the ButtonDownFcn in two scenarios when used for selecting lines plotted in a figure.
Scenario 1: I have a push button callback from a GUIDE created GUI that plots two lines:
function pushbutton_Plot_Callback(hObject, eventdata, handles)
handles.P(1) = line(handles.Plot1, 'XData', handles.x', 'YData', handles.y1, 'Color', 'Blue', 'Tag', 'Ch1', 'ButtonDownFcn', {@LineSelected, handles} );
handles.P(2) = line(handles.Plot1, 'XData', handles.x', 'YData', handles.y2, 'Color', 'Green', 'Tag', 'Ch2', 'ButtonDownFcn', {@LineSelected, handles} );
For both scenarios the function LineSelected is called clicking on a line in the figure. The LineSelected function for scenario 1 is:
function LineSelected(hObject, eventdata, handles)
handles.strTag = get(hObject, 'Tag');
switch handles.strTag
case 'Ch1'
delete(handles.P(1));
handles.P(1) = line(handles.Plot1, 'XData', handles.x', 'YData', -handles.y1, 'Color', 'Blue', 'Tag', 'Ch1', 'ButtonDownFcn', {@LineSelected, handles} );
case 'Ch2'
delete(handles.P(2));
handles.P(2) = line(handles.Plot1, 'XData', handles.x', 'YData', -handles.y2, 'Color', 'Green', 'Tag', 'Ch2', 'ButtonDownFcn', {@LineSelected, handles} );
In scenario 1 if I click the 'Ch2' line I keep getting an error saying 'index exceeds matrix dimensions' and if I step through the program in the debugger, I see handles contained handles.P which consists of 2 lines but once the program steps into the LineSelected function is only consists of one elements and therefore one line. It seems the other line is outside the scope of the function even though I have said the entire handles structure should eb passed as an argument to the function.
Scenario 2: I have a push button callback from a GUIDE created GUI that plots two lines:
function pushbutton_Plot_Callback(hObject, eventdata, handles)
handles.P(1) = line(handles.Plot1, 'XData', handles.x', 'YData', handles.y1, 'Color', 'Blue', 'Tag', 'Ch1');
handles.P(2) = line(handles.Plot1, 'XData', handles.x', 'YData', handles.y2, 'Color', 'Green', 'Tag', 'Ch2');
set(handles.P, 'ButtonDownFcn', {@LineSelected, handles} );
function LineSelected(hObject, eventdata, handles)
handles.strTag = get(hObject, 'Tag');
switch handles.strTag
case 'Ch1'
delete(handles.P(1));
handles.P(1) = line(handles.Plot1, 'XData', handles.x', 'YData', -handles.y1, 'Color', 'Blue', 'Tag', 'Ch1');
case 'Ch2'
delete(handles.P(2));
handles.P(2) = line(handles.Plot1, 'XData', handles.x', 'YData', -handles.y2, 'Color', 'Green', 'Tag', 'Ch2' );
set(handles.h, 'ButtonDownFcn', {@LineSelected, handles}
In scenario 2 when I call the LineSelect function the function seems to have access to both handles.P(1) and handles.P(2). I am not sure why this is the case because from what I understand both methods are just setting the properties of the 'ButtonDownFcn' to {@LineSelected, handles}.
0 Comments
Accepted Answer
Rik
on 14 Jan 2018
To avoid these confusing bugs, it may be simpler to recreate the handles variable when you call the function:
'ButtonDownFcn', @(hObject,eventdata)LineSelected(hObject,eventdata,guidata(hObject))
(of course you should have preceded this by having saved the data to guidata)
4 Comments
Rik
on 15 Jan 2018
I hope you understand the phrasing by Steven Lord, because that is also what I meant with my initial answer. You need to be careful when it is you load the guidata. That is one of the reasons why I don't use the cell syntax: it makes this more difficult (also I didn't know it until a few weeks back).
More Answers (1)
Steven Lord
on 15 Jan 2018
"Now when I look at what is in handles.y2, the original values which I set in the initialisation function are still there so it seems that the handles.y2 variable was not updated."
That is correct. Look at your code:
handles.h(1) = line(handles.axes1, 'XData', handles.x, ...
'YData', handles.y1, 'color','blue','Tag','1', ...
'ButtonDownFcn',{@select, handles});
The last part of that command creates a cell array with two elements. The first element of the cell array is a function handle. The second element of the cell array is a copy of the handles struct array as it exists when that command gets executed. Changing the handles structure later on has no effect on the copy created by this line.
Instead of passing the handles structure in as an input, retrieve the handles structure inside the select function. The first input to the ButtonDownFcn will be the handle to the line. Use the guidata function with that line handle as input to retrieve the handles structure.
2 Comments
Rik
on 15 Jan 2018
Because the hObject is the same each time. You could compare it to an address: the building stays at the same place, the people might move. If you want to use the number of people in the house, you don't hard-code the number of people, you load the number of people in the house with guidata.
Could you also accept the answer that solves your problem best?
See Also
Categories
Find more on Interactive Control and Callbacks 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!