Discussion:
Function handle with arguments for GUI callback
Arnaud Miege
2013-03-11 16:21:49 UTC
Permalink
Hi,

I am trying to develop a GUI (using Octave 3.6.2 with Qt graphics toolkit
on Windows). The whole of the code is in a single function file, with a
number of nested functions. I have used MATLAB for more than 10 years so I
am used to the nested functions having access to the workspace of the
calling function. Now, I understand that the decision was made for Octave
to not support this behaviour, and that's fine, everybody's entitled to
their opinion, I am not going to discuss the benefits of using either
approach. It just means that I have to pass arguments to the callback
functions, which is fine, or at least should be in theory.

My question really is what is the best way to use a function handle *with
arguments* as a callback to a uicontrol?

Here's what my code looks like:

function my_top_level_GUI()

function gui = create_interface()
% some code to create the uicontrols
% gui is a struct

% Add pop-up menus for dimension choice of each input
strings = {'Nominal dimensions|Measurement file'};
width = [0.5 0.5 0.5];
gui.dim_choices = cell(size(gui.inputs_txt)); % cell of dim (3,1)
for k=1:length(gui.inputs_txt)
gui.dim_choices{k} = uicontrol('Style','popupmenu','String',strings,...
'Units','normalized','Position',[0.23 y_pos(k) width(k) 0.1],...
'BackgroundColor','w','Parent',gui.inputs_panel,'Callback',...
@(gui,k)update_browse_btn);
end

end % end create_interface

function update_browse_btn(gui,k)
% Called when user activates popup menu
val = get(gui.dim_choices{k},'Value');
if val == 2
set(gui.browse_btns{k},'Enable','on');
end
end % end update_browse_btn

