Discover MakerZone

MATLAB and Simulink resources for Arduino, LEGO, and Raspberry Pi

Learn more

Discover what MATLAB® can do for your career.

Opportunities for recent engineering grads.

Apply Today

Thread Subject:
Setting GUI callbacks

Subject: Setting GUI callbacks

From: Jane T

Date: 21 Jun, 2011 16:00:10

Message: 1 of 7

I'm trying to build a GUI to house the data simulator I am building, but I'm have problems setting up my callbacks to pass variables. I've built a very simplified GUI to illustrate the problem I'm having in the hopes you might be able to help me.

If I use the edit box to change the varaible of s.var1 then the function is able to 'see' this new value, however if I then update the value of s.var2 then the update of s.var1 is lost and it's value in the structure has returned to the default.

It seems that I'm not correctly passing the structure s out of the simulate function, but being a GUI I have no idea where to even set the breakpoint to see what is going on in the main function.

I'm running Matlab 2011a

Thanks for your time
Jane

function callbackIssue()
    s.var1 = 2;
    s.var2 = 6;
    s.var3 = 11;

    fig = figure;
    for i = 1:3
        h.(['testEdit',num2str(i)]) = uicontrol('Parent',fig,...
            'Style','Edit',...
            'HorizontalAlignment','left',...
            'BackgroundColor','w',...
            'String',s.(['var',num2str(i)]),...
            'Tag',['var',num2str(i)],...
            'Position',[100*i 20 80 20]);
        set(h.(['testEdit',num2str(i)]),...
            'Callback',{@simulate,s});
    end
end

function [hobject,eventdata,s] = simulate(hobject,eventdata,s)
    disp([get(hobject,'Tag'),' = ',get(hobject,'String')]);
    s.(get(hobject,'Tag')) = str2num(get(hobject,'String'));
    disp(s);
end

Subject: Setting GUI callbacks

From: Doug Schwarz

Date: 21 Jun, 2011 16:17:43

Message: 2 of 7

On 6/21/2011 12:00 PM, Jane T wrote:
> I'm trying to build a GUI to house the data simulator I am building, but
> I'm have problems setting up my callbacks to pass variables. I've built
> a very simplified GUI to illustrate the problem I'm having in the hopes
> you might be able to help me.
>
> If I use the edit box to change the varaible of s.var1 then the function
> is able to 'see' this new value, however if I then update the value of
> s.var2 then the update of s.var1 is lost and it's value in the structure
> has returned to the default.
>
> It seems that I'm not correctly passing the structure s out of the
> simulate function, but being a GUI I have no idea where to even set the
> breakpoint to see what is going on in the main function.
>
> I'm running Matlab 2011a
>
> Thanks for your time
> Jane
>
> function callbackIssue()
> s.var1 = 2;
> s.var2 = 6;
> s.var3 = 11;
>
> fig = figure;
> for i = 1:3
> h.(['testEdit',num2str(i)]) = uicontrol('Parent',fig,...
> 'Style','Edit',...
> 'HorizontalAlignment','left',...
> 'BackgroundColor','w',...
> 'String',s.(['var',num2str(i)]),...
> 'Tag',['var',num2str(i)],...
> 'Position',[100*i 20 80 20]);
> set(h.(['testEdit',num2str(i)]),...
> 'Callback',{@simulate,s});
> end
> end
>
> function [hobject,eventdata,s] = simulate(hobject,eventdata,s)
> disp([get(hobject,'Tag'),' = ',get(hobject,'String')]);
> s.(get(hobject,'Tag')) = str2num(get(hobject,'String'));
> disp(s);
> end

You don't show the structure of your whole app, but these two callback
functions must be nested functions of the main gui function. Also,
callbacks can't return anything; they must operate on variables in the
main gui workspace. Something like this:

function maingui
s = [];
h = [];
   function callbackIssue()
     ...
     h.testEdit1 = uicontrol(...,'Callback',{@simulate,1})
     h.testEdit2 = uicontrol(...,'Callback',{@simulate,2})
   end
   function simulate(h,evt,index)
     s.(['field',num2str(index)]) = get(h,'String');
   end
end


--
Doug Schwarz
dmschwarz&ieee,org
Make obvious changes to get real email address.

Subject: Setting GUI callbacks

From: Steven_Lord

Date: 21 Jun, 2011 16:35:58

Message: 3 of 7



"Jane T" <jterry@boreal-laser.com> wrote in message
news:itqf6a$lae$1@newscl01ah.mathworks.com...
> I'm trying to build a GUI to house the data simulator I am building, but
> I'm have problems setting up my callbacks to pass variables. I've built a
> very simplified GUI to illustrate the problem I'm having in the hopes you
> might be able to help me.
>
> If I use the edit box to change the varaible of s.var1 then the function
> is able to 'see' this new value, however if I then update the value of
> s.var2 then the update of s.var1 is lost and it's value in the structure
> has returned to the default.
>
> It seems that I'm not correctly passing the structure s out of the
> simulate function, but being a GUI I have no idea where to even set the
> breakpoint to see what is going on in the main function.
>
> I'm running Matlab 2011a
>
> Thanks for your time
> Jane
>
> function callbackIssue()
> s.var1 = 2;
> s.var2 = 6;
> s.var3 = 11;
>
> fig = figure;
> for i = 1:3
> h.(['testEdit',num2str(i)]) = uicontrol('Parent',fig,...
> 'Style','Edit',...
> 'HorizontalAlignment','left',...
> 'BackgroundColor','w',...
> 'String',s.(['var',num2str(i)]),...
> 'Tag',['var',num2str(i)],...
> 'Position',[100*i 20 80 20]);
> set(h.(['testEdit',num2str(i)]),...
> 'Callback',{@simulate,s});

