I am fairly new to writing GUIs in Matlab and noticed that when passing information between callbacks usually two values hObject and handles are passed.
From what I read and understood, hObject is the handle to an object which contains the real data (or at least handles to it) and handles is not itself a handle, but a struct reproducing the structure of objects "behind" hObject. Changing (or adding to) handles does not change the real data as it is seen from the calling function but a local copy. To actually write the changed data into the object pointed to by hObject I need to call guidata(hObject, handles).
Is this right so far or did I get something wrong?
I also read that I can create struct similar to handles by calling handles = guidata(hObject).
So is there any point in passing both hObject and handles to one of my own functions instead of just passing hObject and creating handles locally?
You are correct so far. The input parameter handles is a handy way of keeping track of all the components of the UI. As a standard handles is not an input parameter. But if you use guide it will set is as an extra parameter as follows by setting for example the Callback option to the anonymous function #(hObject,eventdata)guitest('pushbutton1_Callback',hObject,eventdata,guidata(hObject)).
This can of course just as easily be done in the code for the function by handles = guidata(hObject).
Usually you will not need to change in the handles (only in the objects they refer to), but if you need to change something in the handles (for example if you use it to store more than just the handles for the UI elements) it is important to call guidata(hObject, handles) to actually save the changes.
So the short answer to you question is: no, you can just as well retrieve the handles yourself when you need them.
Related
I need to process an image based on where the user is clicking using Matlab Gui. I have found examples which suggest to use the ButtonDownFcn like this:
function buttonSelectSuperpixels_Callback(hObject, eventdata, handles)
h = handles.myCanvas;
set(h,'ButtonDownFcn',#position_and_button);
and then process the clicked points in the subfunction position_and_button like this:
function position_and_button(hObject,eventdata)
Position = get( ancestor(hObject,'axes'), 'CurrentPoint' );
Button = get( ancestor(hObject,'figure'), 'SelectionType' );
However I would need to process some other variables in that last subfunction. Is it possible to pass the handles variable to position_and_button and also update it?
I tried to just pass handles as an argument but it doesn't seem to work.
You can pass the handles struct to your callback by adding it as an input using either an anonymous function
set(h, 'ButtonDownFcn', #(src, evnt)position_and_button(src, evnt, handles))
Or a cell array
set(h, 'ButtonDownFcn', {#position_and_button, handles})
The issue though, is that MATLAB passes variables by value rather than by reference. So when you define these callbacks, they will make a copy of handles as it looks when the callback is created. It is this copy that will be passed to the other function. Additionally, any changes that you make to handles within your callback are made to yet another copy and no other function will ever see these changes.
To avoid this behavior, you can retrieve the handles struct from the guidata within your callback (ensuring you have the most up-to-date version). Then, if you make any changes to it, you would then need to save the guidata after these changes and all other functions will be able to see these changes.
function position_and_button(src, evnt)
% Get the handles struct
handles = guidata(src);
% Now use handles struct however you want including changing variables
handles.variable2 = 2;
% Now save the changes
guidata(src, handles)
% Update the CData of the image rather than creating a new one
set(src, 'CData', newimage)
end
In this case, you would only need to specify the default two inputs to the callback function.
I am relatively new to MATLAB so forgive me if this is rather basic question. I am trying to understand how to manipulate variables and pass the results between functions within the GUI.
If I set up the GUI using the GUIDE interface I get several functions. I would like to do a certain action when I click a pushbutton, save a variable, then use that variable in another function.
function pushbutton1_Callback(hObject, eventdata, handles)
handles.MyData = 7;
Now, since that data is stored in handles can I not simply use this in another function within the GUI in this fashion?
function pushbutton2_Callback(hObject, eventdata, handles)
result = 5 + handles.MyData;
This is a really simple example, but I am trying to get down to the logic of how to pass variables. I know there is a lot of information out there and I have read it but I cannot get down to the logic of how the variables are stored in the structure and how they can be passed between functions.
When you update the handles struct, you have to store it using guidata:
guidata(hObject, handles);
Then you can use it in a different callback.
I am struggling to use axes on my GUI because it says it is not defined. Here is the summary of the code :
function bitirme_OpeningFcn(hObject, eventdata, handles, varargin)
axes(handles.axes1)
imshow('photo1.jpg');
...
function pushbutton1_Callback(hObject, eventdata, handles)
theta=inverseKinematic(...)
...
function [Theta1,Theta2]=inverseKinematic(angle1,angle2,angle3,desCorX,desCorY)
axes(handles.axes1);
....
plot(a,b);
....
Until the function inverseKinematic is called,everything works fine. However when it is called, the image doesn't turn to be a graphic and I see the error " Undefined variable "handles" or class "handles.axes3" " on matlab command window. Why can I not call axes(handles.axes1) in a nested function? What is the reason behind it?
Each function has its own workspace, and callbacks generated by GUIDE share data associated with what is called the handles structure. Every components of the GUI (axes, pushbuttons, etc.) are associated with the figure in which they are located. Hence GUIDE already provides the callback functions with everything stored in the handles structure.
However, nested functions do not have implicit access to the data stored in the handles structure. You need to specifically provide those data to the functions. There are a couple options available, for example:
1) Provide the handles structure as an input argument to the function.
2) Use getappdata and setappdata functions to associate data with a figure or MATLAB's root
3) Retrieve the handles structure "by hand" at the very beginning of the nested functions like so for example:
function [Theta1,Theta2]=inverseKinematic(angle1,angle2,angle3,desCorX,desCorY)
handles = guidata(gcf)
axes(handles.axes1);
....
plot(a,b);
....
%// Save the changes made to the handles structure.
guidata(handles to the figure,handles);
where gcf refers to the current figure. You can actually use the name of the figure or hObject.
Note that when using the command plot, you don't need to set the current axes before each call. You can use the Parent property inside the call to plot to select where to plot the data.
Example:
plot(a,b,'Parent',handles.axes1)
I hope that was clear enough!
Inside of one parent function, I have a callback function related to a button on a gui.
When the button is pressed, one of the things it does is define a variable (let's say X) that needs to be persistent so that later on, another sub function to the parent function can use X.
(i.e. callback functionA creates variable X.
later on, functionB requires variable X to be known, to know a specific path to take)
Is there any way to go about this?
I've read up on using handles to pass it to the second function, but I can't seem to figure out a way to do this.
Indirectly from Matlab guidata documentation:
in the first callback function:
function first_Callback(hObject, eventdata, handles)
% add some additional data as a new field called x
handles.x = 1;
% Save the change you made to the structure
guidata(hObject, handles)
in the second callback function simply use handles.x because handles is already passed as a parameter to the second callback, if they belong to the same parent figure.
function second_Callback(hObject, eventdata, handles)
% a will have the value 1
a = handles.x;
Note: Even though you are saving handles to hObject (which is the current object that has called the callback function), the handles structures is visible to other objects on the same figure. Saving handles structure to hObject and saving to the parent figure are virtually the same. Also you only need to use guidata if you make changes to the handles structure. If you only read the value of a handles member, you don't need to save it after that.
I've written a Matlab script that reads in data using a virtual COMM port in real-time. I've done a significant amount of signal processing in an mfile.
Next, I felt the need to have a compact GUI that displays the information as summary.
I only recently started digging and reading more of Matlab's built-in GUI tool, GUIDE. I've followed a few tutorials and am successfully able to get my graphs to display on my GUI after a button-press.
However, I want the GUI to update in real-time. My data vector is constantly updating (reading in data from the COMM port). I want the GUI to keep updating the graphs with the newer data, as opposed to relying on a button press for an update. Can someone please point me in the right direction for background updating?
Here is the relevant code currently for the GUI:
% --- Executes on button press in pushbutton1.
function pushbutton1_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global data
global time
% Time domain plot
axes(handles.timeDomainPlot);
cla;
plot (time, data);
EDIT Changed code:
% --- Executes on button press in pushbutton1.
function pushbutton1_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
%Setting it to display something when it ends
% t = timer('TimerFcn', 'timerOn=false; disp(''Updating GUI!'')',...
t = timer(...
'TasksToExecute', 10, ... % Number of times to run the timer object
'Period', 3, ...
'TimerFcn', GUIUpdate());
%Starting the timer
start(t)
function GUIUpdate()
global data
global time
%Parameters below axes
global min
global max
% Time domain plot
axes(handles.timeDomainPlot);
cla;
plot (time, data);
%Other parameters:
set(handles.mean, 'String', mean);
set(handles.max, 'String', max);
The error that I get is:
??? Error using ==> GUI_Learning>GUIUpdate
Too many output arguments.
Error in ==>
#(hObject,eventdata)GUI_Learning('pushbutton1_Callback',hObject,eventdata,guidata(hObject))
??? Error while evaluating uicontrol Callback
Here is an example using a timer with a timerFcn callback. I made a simple GUI with 1 axes and 1 button.
In the opening function I initialize the plot and create the timer. In the start button callback I start the timer and start manipulating the data. The timer function callback the just updates the y-data of the line via its handle. Below are the relevant functions from the GUI's M-file (snipped init section and output fcn.
function testTimer_OpeningFcn(hObject, eventdata, handles, varargin)
global y x
x = 0:.1:3*pi; % Make up some data and plot
y = sin(x);
handles.plot = plot(handles.axes1,x,y);
handles.timer = timer('ExecutionMode','fixedRate',...
'Period', 0.5,...
'TimerFcn', {#GUIUpdate,handles});
handles.output = hObject;
guidata(hObject, handles);
% --- Executes on button press in startButton.
function startButton_Callback(hObject, eventdata, handles)
global y x
start(handles.timer)
for i =1:30
y = sin(x+i/10);
pause(1)
end
function GUIUpdate(obj,event,handles)
global y
set(handles.plot,'ydata',y);
You may want a Stop button to stop the timer depending on how your GUI is structured and were/how the data is updated.
Edit: Basic handles info some of this is pretty basic and you may already know it:
An individual handle to an object contains a bunch of properties that you can read with the get() function or set with the set() function. So for example maybe I wanted to change the text of the startButton for some reason in my GUI.
set(handles.startButton,'String','Something Other Than Start');
You may just want to set a break point in your code somewhere (maybe in a button press) and play around with the handles struct. Running get() commands on various objects to learn their properties.
Now the handles structure contains all of the ... umm... handles to your GUI's objects as well as any custom items that may be convenient for your to store there. Most GUI callbacks automatically get passed the handles struct so you have easy access to all parts of the GUI.
Ex. The 'startButton' callback was automatically passed handles. So I had easy access to the timer object via handles.timer.
Which brings me to sticking custom things into handles. In the opening function I added a new item to the handles structure handles.timer and handles.plot because I knew they would be useful in other callbacks (like button press and the timerFcn callback).
However, to store these things permanently you need to use the 'guidata' function. This function basically either stores the modified handles struct or retrieves a copy of handles depending on how you call it. So the following line in the opening function is storing the modified handles structure (added .timer and .plot) into the main GUI.
guidata(hObject,handles);
Basically any time you add something in handles you should have that line to make the change permanent.
Now the other method of calling it is:
handles = guidata(hObject); %hObject can be any handle who is a child of the main GUI.
This will retrieve the handles structure for the GUI.
And last handles.output = hObject is just the default output when you launch your GUI. IF you call your GUI via Matlab's command line like this h = myGUI; it should return the handle to your GUI.
You need to use a timer object. Set the callback to be the function that updates the plots.
Take a look at Making Graphs Responsive with Data Linking
and the linkdata command.
If the same variable appears in plots in multiple figures, you can
link any of the plots to the variable. You can use linked plots in
concert with Marking Up Graphs with Data Brushing, but also on their
own. Linking plots lets you
Make graphs respond to changes in variables in the base workspace or within a function
Make graphs respond when you change variables in the Variable Editor and Command Line
Modify variables through data brushing that affect different graphical representations of them at once
Create graphical "watch windows" for debugging purposes
Watch windows are useful if you program in the MATLAB language. For
example, when refining a data processing algorithm to step through
your code, you can see graphs respond to changes in variables as a
function executes statements.
I made a quick and dirty test seen below and I am not sure how this will work in a GUI verses a function but may do the trick.
Note 1: I had to add a break point in my subroutine where it modifies the global y to actually see the plot auto-update. You may need some combination of drawnow, pause, or a timer if data is getting changed rapidly.
function testLinking()
global x y
%Links failed if the global did not also exist in the base workspace
evalin('base','global x y');
x = 0:.1:3*pi; % Make up some data and plot
y = sin(x);
h = plot(x,y,'ydatasource','y','xdatasource','x');
linkdata on
testSub
function testSub()
%Test to see if a sub can make a linked global refresh
global x y
for i = 1:10
%This should automatically update the plot.
y = sin(x+i/10);
end
Edit: there may be ways around the use of globals depending on how your functions are structured ... but I don't have time to dig into it to much.
You can add a callback on the serial object that executes a plotting function. You must attach the callback to the 'BytesAvailableFcn' event on the object (see this for more details on the properties of the com object).
Essentially, when there are bytes available on the com port, you instruct matlab to run a specific function. In your case, it will be the function updating the GUI. If you need to process the incoming data first, then your callback function will first do the signal processing and then do the plotting commands.