2
votes

I am working on a big GUI, the essential structure of which is quite elementary and can be simply reduced to two interconnected controls (each one updates the value of the other): a slider and an edit box. The value they share is used to make a plot. If you run the following code, you find that you can change the value (by moving the slide or editing the box) only once. The second time, it will throw an error. The main questions are: WHY? HOW SHOULD GUIHANDLES BE USED INSTEAD?

function GuiHandleShare1

handles.figure=figure;

handles.edit=uicontrol('Style','Edit',...
                       'Position',[5  5 50 20],...
                       'Callback',@edit_callback,...
                       'Tag','edit');
handles.slider=uicontrol('Style','Slider',...
                         'Position',[55 5 500 20],...
                         'Callback',@slider_callback,...
                         'Tag','slider');
handles.axes=axes('OuterPosition',[0.1 0.1 0.8 0.8],...
                  'Tag','axes');

function plotter
handles=guihandles;
plot(handles.axes,[0 1],[0 str2num(get(handles.edit,'String'))])

function edit_callback(h,eventdata)
handles=guihandles;
set(handles.slider,'Value',str2num(get(handles.edit,'String')));
plotter

function slider_callback(h,eventdata)
handles=guihandles;
set(handles.edit,'string',num2str(get(handles.slider,'Value')));
plotter

I tried to find the answer by digging into the code of guihandles, but just as guidata, it is a wrapper for getappdata, setappdata, etc., the source of which is not available (Matlab R2008b).

I already know other solutions for a GUI of this kind: 1- Instead of using guihandles, guidata or others of that kind, I use global variables. 2- Use nested functions.

Nested functions is not an option in the case I'm working on because that would make the main function workspace a static workspace. This is not what I want because of the way I have to manage variables in the application. I ended up using global variables: I declared the handles as global inside every function that needs them and it is working fine. Does this have any disadvantage? I mean, if we can use global variables, why did Matlab come up with commands like guihandles, guidata, etc.?

2
I think you need to define the axes before each plot, i.e. to add handles.axes one line before the plot line inside the plotter function. Otherwise, he probably try to plot it somewhere, in the same or in other figure, and crash.Adiel

2 Answers

3
votes

You have to use this property/value pair:

'NextPlot' ,'ReplaceChildren'

in the definition of your axes at the very beginning, otherwise the GUI creates a new figure after the 1st plot and the tag associated with the axes at the beginning is no longer valid. Actually if you type

get(handles.axes)

after creating it you will see that this property is set to 'replace', which replace the entire axes instead of its children. Therefore the code would look like this:

handles.axes=axes('OuterPosition',[0.1 0.1 0.8 0.8],...
                  'Tag','axes','NextPlot' ,'ReplaceChildren');

As a workaround to global variables you could also use findobj to detect the axes and then plot in it:

function plotter

hAx = findobj('Type','axes')
handles=guihandles;
plot([0 1],[0 str2num(get(handles.edit,'String'))],'parent',hAx);

but it's not very convenient if you have more than one axes.

As far as I know, global variables in GUIs make the code easier to implement, however the one caveat I know of is that if you plan to deploy a standalone application from your GUI it will throw tons of errors during compilation and you will have to get rid of them.

Anyhow using the code above works fine for me. Hope that helps!

3
votes

I think you misunderstood the function guihandles(), which gives you a list of real handles in the figure, not the same as guidata(). In fact, try rename your handles.axes to handles.axes1, and you'll see it fails on the first callback.

This code uses guidata() to save and retrieve data (comments at end of lines).

function GuiHandleShare1

handles.figure=figure;

handles.edit=uicontrol('Style','Edit',...
                       'Position',[5  5 50 20],...
                       'Callback',@edit_callback,...
                       'Tag','edit');
handles.slider=uicontrol('Style','Slider',...
                         'Position',[55 5 500 20],...
                         'Callback',@slider_callback,...
                         'Tag','slider');
handles.axes1=axes('OuterPosition',[0.1 0.1 0.8 0.8],...
                  'Tag','axes');
guidata(handles.figure, handles); % save handles to GUIDATA

function plotter
handles=guidata(gcf); % retrieve handles from GUIDATA
plot(handles.axes1,[0 1],[0 str2num(get(handles.edit,'String'))])

function edit_callback(h,eventdata)
handles=guidata(gcf);
set(handles.slider,'Value',str2num(get(handles.edit,'String')));
plotter

function slider_callback(h,eventdata)
handles=guidata(gcf);
set(handles.edit,'string',num2str(get(handles.slider,'Value')));
plotter