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.