Passing Edit uicontrol string to callback of another uicontrol in Matlab - matlab

I wrote a code like this in Matlab:
function[] = gui_function()
window.value1 = uicontrol('style', 'edit', ...
'string', '5', ...
'callback', #is_number);
window.computeButton = uicontrol('style', 'push', ...
'callback', {#test_script, str2double(get(window.value1, 'string'))});
end
function[] = test_script(varargin)
value1 = varargin{3};
end
I want to pass the text from Edit uicontrol to Button's callback. When I do it as following, the value that is passed is an old value that is set when declaring the uicontrol.
So ie. I run the GUI and have a value of 5 in the edit. I overwrite it to be 20, but after pushing the button, the value that is being passed is still 5
What is wrong in this approach? How can it be done differently?
Thank you in advance!

In my opinion, the best option when working with GUIs is to use the handles structure of the GUI, in which every uicontrols are stored along with their associated properties, in addition to (that's the cool part) whatever you want to store in it, like variables for instance.
So I modified you code a bit to make use of the handles structure. I'm not entirely clear as to what you want, but in my example the pushbutton is used to update the content of a second edit box with the content of the 1st edit box. That's very basic, but it should help you get a feel of handles and the handles structure. If something is unclear please let me know!
function gui_function()
ScreenSize = get(0,'ScreenSize');
handles.figure = figure('Position',[ScreenSize(3)/2,ScreenSize(4)/2,400,285]);
handles.Edit1 = uicontrol('style', 'edit','Position',[100 150 75 50], ...
'string', '5');
handles.Edit2 = uicontrol('style', 'edit','Position',[100 80 75 50], ...
'string', 'Update me');
handles.computeButton = uicontrol('style', 'push','Position',[200 100 75 75],'String','PushMe', ...
'callback', #PushButtonCallback);
guidata(handles.figure, handles); %// Save handles to guidata. Then it's accessible form everywhere in the GUI.
function PushButtonCallback(handles,~)
handles=guidata(gcf); %// Retrieve handles associated with figure.
TextInBox1 = get(handles.Edit1,'String');
set(handles.Edit2,'String',TextInBox1); %// Update 2nd edit box with content of the first.
%// Do whatever you want...
guidata(handles.figure, handles); %// DON'T forget to update the handles structure
You could customize this GUI by adding your function callback (test_script) in the same way I implemented the PushButtonCallback. Hope I understood what you wanted :)

Related

How to reset the default values in a graphical user interface

I'm creating a graphic interface (manually) and I would like to have a reset button which reset the default values.
I already code this
H.but(3) = uicontrol('Units','normalized', ...
'BackgroundColor',[1 0.7 1], ...
'Callback','MyFunction(''Reset'');', ...
'FontSize',12, ...
'Position',[0.04 0.54 0.1 0.05 ], ...
'String','Reset');
case 'Reset'
clear all % Is not working and I think that isn't that I expect
set(findobj(H.fig,'style','edit', '-or','style','text'),'string','') % H is a global variable. This trial don't give the default value, it just clear certain boxes
I usually prefer to create a specific reset_gui function for my GUIs that resets all the relevant control properties (like checkbox states, strings in editable text boxes, etc.) to appropriate default values, as well as setting all relevant variable values to their defaults, clearing plots, etc..
If you'd prefer a generic option for resetting all UI control properties to their initial state, here's an example of one possible solution:
function example_reset_gui
% Initialize GUI:
hFigure = figure();
uicontrol('Style', 'edit', 'Position', [20 100 100 25]);
uicontrol('Style', 'edit', 'Position', [20 65 100 25]);
uicontrol('Style', 'push', 'Position', [20 20 60 30], ...
'String', 'Reset', 'Callback', #reset_fcn);
drawnow
% Collect default states:
[defaultState{1:3}] = get_default_state(hFigure);
% Nested reset function:
function reset_fcn(~, ~)
set(defaultState{:});
end
end
% Local function:
function [hArray, propArray, valueArray] = get_default_state(hFigure)
hArray = findall(hFigure, 'Type', 'uicontrol');
propArray = fieldnames(set(hArray(1)));
valueArray = get(hArray, propArray);
end
This creates a figure with 2 editable text boxes and a reset button. You can type whatever you want into the text boxes, and when you push the reset button it will clear them (i.e. set them to the default empty string they first contained).
The local function get_default_state will find all the uicontrol objects in the figure, then get all of their set-able properties (i.e. all properties that are not read-only), then get all the initial values for those properties. The three outputs are stored in the 1-by-3 cell array defaultState, which is accessible by the nested function reset_fcn. When the reset button is pressed, all of the set-able UI control properties are set to the values they had when first created.
It should be noted that any changes made to the Position property (such as due to resizing of the figure) could be undone by this approach. Using 'normalized' units would avoid this.
If you truly want to start your GUI over from scratch the easiest way would be to just close it open it again. You can do that from your button's callback. Which I pointed at a new function restartGUI. That could be a subfunction of your main gui or its own m-file, your choice.
Your question is pretty light on details so I can't help with some of the specifics but this should give you the general idea.
IF closing and opening isn't what your want then in the restartGUI function you would have to just manually reset the state of each of your uicontrols, etc. (whatever else is in your GUI that we can't see).
H.but(3) = uicontrol('Units','normalized', ...
'BackgroundColor',[1 0.7 1], ...
'Callback',#restartGUI, ...
'FontSize',12, ...
'Position',[0.04 0.54 0.1 0.05 ], ...
'String','Reset');
% <<<< THE rest of your code >>>
function restartGUI(hObject,varargin)
global H
close(H.fig) %Assuming H.fig the main GUI window.
%Call the GUI again which will restart it.
yourGUIFunction
Edit: added the use of the global H to close.

Make a panel with values visible when I press a radiobutton

I have a uibuttongroup with radio buttons defined in it. I have uipanels defined with their corresponding properties. What I want to do is to be able to click one radio button and have one uipanel appear, and then click my other radio button to have the other uipanel appear. Here are snippets of my code:
operation_type_1 = uibuttongroup(S.Test, 'Title', 'Operation Type', 'position', [0 0.3 panel_w/2 0.15]);
uicontrol('Parent',operation_type_1, 'Style', 'radiobutton',...
'String', 'invisible',...
'position', [0 0 0 0], 'Tag', 'invisibutton');
uicontrol('Parent',operation_type_1,'Style','radiobutton',...
'String', 'Time Operation',...
'Position', 100*[0.1 flooring(3.5, 'tp') 1.2 0.15], 'Tag', 'timeop1');
uicontrol('Parent',operation_type_1,'Style','radiobutton',...
'String', 'Volume Operation',...
'Position', 100*[0.1 flooring(2.5, 'tp') 1.2 0.15], 'Tag', 'volumeop1');
This defines my button group and the two radio buttons.
Then I have code which creates a volume panel:
As well as a Time Panel:
These are in the same position. What I want is to be able to click on the "Time Operation" radio button and have the time panel be visible, and when I click on the "Volume Operation" radio button, the volume panel is visible.
I've tried doing switch case statements. I don't get errors, but I don't get results either. For example, my case statements for the time and volume panels are:
switch str
case 'timeop1'
if U.Value; S.result_panel_time1.Visible = 'On';
else S.result_panel_time1.Visible = 'Off';
end
case 'volumeop1'
if U.Value; S.result_panel_volume1.Visible = 'On';
else S.result_panel_volume1.Visible = 'Off';
end
How do I get this to work? I'm not using GUIDE, just coding a MATLAB GUI.
UPDATE
I've tried implementing the callback suggested below, but I get a "Function definition is misplaced or improperly nested." error. I use the following function:
function button_callback(U, varargin{2})
switch get(get(operation_type_1, 'SelectedObject'), 'Tag')
case 'timeop1'
if U.Value; S.result_panel_time1.Visible = 'On';
else S.result_panel_time1.Visible = 'Off';
end
case 'volumeop1'
if U.Value; S.result_panel_volume1.Visible = 'On';
else S.result_panel_volume1.Visible = 'Off';
end
end
end
And I've added the callbacks "...'callback', {#pb_call, S}" to my timeop1 and volumeop1. (Because all of the other function I have are in a .m file called pb_call.m). The function appears to be nested fine but the error points at the exact one.
It seems to me you did not define callback for your RadioButton. For example, set callback for volumeop1:
uicontrol('Parent',operation_type_1,'Style','radiobutton',...
'String', 'Volume Operation',...
'Position', 100*[0.1 0.3 1.2 0.15], 'Tag', 'volumeop1', ...
'Callback', #switchPanel);
Then in function switchPanel, you will set corresponding panel visible, while set others invisible.
This is trying to answer your questions, but it seems to me what you want is uitab.
My partner ended up fixing it:
The callback was {callback, S} and S, U, and str were:
S = varargin{3}; %main figure handle
U = varargin{1}; %current uicontrol
str = char(U.String);
The problem occurred in the radiobutton creation, since the result panels were being created after the radiobuttons could be triggered, thus nothing was made invisible/visible and an error would occur.
However, it would be highly convenient if callbacks could affect all GUI parts, not just previously defined ones. I've tried using guidata in the past, but I had to use other, less straighforward methods to accomplish my goals. I'll try using working samples and building upon those in the future, but currently I am working on another part of the project and will get back to that later.
But using either guidata/setappdata or something related would work here as well as my own solution, which is making sure that the objects you are trying to change are already defined before the button triggering the callback.
(He also posted this answer to where I asked this same question in MATLAB Answers.)

Access children of copied uipanel (Matlab)

I have created an uipanel in Matlab and placed some uicontrols on it. How can I access those uicontrols when I copy the panel?
Example:
panel_a=uipanel(figure);
editfield=uicontrol(panel_a, 'style','edit');
x=uitab(tabgroup);
panel_b=copyobj(panel_a,x);
tmp=panel_b.editfield.String; <-- how do I write this?
How is editfield of panel_b accessed?
If you assign the uicontrol a Tag value to begin with, you can use this to find the handle to it once you copy it to the new panel using findobj.
% Assign a 'Tag' value specific to this uicontrol
editfield = uicontrol(panel_a, 'style', 'edit', 'tag', 'editfield');
% Copy your relevant objects
panel_b = copyobj(panel_a, x);
% Use findobj to locate the handle to the object of interest
tmp = findobj(panel_b, 'Tag', 'editfield')
Alternately, you could use findobj to find all edit boxes
tmp = findobj(panel_b, 'Style', 'edit');

Manage multiple callbacks

I have made a user interface with many edit text boxes created in loops, now I want to store the user inputs in a variable with callback.
For example consider this code,
function p = myfun()
f = figure;
set(f,'Position',[200 350 250 150],'Color',[.4 .6 .4],'MenuBar','none',...
'Visible','off');
bc = [.4 .6 .4];
uicontrol('Style','text','Position',[50 80 80 30],...
'String','X','BackgroundColor',bc,'ForegroundColor','w');
uicontrol('Style','text','Position',[50 40 80 30],...
'String','Y','BackgroundColor',bc,'ForegroundColor','w');
uicontrol('style','edit','Position', [120 80 80 30],...
'BackgroundColor',bc,'ForegroundColor','w','Callback',{#My_Callback});
uicontrol('style','edit','Position', [120 40 80 30],...
'BackgroundColor',bc,'ForegroundColor','w','Callback',{#My_Callback});
uicontrol('Style', 'pushbutton', 'String', 'Ok',...
'Position', [100 5 60 30],'Callback', 'close');
movegui(f,'center')
set(f,'Visible','on')
function My_Callback(hObject,eventdata)
p = str2double(get(hObject,'string'));
end
end
Now My_Callback will be called twice but only the last one will be stored in p.
But I want them to be stored like p.x and p.y.
I think I should use Tag, it says:
Tag
string (GUIDE sets this property)
User-specified object label. The Tag property provides a means to identify graphics objects with a user-specified label. This is particularly useful when constructing interactive graphics programs that would otherwise need to define object handles as global variables or pass them as arguments between callback routines. You can define Tag as any string.
But I don't know how (I have about 16 editable boxes),
Thanks for any help.
If I understood your question correctly, you could use the UserData property of uicontrols to store the content of the edit boxes as you enter it, that way it would be very easy to recover them anywhere within your GUI or elsewhere.
Moreover, to facilitate things you can assign names to uicontrols during their creation, so when you need to get one/many of their property you can call the handles with its name instead of the hObject argument.
For example, let's say you name the box with the X data x1, then you can create and store it in the handles structure of the GUI like so:
handles.x1 = uicontrol(...)
so when you need to fetch a property, you can use
get(handles.x1,'Some Property');
So to come back to your question, you could use this syntax to set the UserData property of all the boxes inside My_Callback. Afterward you can recover them in any callback you want. Of course a simple way would be to get the String property of the edit boxes instead of their UserData, but with the latter you can store anything you want which might come handy.
In the following GUI I modified yours to change the callback for the 'OK' button for a function called DisplayData which gets the UserData from each edit box and displays it.
function p = myfun()
clear
clc
f = figure;
set(f,'Position',[200 350 250 150],'Color',[.4 .6 .4],'MenuBar','none',...
'Visible','off');
bc = [.4 .6 .4];
%//===============
uicontrol('Style','text','Position',[50 80 80 30],...
'String','X','BackgroundColor',bc,'ForegroundColor','w');
uicontrol('Style','text','Position',[50 40 80 30],...
'String','Y','BackgroundColor',bc,'ForegroundColor','w');
%//===============
handles.x1 = uicontrol('style','edit's,'Position', [120 80 80 30],...
'BackgroundColor',bc,'ForegroundColor','w','Callback',{#My_Callback});
handles.y1 = uicontrol('style','edit','Position', [120 40 80 30],...
'BackgroundColor',bc,'ForegroundColor','w','Callback',{#My_Callback});
%//===============
uicontrol('Style', 'pushbutton', 'String', 'Ok',...
'Position', [100 5 60 30],'Callback', #(s,e) DisplayData);
movegui(f,'center')
set(f,'Visible','on')
guidata(f,handles); %// Updata guidata
function My_Callback(hObject,eventdata)
p = str2double(get(hObject,'string'));
%// Assign the content of the box to its "UserData" property
set(hObject,'UserData',p)
guidata(f,handles)
end
function DisplayData(~,~)
%// You could do it for all the boxes in your GUI.
x1Data = get(handles.x1,'UserData');
y1Data = get(handles.y1,'UserData');
fprintf('The number in box 1 is %0.2f and the number in box 2 is %0.2f\n',x1Data,y1Data);
guidata(f,handles)
end
end
Sample output:
And after pressing the "OK" button, this string is displayed in the Command Window:
The number in box 1 is 2.00 and the number in box 2 is 4.00
Hope that helps!
As you mentioned in comments, you want to read your values from editbox after the "Ok" button pressed. In order to do this, you should assign your callback function to the "ok" button, not edit boxes:
uicontrol('Style', 'pushbutton', 'String', 'Ok',...
'Position', [100 5 60 30],'Callback', {#My_Callback});
In your Callback function you should read values from all your edit boxes.
I suggest you to use handles when you defined your edit boxes (and better to use it for all the objects):
e1=uicontrol('style','edit','Position', [120 80 80 30],...
'BackgroundColor',bc,'ForegroundColor','w');
e2=uicontrol('style','edit','Position', [120 40 80 30],...
'BackgroundColor',bc,'ForegroundColor','w');
Now, in order to read values, you just use handles of the corresponding edit box.
function My_Callback(hObject,eventdata)
p1 = str2double(get(e1,'string'));
p2 = str2double(get(e2,'string'));
end
Note: this handles (e1,e2) will have cyan color in your code, that means that they are "global" variables, i.e. are used in main code and callback function.
If you don't want to use global handles, you can pass them into callback function. So your callback function will have more arguments.
uicontrol('Style', 'pushbutton', 'String', 'Ok',...
'Position', [100 5 60 30],'Callback', {#My_Callback(e1,e2)});
function My_Callback(hObject,eventdata,e1,e2)
p1 = str2double(get(e1,'string'));
p2 = str2double(get(e2,'string'));
end

Cannot call callback of the pushbutton of the uicontrol in matlab

I am trying to create a button in GUI matlab and call a function when it is pressed. This code it is not working. I have also tried to use these values in the last argument of uicontrol:
fnHi, 'fnHi', 'fnHi();'
The code is:
function [] = testui()
function fnHi()
fprintf('hi');
end
fnHiHandler = #fnHi;
fnHiHandler(); fnHi();
figure();
uicontrol('Style', 'pushbutton', 'string', 'Hi', 'callback', fnHiHandler);
end
The output is:
testui()
hihiUndefined function or variable 'fnHiHandler'.
Error while evaluating uicontrol Callback
So the function works since it is called twice but when I press the button it crashes.
I dont want to use more than one file. Thank you.
Ok, I found the answer. The problem is that fnHi should receive two arguments, otherwise it will crash saying that are too many input arguments. So this code works:
function [] = testui()
function fnHi(source,eventdata)
fprintf('hi');
end
fnHiHandler = #fnHi;
fnHiHandler(); fnHi();
figure();
uicontrol('Style', 'pushbutton', 'string', 'Hi', 'callback', fnHiHandler);
end