I'm trying to create a GUI using GUIDE, which reads a string through serial communication. After that it cuts out the needed numbers and puts it on the screen. I have created this function, which is executed every time when there is a line of data in the buffer of the COM port:
function out = intcon1(hObject, eventdata, handles)
global comPort;
a=fgetl(comPort);
disp(a);
a(a==' ') = '';
indexstart=strfind(a,'[');
indexend=strfind(a,']');
measureddata=a(indexstart(1):indexend(1));
commas=strfind(measureddata,',');
re1data=measureddata(2:(commas(1)-1));
re2data=measureddata((commas(1)+1):(commas(2)-1));
im1data=measureddata((commas(2)+1):(commas(3)-1));
im2data=measureddata((commas(3)+1):(commas(4)-1));
temp1data=measureddata((commas(4)+1):(commas(5)-1));
temp2data=measureddata((commas(5)+1):(commas(6)-1));
old_str=get(handle.re1, 'String');
new_str=strvcat(old_str, re1data);
set(handles.listbox8, 'String', re1data);
Now I'm trying to put the data into a listbox. This is just the first value. The problem is, that Matlab keeps saying, that the handles are not defined. But I cound already create a button which clears the listbox using the following code:
function clearlists_Callback(hObject, eventdata, handles)
% hObject handle to clearlists (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
set(handles.listbox8, 'String', '');
Does anyone have any idea what the problem is and how to fix it?
Serial port callbacks are different to GUIDE callbacks. In the case of a serial port callback your object handle is to the serial port object and the event is a serial event. There is no third argument, hence handles being undefined.
If you want to retrieve your GUI handles from within this function you'll need to do so explicitly, similar to the way you're retrieving the comport handle - incidentally getting comport this way is probably unnecessary since I'd imagine it's the same object the callback is already receiving as hObject.
Since in this case handles is GUIDE-specific data, the 'proper' way to retrieve it
would be:
handles = guidata(gcf);
If your GUI has multiple figures, you may need to use findobj() instead of gcf() to get the right one.
You probably defined your BytesAvailableFCN using function handle syntax without additional arguments, like this
s.BytesAvailableFCN = #myfun();
Instead, you need to define your callback using a cell array, as explained here in the documentation. For example,
s.BytesAvailableFCN = {'myFun', handles};
handles must already be defined and in your workspace when that line is run.
Related
This is a similar problem encountered by many others where guidata(hOjbect, handles) does not seem to update a value. I'm using it with a listener, and am not sure how to proceed.
In my gui_OpeningFcn I have the following line:
addlistener(handles.s, 'name', 'PostSet', #(s,e)updatefilesave(hObject, [], handles));
This sets the listener appropriately and it does call updatefilesave when name is modified. However, inside updatefilesave is the following code:
handles.fileUnsaved = true;
guidata(hObject, handles);
Inside the function, both lines work. When I breakpoint on the first line and step, fileUnsaved gets set to true. After I step the second line (while still inside the updatefilesave function), handles.fileUnsaved is still set to true.
However, when I step out of the function, the green arrow gets put on to the addlistener line in the gui_OpeningFcn function. at this level, handles.fileUnsaved is now set back to false.
How do I get handles to update when using a listener?
EDIT
What I'm trying to do is know when input fields have changed so I can prompt the user to save their work before closing the program. I check the fileUnsaved flag in the CloseRequestFcn and if it is true, I ask the user if they want to save before exiting.
function namebox_Callback(hObject, eventdata, handles)
newName = handles.namebox.String;
if ~isempty(newName)
handles.s.name = newName; % (listener gets triggered here post set)
end
handles.namebox.String = handles.s.name;
guidata(hObject, handles); % (namebox's local handles with fileUnsaved set to false gets put into hObject)
This is why I cannot call handles = guidata(hObject) in the CloseRequestFcn. The only way to stop this is to call handles = guidata(hObject) in the namebox callback before I call guidata(hObject, handles). But doing that everywhere would defeat the point of using listeners. I would just go and set fileUnsaved to true in every callback function (about 50 of them).
In general, if you want to have a function that you call from one callback to modify handles and then have those changes be made available to the calling function, you'll need to not only save the handles struct in the called function (so that they are available to other callbacks), but you have to re-load the handles struct in the calling function otherwise the calling function is just going to simply use it's own local (and unmodified) copy of handles since it has no way to know that it was modified.
function main_callback(hObject, eventData, handles)
% Set the value to one thing
handles.value = false;
sub_callback(hObject, eventData, handles);
% Check that the value is STILL false
disp(handles.value)
% Load in the change so that handles gets updated
handles = guidata(hObject);
end
function sub_callback(hObject, eventData, handles)
handles.value = true;
% Save the value
guidata(hObject, handles);
end
The other option, is to have your other function actually return the modified handles
function handles = sub_callback(hObject, eventData, handles)
handles.value = true;
guidata(hObject, value);
end
And then from within the calling function you can use the output argument to overwrite the local handles variable
handles = sub_callback(hObject, eventData, handles);
Now to your specific question regarding addlistener, since the callback is executed in an "asynchronous" sense, it doesn't really make sense to return a value. What I would recommend though is to reload the handles data (as shown in the first example), before you go to use handles again (where you expect it to be changed) to ensure that you have the most up-to-date version.
I stumbled upon this thread having a similar issue, but for me modifying handles inside the listener seems to be working.
In the outside function, I have something like this:
handles.myListener = addlistener(ObjectThrowingEvent,'EventName', #(src,evt)ListenerFunction(src, evnt, hObject));
guidata(hObject,handles);
Then in the inside function
function ListenerFunction(ObjectThrowingEvent, eventData, hObject)
handles = guidata(hObject)
% a bunch of stuff happens, including updates to the handles structure
guidata(hObject, handles);
To me it looks like the difference is that I'm passing in hObject and looking up the handles from hObject in the listener. Even though the listener is asynchronous, it's being passed hObject which I think just points to the current state of the figure rather than some local non-updated copy.
I'd be curious if this works for you. It seems to be working in my code so far.
I have a GUI called GUI_main in which I have a pushbutton called pushbutton_GUI_main. I currently have the following callback function implemented:
function pushbutton_GUI_main_Callback(hObject, eventdata, handles)
GUI_sub
Where GUI_sub is another GUI that opens when you click on pushbutton_GUI_main. However, I want something like the following:
function pushbutton_GUI_main_Callback(hObject, eventdata, handles)
if (GUI_sub == open)
close(GUI_sub)
else
GUI_sub
That is, with pushbutton_GUI_main I want to be able to open and close GUI_sub.
You need an object handle to reference the sub GUI. Assuming GUI_sub is a GUI built with GUIDE, it is programmed by default with an optional handle output.
A naive implementation for a GUIDE GUI would look something like this:
function pushbutton1_Callback(hObject, eventdata, handles)
if ~isempty(handles.figure1.UserData)
close(handles.figure1.UserData);
handles.figure1.UserData = [];
else
handles.figure1.UserData = sub_GUI;
end
Most of (maybe all?) MATLAB's graphics objects have a UserData field by default. I've utilized the UserData of the base figure object for this simple example. See also: Share Data Among Callbacks for other methods to store/transfer this data.
As excaza says, handles is a great way to pass data or information in a GUI.
Another way, if you for some reason don't want to store the GUI handle, perhaps if the GUI_sub could be created independently is to search for the figure handle.
subGuiH = findall(0,'Name','GUI_sub');
if ~isempty(subGuiH)
close(subGuiH);
end
GUI_sub;
The search could be narrowed by adding
findall(0,'Type','figure','Name','GUI_sub')
Depending on your Matlab version, you could also checkout groot
My Matlab GUI is a form with many text fields that are initially populated using the same data struct. Each text field has a callback and a create function, where the text field is assigned the value of the given struct. However, at some later point I would like to repopulate the form using a different struct, as an event triggered by pressing a push button. The code looks approximately like:
h = MyFigure;
global mystruct
mystruct = somevalues;
handles = guidata(h);
set( handles.textfield1, 'String', mystruct.value1 )
...
set( handles.textfieldN, 'String', mystruct.valueN )
However, if I could make Matlab call all these callbacks recursively (like a "validate tree" function), I wouldn't have to call "set" for each text field. I have tried refresh(h) and drawnow(), with no luck.
Now my question is whether or not there is such a function built into the matlab guide framework?
When you set a property of a handle like set(h,'String',str), the value of str is copied. It is not a reference to that variable that can be updated automatically. Your best bet is to make a subroutine called updateText or something like that, put all of the set statements in it, and call it when needed.
Calling guidata(hObject, handles); is only for updating the GUI with modifications to handles. You may need this elsewhere, but for the job of updating properties of certain handle graphics objects, it is not really used.
One possibility is to create a timer to update the text fields on a regular basis. In your GUI's opening function, create a timer that defines an update function to run periodically:
T = timer('Period',1,'StartDelay',0.5,'TimerFcn', ...
{#updateTextBoxes,handles},'ExecutionMode','FixedRate');
start(T)
The update function would look like:
function updateTextBoxes(hTimerObj, timerEvent, handles)
global mystruct
% get mystruct data however you do it...
% maybe also get handles via handles=guidata(hTimerObj); instead of input
set( handles.textfield1, 'String', mystruct.value1 )
...
set( handles.textfieldN, 'String', mystruct.valueN )
EDIT: Do NOT forget to delete the timer (delete(T)) or stop it before you quit the GUI or do clear T, otherwise it will just keep running and you will have to quit MATLAB... No, I did not just do this myself!
You need to update the handles structure with this :
% Update handles structure
guidata(hObject, handles);
I created a GUI named SCADA and I added a boolean variable called StatusData which is a flag that that is set to false when the GUI is launched
handles.StatusData=false;
guidata(handles.output,handles);
I press a button and then a function is called which executes continuously (the function has infinite loop). After some time I press another button which sets the StatusData to true.
handles.StatusData=true;
guidata(handles.output,handles);
Now, I need to access the StatusData from the callback function (the same function I mentioned above), In order to acheieve this I sent the handle as a parameter when I called that function. Now, When the pressed the button that changes the StatusData, the data in the actual handle changes but I cannot access the updated StatusData as the function is already called.
How can I access the updated handle of GUI without sending it as a parameter.
Thanks
You can just pass in the hObject parameter to your function instead, and retrieve your value when it's needed using guidata; i.e.,
function some_callback(hObject, handles, ...)
myLoopingFunction(hObject, ...);
function myLoopingFunction(hObject, ...)
for someVar = something
% Update handles structure
handles = guidata(hObject);
end
Alternatively you could create a handle object and put that in the handles structure; e.g.,
% In a separate file:
classdef uiState < handle
% Probably should give this class a less general name...
properties
StatusData
end
end
% In your UI file:
function some_callback(hObject, handles, ...)
handles.state = uiState();
handles.state.StatusData = false;
% Now, when you modify handles.StatusData, the version used by
% myLoopingFunction will also be updated, because they point to
% the same object!
myLoopingFunction(handles.state);
function myLoopingFunction(state, ...)
for someVar = something
% Now you just have to check state.StatusData
end
For simple cases, I'd use the first method. For more complicated situations, where several parameters must be kept track of and they interact in complex ways, I would use the second. The second is also useful if you have a large chunk of data in some variable and want to stop it from being copied into every call to the UI.
Personally, for a complex UI I would usually create some application class that keeps track of the user interface (and provides a command-line interface to it) and make sure that was always available to my UI, but that is a bit like using a sledgehammer to open a jam jar in this simple case.
I save and load gui data as described in the manual using
function readImage(filename, hObject, handles)
handles.image.data = imageRGBNoEdge;
guidata(hObject,handles);
and
function createHistogram(handles)
imageRGB = handles.image.data;
which are both called directly after the other
readImage(imageFile,hObject,handles);
createHistogram(handles);
However in he second function handles.image is unkown.
??? Reference to non-existent field 'image'.
Error in ==> ui_histogram>createHistogram at 252
imageRGB = handles.image.data;
But if I call the function a second time it is known?
Despite its name, handles is a structure and not a handle class so changing it within readImage does not propagate the change to the calling function.
You could either change readImage to be
function handles = readImage(filename, hObject, handles)
and call it with
handles = readImage(imageFile,hObject,handles);
or add a call to guidata
handles = guidata(hObject);
just before your calll to createHistogram.
I'm working off the assumption that imageRGBNoEdge is already defined at this point.
By briefly looking over the guidata function documentation it looks like that could be part of the issue here. When you try to load the data within createHistogram you need to be using something like this: imageRGB = guidata(hObject) because that is what tells guidata what data to get for you and you've already saved the data to that object handle (hObject)
Also, I can't really comment much more because it looks like there is also a fair bit of missing code for each of those functions. Hopefully this will help get you going in the right direction though!