end
error: `gui' undefined near line 184 column 11
error: evaluating argument list element number 1
error: called from:
error: <path_to_my_GUI_file> at line 184, colu
mn 5

Any suggestions on how to make this work?

Many thanks in advance,

Arnaud
Jordi Gutiérrez Hermoso
2013-03-11 16:32:52 UTC
Permalink
I am trying to develop a GUI (using Octave 3.6.2 with Qt graphics toolkit on
Windows). The whole of the code is in a single function file, with a number
of nested functions. I have used MATLAB for more than 10 years so I am used
to the nested functions having access to the workspace of the calling
function. Now, I understand that the decision was made for Octave to not
support this behaviour, and that's fine, everybody's entitled to their
opinion, I am not going to discuss the benefits of using either approach.
You might be interested in knowing that the current development branch
of Octave has changed nested functions:

http://hg.savannah.gnu.org/hgweb/octave/rev/fa3989fbb1b5#l1.57

- Jordi G. H.
Ben Abbott
2013-03-11 16:42:47 UTC
Permalink
Post by Jordi Gutiérrez Hermoso
I am trying to develop a GUI (using Octave 3.6.2 with Qt graphics toolkit on
Windows). The whole of the code is in a single function file, with a number
of nested functions. I have used MATLAB for more than 10 years so I am used
to the nested functions having access to the workspace of the calling
function. Now, I understand that the decision was made for Octave to not
support this behaviour, and that's fine, everybody's entitled to their
opinion, I am not going to discuss the benefits of using either approach.
You might be interested in knowing that the current development branch
http://hg.savannah.gnu.org/hgweb/octave/rev/fa3989fbb1b5#l1.57
- Jordi G. H.
There's a developer's build for Windows that I believe includes nested functions.

http://dl.dropbox.com/u/45539519/octave-3.7.2%2B-vs2010-setup.exe

The original post to the maintainer's mail-list is below.

https://mailman.cae.wisc.edu/pipermail/octave-maintainers/2013-February/032251.html

If you find any problems, please report them. If you think they qualify as bugs, please file a report.

https://savannah.gnu.org/bugs/?group=octave

Ben
Arnaud Miege
2013-03-11 16:43:33 UTC
Permalink
Post by Jordi Gutiérrez Hermoso
You might be interested in knowing that the current development branch
http://hg.savannah.gnu.org/hgweb/octave/rev/fa3989fbb1b5#l1.57
- Jordi G. H.
Thanks. Even though I mentioned nested functions, I am not currently using
any. My code is structured as follows:

- Main GUI function
- Sub-function to create the UI controls
- Sub-function for first callback
- Sub-function for second callback
- etc...
end

I just need to find a mechanism to pass (and modify) data to/from the
callback functions to the main GUI function where the information is stored
(in a struct).

It's good to know about nested functions though, I'll give them a try when
I upgrade to the next stable release of Octave (hopefully there will have
some improvement to the Octave GUI by then, fingers crossed). Right now, I
need a solution for 3.6.2. I have tried defining the callback as a cell
array, i.e. {@update_browse_btn,gui,k} or even
{@update_browse_btn,"gui","k"}, but that didn't work either.

Thanks,

Arnaud
Michael Goffioul
2013-03-11 17:34:24 UTC
Permalink
Post by Arnaud Miege
Post by Jordi Gutiérrez Hermoso
You might be interested in knowing that the current development branch
http://hg.savannah.gnu.org/hgweb/octave/rev/fa3989fbb1b5#l1.57
- Jordi G. H.
Thanks. Even though I mentioned nested functions, I am not currently using
- Main GUI function
- Sub-function to create the UI controls
- Sub-function for first callback
- Sub-function for second callback
- etc...
end
I just need to find a mechanism to pass (and modify) data to/from the
callback functions to the main GUI function where the information is stored
(in a struct).
It's good to know about nested functions though, I'll give them a try when
I upgrade to the next stable release of Octave (hopefully there will have
some improvement to the Octave GUI by then, fingers crossed). Right now, I
need a solution for 3.6.2. I have tried defining the callback as a cell
Using a cell array is the right approach. It is supported. What error do
you get and what code are you using? Also please note that a GUI callback
always get the object handle and an event data as first 2 arguments.
Whatever arguments you specify in the cell array starts at position 3 in
the callback argument list.

Michael.
Arnaud Miege
2013-03-11 18:13:50 UTC
Permalink
Post by Michael Goffioul
Using a cell array is the right approach. It is supported. What error do
you get and what code are you using? Also please note that a GUI callback
always get the object handle and an event data as first 2 arguments.
Whatever arguments you specify in the cell array starts at position 3 in
the callback argument list.
Michael.
Thanks, I have made some progress since my initial email.

In my main function, I create a variable called "gui" as the output of a
sub-function called create_interface:

gui = create_interface;

In the sub-function create_interface, I add various fields to the gui
structure which are handles to the various UI components, such as:

% Add pop-up menus for dimension choice of each input
strings = {'Nominal dimensions|Measurement file'};
width = [0.5 0.5 0.5];
gui.dim_choices = cell(size(gui.inputs_txt));
for k=1:length(gui.inputs_txt)
gui.dim_choices{k} = uicontrol('Style','popupmenu','String',strings,...
'Units','normalized','Position',[0.23 y_pos(k) width(k) 0.1],...
'BackgroundColor','w','Parent',gui.inputs_panel,'Callback',...
{@update_browse_btn,num2str(k),gui});
end

I have worked out that the first argument to the function handle callback
needs to be converted to a string. I am also passing the gui structure as a
second argument because I couldn't figure out a way of using the second
default argument (eventdata - there doesn't seem to be much documentation
about it).

If we then come out of create_interface, I have various functions for the
callbacks, all at the same level as create_interface. The one of interest
is (I have only put some trivial commands to debug what is going on):

function update_browse_btn(src,data,k,gui)
% Called when user activates popup menu
disp(['k = ' num2str(k)]);
val = get(src,'Value')
gui
end

That works well and displays the following in the console when I change the
Post by Michael Goffioul
k = 1
val = 2
gui =

scalar structure containing the fields:

Window = 1
outputs_panel = -28.293
inputs_panel = -27.709
graph_panel = -26.338
HelpMenu = -25.343
inputs_txt =
{
[1,1] = -23.566
[2,1] = -22.087
[3,1] = -21.487
}
browse_btns =
{
[1,1] = -20.863
[2,1] = -19.427
[3,1] = -18.260
}
dim_choices =
{
[1,1] = [](0x0)
[2,1] = [](0x0)
[3,1] = [](0x0)
}

If I then change the callback function slightly to:

function update_browse_btn(src,data,k,gui)
% Called when user activates popup menu
disp(['k = ' num2str(k)]);
val = get(src,'Value')
gui.browse_btns
end
Post by Michael Goffioul
k = 1
val = 2
ans =
{
[1,1] = -20.090
[2,1] = -19.064
[3,1] = -18.774
}

However, if I start using the index k (which has a sensible value between 1
and 3), as in:

function update_browse_btn(src,data,k,gui)
% Called when user activates popup menu
disp(['k = ' num2str(k)]);
val = get(src,'Value')
gui.browse_btns(k,1)
end
Post by Michael Goffioul
k = 1
val = 2
error: update_browse_btn: A(I,J): row index out of bounds; value 49 out of
bound
3
error: called from:
error: <path_to_my_file> at line 185, colu
mn 3

I can't then close the GUI, I need to click on the console to activate it,
which triggers the following error message:

error: octave_base_value::convert_to_str_internal (): wrong type argument
`<unkn
own type>'
error: octave_base_value::convert_to_str_internal (): wrong type argument
`<unkn
own type>'
error: octave_base_value::convert_to_str_internal (): wrong type argument
`<unkn
own type>'
error: octave_base_value::double_value (): wrong type argument `<unknown
type>'
error: octave_base_value::convert_to_str_internal (): wrong type argument
`<unkn
own type>'
error: octave_base_value::convert_to_str_internal (): wrong type argument
`<unkn
own type>'
error: octave_base_value::convert_to_str_internal (): wrong type argument
`<unkn
own type>'

