GUI - Executing Function when Pressing Button

Hello everyone!

I have a question regarding the GUI functions in octave. I hope this hasn’t been discussed recently, as I could not find a solution to my problems in other posts.

I want to create a GUI where a number of buttons are present and there to be used for different tasks. And my problem is, that I want to have one button which asks for a filename of a given file, and then another button who executes a function with that filename included.

Here is the code:

close all;
clear h; 
dir = pwd();
p = uipanel ("title", "Panel", "position", [0 0 1 1]);

h.fileselect_button = uicontrol(p, "style", "pushbutton", 
                                "string", "Select Sample File", 
                                "units", "normalized", 
                                "callback", @parameters,
                                "position", [0.5 0.68 0.3 0.1]);
h.start_button = uicontrol(p, "style", "pushbutton", 
                           "string", "Calculate", 
                           "units", "normalized",
                           "callback", @parameters_decon,
                           "position", [0.5 0.57 0.3 0.1]);

function [filename, cm, cc] = parameters (obj, init = false)  
  h = guidata (obj); 
  switch (gcbo)
    case {h.fileselect_button}
      filename = uigetfile('Sample file data', 'Choose sample file (must be xlsx!)');    
    case {h.start_button}
      [~] = testfunction(dir, filename, cm, cc, p);  
  endswitch  
endfunction

set (gcf, "color", get(0, "defaultuicontrolbackgroundcolor"))
guidata (gcf, h)
parameters (gcf, true);

So the first button “h.fileselect_button” gives a callback to this function which according to the switch gcbo executes the uigetfile function, which returns the “filename” string. However, as soon as I want to execute the h.start_button callback, the function “testfunction” does give me an error as that “filename” is undefined. How can i properly give the preselected filename to the function?

In my understanding, the case syntax does not hand over the outcomes of the executed tasks to other cases, but how can i do so if I wanted it?

Thanks very much in advance!

Greetings

There are probably multiple different solutions for that. Which is best for you depends on your use case.
Two possible solutions are:

  • If you’d like to use the same function parameters for the callback function of both buttons in your example, you could make the variable filename persistent in that function. For this, add persistent filename close to the beginning of the definition of the function parameters. Note that the lifetime of persistent variables is limited (e.g. they are re-initialized when the file is re-parsed).

  • Another possibility might be to store that kind of information as “appdata” in the common parent of both buttons. You could save it with setappdata (get (obj, 'Parent'), 'my_filename', filename); inside the callback function for the “Select Sample File” button. And retrieve that information with filename = getappdata (get (obj, 'Parent'), 'my_filename');.

hey mmuetzel, thanks very much for your quick and informative reply! Indeed this worked quite well, with the appdata functions I can give the information for the function now, thanks very much!

One follow up question on this, is it also possible to transfer the handle “p” from the panel to the callback function and also the Testfunction? I tried it by defining p as global, or also using setappdata and including p in the function variables, but all the time the error occurs that p is undefined when I try to press the start_button. the idea would be to have a figure window on the panel on which the results of the calculation of the testfunction should be plotted, and I am assuming I need the panel handle in the function for that

(Most) callback functions are called with two input arguments: A handle to the object the callback belongs to and a eventData structure.
You can use simple anonymous functions if you’d like to pass other arguments. E.g.:

h.fileselect_button = uicontrol(p, "style", "pushbutton", 
                                "string", "Select Sample File", 
                                "units", "normalized", 
                                "callback", @(h,e) parameters(h, p),
                                "position", [0.5 0.68 0.3 0.1]);

function parameters (h_obj, h_parent)
  disp('test')
  h_obj
  h_parent
endfunction

Note that the values of the additional input parameters in the callback function are those when the callback was created. (That’s not necessarily the same like when the callback function is called.)

HTH

okay, i tried it, but upon pressing the fileselect_button its gives me an error that the “hobj” is undefined. I assumed it should be “h_obj” since its the input argument of the “parameters” function but it still doesn’t work.

And for understanding, what does the (h,e) part of the callback exactly mean?

Sorry. There was a typo in the example.
Does it work now?

@(h,e) means that the anonymous function takes two arguments h and e. You can refer to their value by these names. In the example, only h is used.

Unfortunately not, it still says that p is undefined for the parameters function:

p = uipanel ("title", "Software", "position", [0 0 1 1]);

h.start_button = uicontrol(p, "style", "pushbutton", 
                           "string", "Calculate", 
                           "units", "normalized",
                           "callback", @(h,e)parameters(h,p),
                           "position", [0.5 0.57 0.3 0.1]);

function parameters(obj, init = false, p)  #<------ added "p" here
  h = guidata (obj);
  switch (gcbo)
    case {h.fileselect_button}
      filename = uigetfile('Sample file data', 'Choose sample file (must be xlsx!)');
      setappdata (get (obj, 'Parent'), 'my_filename', filename);
    case {h.start_button}
      filename = getappdata (get(obj, 'Parent'), 'my_filename');    
      [x] = testfunction(filename, cm, cc, p);  #<------------------- Here the "p" is undefined
  endswitch  
endfunction

guidata (gcf, h)
parameters_decon (gcf, true, p); #<------ added "p" here

It is strange since by executing the start button p should be handed over to the parameters function which should then be picked up by the testfunction.

Is there maybe another way to do it? e.g. with setappdata ideas?

There is no input parameter p in your function definition.

Ok that was my bad, i edited the code now in the post, i added p to the function and also to the execution of the function at the end, its still undefined though :pensive:

The signature of the definition for function parameters doesn’t match how it is used now.
Either add a value for init in the argument list where you call the function. Or remove that input argument from the function definition. (It doesn’t look like you are using it anyway.)

ah that was my error, of course, now it makes sense and it works! thanks very much for that great help! :grinning: