Return data from GUIDE on figure close

I have a GUIDE generated UI in which I have wired up one of computed values, to handles and return it through automatically generated callback OutputFcn. When I run my UI, it computes the value and returns it to the command window immediately. The UI has interactive controls which will modify the output value, but it is not returned after the interactive controls are manipulated.
When I add uiwait(handles.figure1), then OutputFcn is not called until close, which is the desired behavior. Unfortunately when I do this the handles passed into OutputFcn is empty. When I omit the uiwait command from OpeningFcn, then the handles object passed to OutputFcn is populated as expected.
It seems that if OutputFcn is called while the figure is still open, then the handles object exists and can be referenced, however, if OutputFcn is not called until I close the figure, then the handles object points to a closed figure and I can no longer reference it.
Any advice to resolve this? Thanks!

 Accepted Answer

Adam Danz
Adam Danz on 13 Sep 2019
Edited: Adam Danz on 14 Sep 2019
To delay a GUIDE-GUI output until the GUI is closed, follow these steps. A functional demo is attached that produces an empty GUI and returns a hard-coded output when the GUI is closed. See comments in the m-file for help.
1) If your GUI does not already have a close request function, add one from within GUIDE by opening your GUI in GUIDE, right click the figure background, select View Callbacks, and the select CloseRequestFcn.
2) In the ..._OpeningFcn
function demoGui_OpeningFcn(hObject, eventdata, handles, varargin)
. . .
uiwait(); % add this to the end
3) In the ..._outputFcn
function varargout = demoGui_OutputFcn(hObject, eventdata, handles)
varargout{1} = handles.output;
delete(hObject); % add this
4) In the ..._CloseRequestFcn you created from GUIDE,
function figure1_CloseRequestFcn(hObject, eventdata, handles)
% delete(hObject); % Remove this
handles.output = 3.1415926; % Produce or grab your outputs
guidata(hObject, handles); % Store the outputs in the GUI
uiresume() % resume UI which will trigger the OutputFcn
[Original answer has been edited]

14 Comments

Thank you for the help. I have the similar structure to what you show. Here is my output function:
function varargout = outputGUI_OutputFcn(~, ~, handles)
% --- Outputs from this function are returned to the command line.
varargout{1} = handles.finalImage;
When I place a breakpoint here on teh varargout line, and omit uiwait from the opening function, handles is filled with the expected data. When I add uiwait to the opening function I do not hit the breakpoint until I close the figure (which is the desired behavior) but, the handles structure is empty :(...
Any thoughts?
What's the purpose of the uiwait in the opening fcn?
I do not want the OutputFcn to be called immeadiately after OpeningFcn is completed. Instead I want to wait to let the user modify output using the GUI, then output on close. I was using uiwait to accomplish this, not sure if that is the right usage, but it does result in delaying the call to OutputFcn until figure close.
I updated the original question. My understanding now is that my wiring is correct, but that when using uiwait, when the figure is close the handles structure is destroyed. I need to access it immediately before it is destroyed or save my data to another non-destroyed structure. Looking for help on this.
Adam Danz
Adam Danz on 13 Sep 2019
Edited: Adam Danz on 13 Sep 2019
ahhh..... ok.
"When I add uiwait(handles.figure1), then OutputFcn is not called until close"
This is the wrong way to go about this (as you've noticed). Get rid of the uiwait. Add the closeReqFcn I described in my answer (this must be added through GUIDE). This function is invoked when you close the GUI. Within the closeReqFcn you can call your outputFcn.
Adam,
Appreciate your help! To be more specific, my GUI is called outputGUI. The output function is not one that I coded but automatically generated. If I call from the command line:
x = outputGUI(); % want to return handles.output to be stored in x on GUI close
then I would like to pass an output variable stored in my handles to back to be stored in x.
As you show I can create a CloseRequestFcn callback, but this will not pass things back to the command window, will it? I think the only way is to use a outputFcn callback. This callback is run immediately after OpeningFcn callback if I do not include uiwait. It is run after figure close if I included uiwait in OpeningFcn, but the handles object has already been destroyed.
If I manually call OutputFcn from CloseRequestFcn it does not return data to the command window.
I would like the output to be passed back to the command window for storage in another variable, not just displayed.
Seems updating the CloseRequestFcn as specified at https://blogs.mathworks.com/videos/2010/02/12/advanced-getting-an-output-from-a-guide-gui/ did the trick for me, along with keeping uiwait in the OpeningFcn
% --- Executes when user attempts to close fullGUIwindow.
function fullGUIwindow_CloseRequestFcn(hObject, eventdata, handles)
% hObject handle to fullGUIwindow (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Hint: delete(hObject) closes the figure
if isequal(get(hObject, 'waitstatus'), 'waiting')
% The GUI is still in UIWAIT, us UIRESUME
uiresume(hObject);
else
% The GUI is no longer waiting, just close it
delete(hObject);
end
The above if else makes me push the close button twice. If I remove the if and else then I get the same issue with handles being destroyed before it can be returned. Even with pause(1) handles is still destroyed by the time I try to return it.
Adam Danz
Adam Danz on 13 Sep 2019
Edited: Adam Danz on 13 Sep 2019
I just played around with this in a GUIDE gui and got this working.
  1. In the '..._OpeningFcn" I call uiwait().
  2. In the '..._outputFcn" I have varargout{1} = handles.output; delete(hObject);
  3. In the '..._CloseRequestFcn" I have handles.output = MyOutput; guidata(hObject, handles); uiresume()
To summarize that in words, the GUI opens and uiwait prevents anything from being output until the GUI closes. When the GUI is closed, it grabs (or produces) the outputs and stores them in the handles structure using guidata and then resumes the uiwait. The output function is invoked which returns the output and destroys the figure.
does this prevent you from closing the GUI? (it seems to for me)
Adam Danz
Adam Danz on 13 Sep 2019
Edited: Adam Danz on 13 Sep 2019
Not for me. I have nothing else in either of those 3 functions listed in the bullet points above. When I press the red 'x' to close the window, it closes. Of course you won't be able to close it using the close() command from the command window since the uiwait is preventing any subsequent commands. If you're using a custom 'close' button, that may operate differently and may require it's own delete(hobject) command.
Adam,
I missed that you moved the delete from the CloseRequest to the Output. This now works as I would like. Thank you very much, you are a wizard!
If I were a wizard I would have understood your question from the getgo!
Glad I could help.
I'll update my answer so it's more useful.

Sign in to comment.

More Answers (1)

Below is a close request function I use in one project. Adapt as needed:
% --- Executes when user attempts to close figMainWindow.
function figMainWindow_CloseRequestFcn(hObject, eventdata, handles)
% hObject handle to figMainWindow (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Hint: delete(hObject) closes the figure
global vidobj; % Video camera object.
try
% Save the current settings to our disk file.
SaveUserSettings(handles, true);
% Shut down the camera
try
delete(vidobj);
catch
end
% Get rid of variables from the global workspace so that they aren't
% hanging around the next time we try to run this m-file.
clear global;
delete(hObject);
catch ME
callStackString = GetCallStack(ME);
errorMessage = sprintf('Error in program %s.\nTraceback (most recent at top):\n%s\nError Message:\n%s', ...
mfilename, callStackString, ME.message);
set(handles.txtInfo, 'string', errorMessage);
WarnUser(errorMessage);
end
fprintf(1, '\n================= Exited figMainWindow_CloseRequestFcn. =================\n');
return; % from figMainWindow_CloseRequestFcn()

3 Comments

I think this does not return any data to the command line which can be captured as a variable. That is my goal.
At the risk of sounding pedantic, the outputFcn returns the output to whatever workspace called the GUI. So if you call the GUI from the command window and included an output, the variable will be assigned to the base workspace. If the GUI is called from another function, the output is assigned to that function's workspace. Just FYI.
I mainly use the close request function to capture situations where the user tries to shutdown the GUI via the x in the upper left of the title bar instead of from an "Exit" button I placed on the GUI. If the user does that (clicks on the X), and you don't have a close request function then the app will shutdown immediately, and if you had any shutdown or cleanup code in the exit button's callback function, then that code won't get implemented, for example shutting down camera(s) or other hardware, closing Excel workbooks, shutting down timers, or whatever you may want to do.
I just checked, and it seems like the OutputFcn() gets called immediately after the OpeningFcn() but does not get called during or after the CloseRequestFcn function, or if you delete the GUI's variable via a call to delete(). It's a good idea to put fprintf's in there so you know what functions get called when. For example:
% Print informational message so you can look in the command window and see the order of program flow.
fprintf('Just entered myApp_OutputFcn...\n');
try
% Get default command line output from handles structure
varargout{1} = handles.output;
% More code if you want....
% Maximize the window via undocumented Java call.
% Reference: http://undocumentedmatlab.com/blog/minimize-maximize-figure-window
MaximizeFigureWindow;
catch ME
% Some error happened if you get here.
callStackString = GetCallStack(ME);
errorMessage = sprintf('Error in program %s.\nTraceback (most recent at top):\n%s\nError Message:\n%s',...
mfilename, callStackString, ME.message);
WarnUser(errorMessage)
end
% Print informational message so you can look in the command window and see the order of program flow.
fprintf('Now leaving myApp_OutputFcn...\n');

Sign in to comment.

Categories

Find more on Scope Variables and Generate Names in Help Center and File Exchange

Products

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!