I then need to press Enter to regain control and close the figure with the
close command.

The syntax gui.browse_btns{k} results in a similar behaviour.

Any idea why although k is definitely equal to 1, it says it's 49 when
trying to index the structure?

Many thanks,

Arnaud
Michael Goffioul
2013-03-11 18:31:04 UTC
Permalink
Post by Arnaud Miege
Post by Michael Goffioul
Using a cell array is the right approach. It is supported. What error do
you get and what code are you using? Also please note that a GUI callback
always get the object handle and an event data as first 2 arguments.
Whatever arguments you specify in the cell array starts at position 3 in
the callback argument list.
Michael.
Thanks, I have made some progress since my initial email.
In my main function, I create a variable called "gui" as the output of a
gui = create_interface;
In the sub-function create_interface, I add various fields to the gui
% Add pop-up menus for dimension choice of each input
strings = {'Nominal dimensions|Measurement file'};
width = [0.5 0.5 0.5];
gui.dim_choices = cell(size(gui.inputs_txt));
for k=1:length(gui.inputs_txt)
gui.dim_choices{k} = uicontrol('Style','popupmenu','String',strings,...
'Units','normalized','Position',[0.23 y_pos(k) width(k) 0.1],...
'BackgroundColor','w','Parent',gui.inputs_panel,'Callback',...
end
I have worked out that the first argument to the function handle callback
needs to be converted to a string. I am also passing the gui structure as a
second argument because I couldn't figure out a way of using the second
default argument (eventdata - there doesn't seem to be much documentation
about it).
This is standard Matlab behavior:
http://www.mathworks.com/help/matlab/creating_guis/writing-code-for-callbacks.html
(look for "Use Cell Arrays with Strings")
Post by Arnaud Miege
However, if I start using the index k (which has a sensible value between
function update_browse_btn(src,data,k,gui)
% Called when user activates popup menu
disp(['k = ' num2str(k)]);
val = get(src,'Value')
gui.browse_btns(k,1)
end
Post by Michael Goffioul
k = 1
val = 2
error: update_browse_btn: A(I,J): row index out of bounds; value 49 out of
bound
3
error: <path_to_my_file> at line 185, colu
mn 3
I can't then close the GUI, I need to click on the console to activate it,
error: octave_base_value::convert_to_str_internal (): wrong type argument
`<unkn
own type>'
error: octave_base_value::convert_to_str_internal (): wrong type argument
`<unkn
own type>'
error: octave_base_value::convert_to_str_internal (): wrong type argument
`<unkn
own type>'
error: octave_base_value::double_value (): wrong type argument `<unknown
type>'
error: octave_base_value::convert_to_str_internal (): wrong type argument
`<unkn
own type>'
error: octave_base_value::convert_to_str_internal (): wrong type argument
`<unkn
own type>'
error: octave_base_value::convert_to_str_internal (): wrong type argument
`<unkn
own type>'
I then need to press Enter to regain control and close the figure with the
close command.
The syntax gui.browse_btns{k} results in a similar behaviour.
As the object is a cell array, you need to index it with {}, but from what
you saying, it doesn't work either. Does it change anything if you do an
assignment instead:

x = gui.browse_btns{k}
x

Michael.
Arnaud Miege
2013-03-12 09:02:05 UTC
Permalink
Post by Michael Goffioul
http://www.mathworks.com/help/matlab/creating_guis/writing-code-for-callbacks.html
(look for "Use Cell Arrays with Strings")
You are right of course, sorry.
As the object is a cell array, you need to index it with {}, but from what
you saying, it doesn't work either. Does it change anything if you do an
x = gui.browse_btns{k}
x
No IVm afraid it doesn't. Don't know why it says k is 49 when used to
index, and 3 when displaying it.

I will maybe try tagging the different uicontrols to circumvent the problem.

Thanks,

Arnaud
Arnaud Miege
2013-03-13 11:45:37 UTC
Permalink
It looks like there is a constant offset of 48 between what the value of k
is and what it should be, so for now, I am using the following:

function update_browse_btn(src,data,k,gui)
% Called when user activates popup menu
val = get(src,'Value');
if val == 2
set(gui.browse_btns{k-48},'Enable','on');
set(gui.ip_file_edit{k-48},'Enable','on');
else
set(gui.browse_btns{k-48},'Enable','off');
set(gui.ip_file_edit{k-48},'Enable','off');
end
end

This works well for all the scenarios and all possible values of k, but I
am slightly uneasy at having an unexplained, hard-coded, offset in the
code, even if this is only a prototype (the final version will probably be
coded in C# for deployment to end-users). Anyway, it does the job for now
until I find a more elegant and more robust solution.

Thanks,

Arnaud
Post by Arnaud Miege
Post by Michael Goffioul
http://www.mathworks.com/help/matlab/creating_guis/writing-code-for-callbacks.html
(look for "Use Cell Arrays with Strings")
You are right of course, sorry.
As the object is a cell array, you need to index it with {}, but from
what you saying, it doesn't work either. Does it change anything if you do
x = gui.browse_btns{k}
x
No IVm afraid it doesn't. Don't know why it says k is 49 when used to
index, and 3 when displaying it.
I will maybe try tagging the different uicontrols to circumvent the problem.
Thanks,
Arnaud
Jordi Gutiérrez Hermoso
2013-03-13 13:26:32 UTC
Permalink
(the final version will probably be coded in C# for deployment to end-users).
I don't know exactly what you're doing, and it depends on the details,
but don't forget your GPL obligations when you distribute this:

http://wiki.octave.org/FAQ#Licensing_issues

- Jordi G. H.
Arnaud Miege
2013-03-13 13:33:50 UTC
Permalink
Post by Arnaud Miege
(the final version will probably be coded in C# for deployment to
end-users).
I don't know exactly what you're doing, and it depends on the details,
http://wiki.octave.org/FAQ#Licensing_issues
- Jordi G. H.
Thanks for the info. The program is just plain *.m file, and it will be
entirely re-written in C#, Octave is just used as a development
environment. It's also for internal use only (where I work), so it won't be
publicly available.

Arnaud

Doug Stewart
2013-03-13 13:27:23 UTC
Permalink
Post by Arnaud Miege
It looks like there is a constant offset of 48 between what the value of k
function update_browse_btn(src,data,k,gui)
% Called when user activates popup menu
val = get(src,'Value');
if val == 2
set(gui.browse_btns{k-48},'Enable','on');
set(gui.ip_file_edit{k-48},'Enable','on');
else
set(gui.browse_btns{k-48},'Enable','off');
set(gui.ip_file_edit{k-48},'Enable','off');
end
end
This works well for all the scenarios and all possible values of k, but I
am slightly uneasy at having an unexplained, hard-coded, offset in the
code, even if this is only a prototype (the final version will probably be
coded in C# for deployment to end-users). Anyway, it does the job for now
until I find a more elegant and more robust solution.
Thanks,
Arnaud
Post by Arnaud Miege
Post by Michael Goffioul
http://www.mathworks.com/help/matlab/creating_guis/writing-code-for-callbacks.html
(look for "Use Cell Arrays with Strings")
You are right of course, sorry.
As the object is a cell array, you need to index it with {}, but from
what you saying, it doesn't work either. Does it change anything if you do
x = gui.browse_btns{k}
x
No IVm afraid it doesn't. Don't know why it says k is 49 when used to
index, and 3 when displaying it.
I will maybe try tagging the different uicontrols to circumvent the problem.
Thanks,
Arnaud
_______________________________________________
Help-octave mailing list
https://mailman.cae.wisc.edu/listinfo/help-octave
ASCII has an offset of 48 Dec. so what you are seeing is the ASCII code for
the number.
--
DAS

https://linuxcounter.net/user/206392.html
Loading...