When you define the callback this way, simulate will be called with a copy
of s as it exists RIGHT NOW when your SET call executes. Any changes to s
later on will NOT affect the copy of s inside the cell array (which is the
copy that's passed into simulate when the callback executes.

> end
> end
>
> function [hobject,eventdata,s] = simulate(hobject,eventdata,s)
> disp([get(hobject,'Tag'),' = ',get(hobject,'String')]);
> s.(get(hobject,'Tag')) = str2num(get(hobject,'String'));
> disp(s);
> end

If simulate were nested inside callbackIssue then you wouldn't need to (and
shouldn't) pass it into simulate as an input. Since it isn't, you will need
to use some technique (like storing s inside the figure's UserData property,
for example) to make it accessible to all the callback functions. Pass fig
into each callback (since the figure handle doesn't change, this is "safe")
and GET its UserData property.

--
Steve Lord
slord@mathworks.com
To contact Technical Support use the Contact Us link on
http://www.mathworks.com

Subject: Setting GUI callbacks

From: Jane T

Date: 21 Jun, 2011 16:44:06

Message: 4 of 7

>
> You don't show the structure of your whole app, but these two callback
> functions must be nested functions of the main gui function. Also,
> callbacks can't return anything; they must operate on variables in the
> main gui workspace. Something like this:
>
> function maingui
> s = [];
> h = [];
> function callbackIssue()
> ...
> h.testEdit1 = uicontrol(...,'Callback',{@simulate,1})
> h.testEdit2 = uicontrol(...,'Callback',{@simulate,2})
> end
> function simulate(h,evt,index)
> s.(['field',num2str(index)]) = get(h,'String');
> end
> end
>
>
> --
> Doug Schwarz
> dmschwarz&ieee,org
> Make obvious changes to get real email address.

This is esentially the structure of my app, it's very cut-down version only containing the parts of interest, but the code is structured the same. Obviously there is some more functionality to go into the simulate function, but I haven't written it yet. It will be using the values from the edit boxes to generate some simulated data that will be plotted in an axis; but I can't write that until I can get the right inputs.

Can you please expand on your response? You say that "callbacks can't return anything; they must operate on variables in the main gui workspace" does that mean that a callback can't be used to change the value of a variable in the main gui workspace?

I think I implemented the change that you suggested, but I still can't get it to permently change the value in the structure

function callbackIssue()
    s = [];
    h = [];
    
    setupGui();

    function setupGui()
        
        s.var1 = 2;
        s.var2 = 6;
        s.var3 = 11;
        fig = figure;

        for i = 1:3
            h.(['testEdit',num2str(i)]) = uicontrol('Parent',fig,...
                'Style','Edit',...
                'HorizontalAlignment','left',...
                'BackgroundColor','w',...
                'String',s.(['var',num2str(i)]),...
                'Tag',['var',num2str(i)],...
                'Position',[100*i 20 80 20],...
                'Callback',{@simulate,s});
        end
    end

    function [hobject,eventdata,s] = simulate(hobject,eventdata,s)
        disp([get(hobject,'Tag'),' = ',get(hobject,'String')]);
        s.(get(hobject,'Tag')) = str2num(get(hobject,'String'));
        disp(s);
    end

end

Thanks
Jane

Subject: Setting GUI callbacks

From: Jane T

Date: 21 Jun, 2011 16:51:05

Message: 5 of 7

"Steven_Lord" <slord@mathworks.com> wrote in message <itqh9d$r99$1@newscl01ah.mathworks.com>...
>
>
> "Jane T" <jterry@boreal-laser.com> wrote in message
> news:itqf6a$lae$1@newscl01ah.mathworks.com...
> > I'm trying to build a GUI to house the data simulator I am building, but
> > I'm have problems setting up my callbacks to pass variables. I've built a
> > very simplified GUI to illustrate the problem I'm having in the hopes you
> > might be able to help me.
> >
> > If I use the edit box to change the varaible of s.var1 then the function
> > is able to 'see' this new value, however if I then update the value of
> > s.var2 then the update of s.var1 is lost and it's value in the structure
> > has returned to the default.
> >
> > It seems that I'm not correctly passing the structure s out of the
> > simulate function, but being a GUI I have no idea where to even set the
> > breakpoint to see what is going on in the main function.
> >
> > I'm running Matlab 2011a
> >
> > Thanks for your time
> > Jane
> >
> > function callbackIssue()
> > s.var1 = 2;
> > s.var2 = 6;
> > s.var3 = 11;
> >
> > fig = figure;
> > for i = 1:3
> > h.(['testEdit',num2str(i)]) = uicontrol('Parent',fig,...
> > 'Style','Edit',...
> > 'HorizontalAlignment','left',...
> > 'BackgroundColor','w',...
> > 'String',s.(['var',num2str(i)]),...
> > 'Tag',['var',num2str(i)],...
> > 'Position',[100*i 20 80 20]);
> > set(h.(['testEdit',num2str(i)]),...
> > 'Callback',{@simulate,s});
>
> When you define the callback this way, simulate will be called with a copy
> of s as it exists RIGHT NOW when your SET call executes. Any changes to s
> later on will NOT affect the copy of s inside the cell array (which is the
> copy that's passed into simulate when the callback executes.
>
> > end
> > end
> >
> > function [hobject,eventdata,s] = simulate(hobject,eventdata,s)
> > disp([get(hobject,'Tag'),' = ',get(hobject,'String')]);
> > s.(get(hobject,'Tag')) = str2num(get(hobject,'String'));
> > disp(s);
> > end
>
> If simulate were nested inside callbackIssue then you wouldn't need to (and
> shouldn't) pass it into simulate as an input. Since it isn't, you will need
> to use some technique (like storing s inside the figure's UserData property,
> for example) to make it accessible to all the callback functions. Pass fig
> into each callback (since the figure handle doesn't change, this is "safe")
> and GET its UserData property.
>
> --
> Steve Lord
> slord@mathworks.com
> To contact Technical Support use the Contact Us link on
> http://www.mathworks.com

Thanks for your reply Steve, I think I'm starting to understand what you mean a little better. I have restuctured my code to this

function callbackIssue()
        
    s.var1 = 2;
    s.var2 = 6;
    s.var3 = 11;
    fig = figure;

    for i = 1:3
        h.(['testEdit',num2str(i)]) = uicontrol('Parent',fig,...
            'Style','Edit',...
            'HorizontalAlignment','left',...
            'BackgroundColor','w',...
            'String',s.(['var',num2str(i)]),...
            'Tag',['var',num2str(i)],...
            'Position',[100*i 20 80 20],...
            'Callback',{@simulate});
    end

    function [hobject,eventdata,s] = simulate(hobject,eventdata,s)
        disp([get(hobject,'Tag'),' = ',get(hobject,'String')]);
        s.(get(hobject,'Tag')) = str2num(get(hobject,'String'));
        disp(s);
    end

end

where simulate is now nested in callbackIssue. However, instead of printing the whole of the structure s tot he command window it is now only printing the element (is that the right term?) of interest.

Have I changed the code in the way you were suggesting? How do I prove to myself that s has been altered outside of simulate and that the changes have been saved?

Thanks for your time
Jane

Subject: Setting GUI callbacks

From: Doug Schwarz

Date: 21 Jun, 2011 18:05:35

Message: 6 of 7

On 6/21/2011 12:44 PM, Jane T wrote:
>>
>> You don't show the structure of your whole app, but these two callback
>> functions must be nested functions of the main gui function. Also,
>> callbacks can't return anything; they must operate on variables in the
>> main gui workspace. Something like this:
>>
>> function maingui
>> s = [];
>> h = [];
>> function callbackIssue()
>> ...
>> h.testEdit1 = uicontrol(...,'Callback',{@simulate,1})
>> h.testEdit2 = uicontrol(...,'Callback',{@simulate,2})
>> end
>> function simulate(h,evt,index)
>> s.(['field',num2str(index)]) = get(h,'String');
>> end
>> end
>>
>>
>> --
>> Doug Schwarz
>> dmschwarz&ieee,org
>> Make obvious changes to get real email address.
>
> This is esentially the structure of my app, it's very cut-down version
> only containing the parts of interest, but the code is structured the
> same. Obviously there is some more functionality to go into the simulate
> function, but I haven't written it yet. It will be using the values from
> the edit boxes to generate some simulated data that will be plotted in
> an axis; but I can't write that until I can get the right inputs.
>
> Can you please expand on your response? You say that "callbacks can't
> return anything; they must operate on variables in the main gui
> workspace" does that mean that a callback can't be used to change the
> value of a variable in the main gui workspace?

A callback function cannot return any arguments. If it is a nested
function it can change the values of variables in its parent function.

[snip]

Here's how I would write it. I made some structural changes to get rid
of the s.('text') syntax which is not really necessary and makes your
code harder to read.

function callbackIssue
s = [];
h = [];
fig = [];
setupGui()

   function setupGui
     s.var = [2 6 11];
     fig = figure;

     h.testEdit = zeros(1,3);
     for i = 1:3
       h.testEdit(i) = uicontrol('Parent',fig,...
         'Style','Edit',...
         'HorizontalAlignment','left',...
         'BackgroundColor','w',...
         'String',s.var(i),...
         'Tag',['var',num2str(i)],...
         'Position',[100*i 20 80 20],...
         'Callback',{@simulate,i});
     end
   end

   function simulate(hobject,eventdata,i)
     disp(i)
     s.var(i) = str2double(get(hobject,'String'));
     disp(s)
   end

end


--
Doug Schwarz
dmschwarz&ieee,org
Make obvious changes to get real email address.

Subject: Setting GUI callbacks

From: Jane T

Date: 21 Jun, 2011 19:26:04

Message: 7 of 7

Doug Schwarz <see@sig.for.address.edu> wrote in message <S35Mp.3250$Md1.2486@newsfe19.iad>...
> On 6/21/2011 12:44 PM, Jane T wrote:
> >>
> >> You don't show the structure of your whole app, but these two callback
> >> functions must be nested functions of the main gui function. Also,
> >> callbacks can't return anything; they must operate on variables in the
> >> main gui workspace. Something like this:
> >>
> >> function maingui
> >> s = [];
> >> h = [];
> >> function callbackIssue()
> >> ...
> >> h.testEdit1 = uicontrol(...,'Callback',{@simulate,1})
> >> h.testEdit2 = uicontrol(...,'Callback',{@simulate,2})
> >> end
> >> function simulate(h,evt,index)
> >> s.(['field',num2str(index)]) = get(h,'String');
> >> end
> >> end
> >>
> >>
> >> --
> >> Doug Schwarz
> >> dmschwarz&ieee,org
> >> Make obvious changes to get real email address.
> >
> > This is esentially the structure of my app, it's very cut-down version
> > only containing the parts of interest, but the code is structured the
> > same. Obviously there is some more functionality to go into the simulate
> > function, but I haven't written it yet. It will be using the values from
> > the edit boxes to generate some simulated data that will be plotted in
> > an axis; but I can't write that until I can get the right inputs.
> >
> > Can you please expand on your response? You say that "callbacks can't
> > return anything; they must operate on variables in the main gui
> > workspace" does that mean that a callback can't be used to change the
> > value of a variable in the main gui workspace?
>
> A callback function cannot return any arguments. If it is a nested
> function it can change the values of variables in its parent function.
>
> [snip]
>
> Here's how I would write it. I made some structural changes to get rid
> of the s.('text') syntax which is not really necessary and makes your
> code harder to read.
>
> function callbackIssue
> s = [];
> h = [];
> fig = [];
> setupGui()
>
> function setupGui
> s.var = [2 6 11];
> fig = figure;
>
> h.testEdit = zeros(1,3);
> for i = 1:3
> h.testEdit(i) = uicontrol('Parent',fig,...
> 'Style','Edit',...
> 'HorizontalAlignment','left',...
> 'BackgroundColor','w',...
> 'String',s.var(i),...
> 'Tag',['var',num2str(i)],...
> 'Position',[100*i 20 80 20],...
> 'Callback',{@simulate,i});
> end
> end
>
> function simulate(hobject,eventdata,i)
> disp(i)
> s.var(i) = str2double(get(hobject,'String'));
> disp(s)
> end
>
> end
>
>
> --
> Doug Schwarz
> dmschwarz&ieee,org
> Make obvious changes to get real email address.

GENIUS!!!

Many thanks. I've kept the s.('text') syntax, as when I actually get around to building the data simulation code I think it will make everything easier to follow and understand, I appreciate your thoughts on that though.

I've tranferred your comments and built my actual design, the code follows. I don't like the eval() statements in the properties of the test and edit objects. Can you think of a better more efficient method of achieving this?

I've also switched from using the 'tag' property to identify the variable of interest to stealing your suggestion of sending the variable name in the callback statement. Thanks!

I should also mention that I'm using the GUI Layout Toolbox which I have downloaded from the file exchange http://www.mathworks.com/matlabcentral/fileexchange/27758-gui-layout-toolbox . I will also have some graphs in the GUI and this toolbox allows the graphs to resize with the Figure, whilst the tab group remains a fixed size :D

I apologise for the long code, I usually try to cut it down as much as possible but feel that having it all there will add context to my question.

Thanks again for your time

function callbackIssue2()

%% Initialise 'global' variables
s = [];
h = [];
f = [];

%% Run code to structure and form the GUI
setupGui();

    function [hobject,eventdata] = simulate(hobject,eventdata,varname)
        disp([varname,' = ',get(hobject,'String')]);
        s.(varname) = str2num(get(hobject,'String'));
        disp(s);
    end

    function setupGui()
        %% Enter default values into a structure
        s.nRamps = 1;
        s.ppm = 50;
        s.L = 100;
        s.temp = 20;
        s.pressure = 101.325;
        s.tuningRate = 100;
        s.Iv0 = 120;
        s.minI = 100;
        s.maxI = 140;
        s.modAmp = 2.8866;
        s.modFreq = 51926;
        s.modPhase = 0;
        s.rampFreq = 300;
        s.sRate = 1.5152e-6;
        s.gas = 'CH4';
        s.n = 0.85;
        s.J = 3;
        s.B = 5.25;
        s.v0 = 1653.7;
        s.HWHM = 0.0621;
        s.S = 1.34e-21;
        s.T0 = 296;
        s.P0 = 101.325;

        %% Create cell array containing the text to add to the setting
        % panel
        tabNames = {'setup','laser','gas'};
        setupText = {'Number of Ramps','Averaged Concentration',...
            'Path Length','Temperature','Pressure'};
        setupVariables = {'nRamps','ppm','L','temp','pressure'};
        laserText = {'Tuning Rate','Current at Line Center',...
            'Min Current','Max Current','Modulation Amplitude',...
            'Modulation Frequency','Modulation Phase','Ramp Frequency',...
            'Sample Rate'};
        laserVariables = {'tuningRate','Iv0','minI','maxI','modAmp',...
            'modFreq','modPhase','rampFreq','sRate'};
        gasText = {'Gas','n','B','J','Line Center','HWHM','S','T0','P0'};
        gasVariables = {'gas','n','B','J','v0','HWHM','S','T0','P0'};

        %% Create and structure the main GUI components
        % Open a figure window and set it's properties
        f = figure('Position',[150 90 975 650],...
            'units','pixels',...
            'IntegerHandle','Off',...
            'NumberTitle','Off',...
            'Renderer','zbuffer',...
            'Name','GUI Layout',...
            'Visible', 'On',...
            'MenuBar', 'None',...
            'Color',[0.8 0.8 0.8]);
        
        h.settings = uiextras.TabPanel('Parent',f);
            setup = uiextras.Grid('Parent',h.settings,...
                'Spacing',15,'Padding',10);
            laser = uiextras.Grid('Parent',h.settings,...
                'Spacing',15,'Padding',10);
            gas = uiextras.Grid('Parent',h.settings,...
                'Spacing',15,'Padding',10);
            h.settings.TabNames = {'Setup','Laser','Gas'};
            h.settings.SelectedChild = 1;

        %% Fill in the user setting tabs with the required fields
        for j = 1:length(tabNames)
            textnames = ([tabNames{j},'Text']);
            for i = 1:length(eval(textnames))
                uicontrol('Parent',eval(tabNames{j}),'Style','Text',...
                    'HorizontalAlignment','left',...
                    'String',eval([textnames,'{i}']));
            end
            for i = 1:length(eval(textnames))
                h.([eval([tabNames{j},'Variables{i}']),'Edit'])...
                    = uicontrol('Parent',eval(tabNames{j}),...
                    'Style','Edit',...
                    'HorizontalAlignment','left','BackgroundColor','w',...
                    'String',s.(eval([tabNames{j},'Variables{i}'])),...
                    'Callback',{@simulate,eval([tabNames{j},'Variables{i}'])});
            end
            set( eval(tabNames{j}), 'ColumnSizes', [-2 -1],...
                'RowSizes', 22*ones(1,length(eval(textnames))) );
        end

    end
end

Tags for this Thread

What are tags?

A tag is like a keyword or category label associated with each thread. Tags make it easier for you to find threads of interest.

Anyone can tag a thread. Tags are public and visible to everyone.

Contact us