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
Related
I have a listbox on my gui. When I start the programm the first value in the listbox is selected. But the programm only registers a value when you click it first.
So is there a way the programm can start my calculation without having to click the first option in the listbox?
My idea was to set the handle in the Openingfunction, but it wont work out.
Here is my code:
function lastfolge_aufbereiten_OpeningFcn(hObject, eventdata, handles, varargin)
...
...
guidata(hObject, handles);
function listbox_runden_stelle_Callback(hObject, eventdata, handles)
contents=cellstr(get(hObject,'String'));
popupmenu_runden_stelle=contents(get(hObject,'Value'));
if (strcmp(popupmenu_runden_stelle,'10'))
y=1;
elseif (strcmp(popupmenu_runden_stelle,'100'))
y=2;
end
handles.y=y;
guidata(hObject, handles);
A quick fix (but not so pretty) could be to call you listbox_runden_stelle_Callback in the Openingfunction with the handle to your popup menu as input.
listbox_runden_stelle_Callback(handles.listbox_runden_stelle, [], handles)
A more general answer: You can use the CreateFcn that is executed when MATLAB creates the uicontrol (popupmenu). Below is a short example where both CreateFnc and Callback calls the a common evaluation function
function PopupMenu()
figure;
uicontrol(...
'Style', 'popup', ...
'String', {'Hello', 'World'}, ...
'CreateFcn', #PopupMenuCreateFcn, ...
'Callback', #PopupMenuCallback);
function PopupMenuCallback(hObject, ~)
disp('In Callback()')
PopupMenuEvaluate(hObject);
function PopupMenuCreateFcn(hObject, ~)
disp('In CreateFcn()')
PopupMenuEvaluate(hObject);
function PopupMenuEvaluate(popupMenu)
fprintf('Evaluated "%s" \n', popupMenu.String{popupMenu.Value})
(if you're using an older Matlab version you might have to replace "~" with an dummy string and the . (dot) operator with get(...) to get properties)
When running this, the CreateFcn is called upon directly, without the user selecting from the menu.
>> PopupMenu
In CreateFcn()
Evaluated "Hello"
If user then select 'World'
In Callback()
Evaluated "World"
If the same things is to be done for both CreateFcn and Callback you could just bind them to the same common function
uicontrol(...
'Style', 'popup', ...
'String', {'Hello', 'World'}, ...
'CreateFcn', #PopupMenuEvaluate, ...
'Callback', #PopupMenuEvaluate);
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 :)
Background: I have several portion in an GUI to handle different tasks. In 1 portion (portion1) I have text input and send button. So once I will click send it would send one data to my serial port. Another portion (portion2) would receive signal from serial port which have been received from other devices. Both the portions are using two buttons; one to start the work of that particular portion and one to stop the work. I have used global variables and while loop (with boolean) to exit the infinite loop, as I need to send the data or receive data continuously.
My question: Problem is when I am using global variables and the above mentioned way of using infinite loop, if I click portion1, portion1 will start iterate. Now if I click portion2 then portion1 will be stopped. But I need to use them both at the same time and both of them will continuously send and receive data until I click other button (s) to exit the infinite loop.
My sample code for clarification:
function send_Callback(hObject, eventdata, handles)
global firstFlag;
firstFlag = true;
while firstFlag
%Required codes
end
function haltSend_Callback(hObject, eventdata, handles)
global firstFlag;
firstFlag = false;
function receive_Callback(hObject, eventdata, handles)
global secondFlag;
secondFlag = true;
while true
%Required codes
end
function stopReceive_Callback(hObject, eventdata, handles)
global secondFlag;
secondFlag=false;
I have tried to find a solution referring to internet, but most of the solutions are using global variable. It would be better if I could work without global variables. But even if my requirements are fulfilled (as per my question) it would work.
Global or not is not the issue here.
Callbacks in Matlab all run on the same thread.
So when callback1 is running and you trigger callback2, callback2 will interrupt callback1.
callback1 will then only proceed once callback2 is finished.
You can only slightly modify this procedure using the BusyAction property:
http://www.mathworks.de/de/help/matlab/ref/uicontrol_props.html#bqxoija
But this won't help in your case.
In a "proper" programming language, you'd have a sending and a receiving thread running in parallel. You can't do this matlab however - unless you're e.g. willing to write java-code.
If you want to stick with matlab, the closest to thread would be timers.
These would replace your while loops.
E.g. as in the following minimalistic example:
function cbtest()
try close('cbtest');end
f = figure('name', 'cbtest');
% create the timers:
period = 0.2; % period in seconds, in which the timer shall execute
sendTimer = timer('TimerFcn', #sendFcn, 'ExecutionMode', 'fixedDelay', 'Period', period, 'TasksToExecute', Inf);
recvTimer = timer('TimerFcn', #recvFcn, 'ExecutionMode', 'fixedDelay', 'Period', period, 'TasksToExecute', Inf);
uicontrol(f, 'position', [10 10 100 25], 'Callback', #(a,b) start(sendTimer), 'string', 'start1');
uicontrol(f, 'position', [120 10 100 25], 'Callback', #(a,b) stop(sendTimer), 'string', 'stop1');
uicontrol(f, 'position', [10 50 100 25], 'Callback', #(a,b) start(recvTimer), 'string', 'start2');
uicontrol(f, 'position', [120 50 100 25], 'Callback', #(a,b) stop(recvTimer), 'string', 'stop2');
end
function sendFcn(hTimer, timerEvt)
% your send-loop-code
disp('sending');
end
function recvFcn(hTimer, timerEvt)
% your receive-loop-code
disp('receiving');
end
sendFcn and recvFcn here then should contain the code you have within your according while loops.
You can of course lower the period to your needs, I chose the above for testing purposes.
Your problem is that you're executing the loop inside the Callbacks. So when the second button is clicked, the second callback will start and loop infinitely, until it is ended. The first loop will wait for the second Callback to terminate until it can resume. What you need is a main program where you execute your loop. Nesting the Callbacks will make sure they can access and change the local variables without making them global. If you're fine with building a GUI programmatically, try this:
function main()
sendFlag = false;
receiveFlag = false;
while true
if sendFlag
% Your Sending code
end
if receiveFlag
% Your Receiving code
end
end
function send_Callback(~,~,~)
sendFlag = true;
end
% other Callbacks
end
Then in the Callbacks for your Buttons (you could use Toggle Buttons by the way), you simply set the sendFlag and receiveFlag, respectively.
Using GUIDE, you want to use toggle buttons.
I don't exactly know how GUIDE handles the OpeningFcn, so you should probably put a "Start" button into your GUI which basically executes the above program with a few changes:
function startbutton_Callback(hObject,~,handles)
while true
handles = guidata(hObject); % Updates handles structure
sendFlag = get(handles.sendtoggle, 'Value');
if sendFlag
% Your Sending code
end
receiveFlag = get(handles.receivetoggle, 'Value');
if receiveFlag
% Your Receiving code
end
end
Also, create send and receive toggle buttons and set their 'Min' to 0 and 'Max' to 1. This will make them switch their 'Value' property (which you read in the above loop) between 0 and 1 when you click them. In the Callback, you can change what they display:
function send_Callback(hObject,~,handles)
on = get(hObject,'Value');
if on
set(hObject, 'String', 'Stop sending');
else
set(hObject, 'String', 'Start sending');
end
guidata(hObject,handles); % Update GUI data
Now your main function, which starts when you click the start button, runs the loop and just checks the toggle buttons' states to determine whether to send and receive.
I am working on pattern recognition project and currently in GUI creation phase. I would like to have a pushbutton that is able to perform the following command once the pushbutton is clicked:
a = imread(image_name);
b = rgb2gray(a);
glcm = graycomatrix(b);
glcm (:);
May I know what function should I use to program the pushbutton? Your help is greatly appreciated.
Thank you.
Seems to me like you don't know how to make callback functions. Here's how to do it if you're building your GUI programmatically:
% create the button
but = uicontrol(...
'style', 'pushbutton', ...
'string', 'my awesome button',...
'callback', #buttonCallback); % <--- SET CALLBACK HERE
function buttonCallback(~,~) % <--- what's called back when pressing the button
a = imread(image_name);
b = rgb2gray(a);
glcm = graycomatrix(b);
glcm (:);
end
How to do it via GUIDE is similar, and outlined in detail here.
Is it possible to write a GUI from inside a function?
The problem is that the callback of all GUI-functions are evaluated in the global workspace. But functions have their own workspace and can not access variables in the global workspace. Is it possible to make the GUI-functions use the workspace of the function? For example:
function myvar = myfunc()
myvar = true;
h_fig = figure;
% create a useless button
uicontrol( h_fig, 'style', 'pushbutton', ...
'string', 'clickme', ...
'callback', 'myvar = false' );
% wait for the button to be pressed
while myvar
pause( 0.2 );
end
close( h_fig );
disp( 'this will never be displayed' );
end
This event-loop will run indefinitely, since the callback will not modify myvar in the function. Instead it will create a new myvar in the global workspace.
There are a number of ways to build a GUI, such as using the App Designer, GUIDE, or creating it programmatically (I'll illustrate this option below). It's also important to be aware of the different ways to define callback functions for your GUI components and the options available for sharing data between components.
The approach I'm partial to is using nested functions as callbacks. Here's a simple GUI as an example:
function make_useless_button()
% Initialize variables and graphics:
iCounter = 0;
hFigure = figure;
hButton = uicontrol('Style', 'pushbutton', 'Parent', hFigure, ...
'String', 'Blah', 'Callback', #increment);
% Nested callback function:
function increment(~, ~)
iCounter = iCounter+1;
disp(iCounter);
end
end
When you run this code, the counter displayed should increment by one every time you press the button, because the nested function increment has access to the workspace of make_useless_button and thus can modify iCounter. Note that the button callback is set to a function handle to increment, and that this function must accept two arguments by default: a graphics handle for the UI component that triggered the callback, and a structure of associated event data. We ignore them with the ~ in this case since we aren't using them.
Extending the above approach to your particular problem, you could add your loop and change the callback so it sets your flag variable to false:
function make_stop_button()
% Initialize variables and graphics:
keepLooping = true;
hFigure = figure;
hButton = uicontrol('Style', 'pushbutton', 'Parent', hFigure, ...
'String', 'Stop', 'Callback', #stop_fcn);
% Keep looping until the button is pressed:
while keepLooping,
drawnow;
end
% Delete the figure:
delete(hFigure);
% Nested callback function:
function stop_fcn(~, ~)
keepLooping = false;
end
end
The drawnow is needed here to give the button callback a chance to interrupt the program flow within the loop and modify the value of keepLooping.
You can declare a variable global in your function and global in the GUI code, certainly if the callback is in a separate function rather than inline. I've done this in a little skeleton GUI I use to make quick menu system.
In your code above you may be able to add the global keyword to your initial declaration and also to your inline callback i.e. 'global myvar = false'
I found a solution to the problem. The callback-function has to modify the handle-structure of the GUI. This structure can be accessed both from within the callback and from the function without introducing new variables to the global workspace:
function myfunc()
h_fig = figure;
% add continue_loop to the GUI-handles structure
fig_handles = guihandles( h_fig );
fig_handles.continue_loop = true;
guidata( h_fig, fig_handles );
% create a useless button
uicontrol( h_fig, 'style', 'pushbutton', ...
'string', 'clickme', ...
'callback', #gui_callback );
% wait for the button to be pressed
while fig_handles.continue_loop
fig_handles = guidata( h_fig ); % update handles
pause( 0.2 );
end
close( h_fig );
disp( 'callback ran successfully' );
end
% The arguments are the Matlab-defaults for GUI-callbacks.
function gui_callback( hObject, eventdata, handles )
% modify and save handles-Structure
handles.continue_loop = false;
guidata( hObject, handles );
end
note that since the while-loop will only update fig_handles when it is run, you will always have at least 0.2 seconds delay until the loop catches the modification of fig_handles.continue_loop