You are now following this question
- You will see updates in your followed content feed.
- You may receive emails, depending on your communication preferences.
How to detect the close window event for a "bar" graph
5 views (last 30 days)
Show older comments
I tried to use the CloseRequestFcn to specify the close action for a bar graph but it does not work. It seems that it only works for figures.
How can I detect the user action of closing a bar graph window and change its behavior?
Thanks in advance for your help!
Answers (1)
Adam Danz
on 4 Sep 2020
Edited: Adam Danz
on 4 Sep 2020
To invoke an action when the bars are deleted, use the DeleteFcn property of the bar object. Bars can be deleted using cla(), delete(h) where h is the bar handle, or when the figure closes.
The CloseRequestFcn is invoked when the figure closes which will also invoke the DeleteFcn if the bars still exist. See a demo in the comments below this answer.
22 Comments
Chao
on 4 Sep 2020
Edited: Adam Danz
on 4 Sep 2020
Thanks Adam for your quick reply!
Is closing the bar figure window and deleting the bars the same thing? I tried it and it doesn't seem to work:
Below is what I have
bar(x, data(2:11), 'DeleteFcn',@my_closereq )
function my_closereq(src,callbackdata)
% Close request function
delete(gcf)
clear s1;
end
Adam Danz
on 4 Sep 2020
'Is closing the bar figure window and deleting the bars the same thing?"
No. Closing the figure invokes the figure's CloseRequestFcn as well as the bars' DeleteFcn but if you clear the axes or delete the bar objects without closing the figure, the DeleteFcn will be invoked but not the CloseRequestFcn.
Example:
fig = figure();
fig.CloseRequestFcn = @(~,~)fprintf('Fig close req called!\n');
h = bar(1:5);
h.DeleteFcn = @(~,~)fprintf('Bars deleted!\n');
now execute the command below to clear the axes and watch the Command Window.
cla()
now try to close the figure and watch the command window
close(fig)
Notice that the figure didn't close because now it has no function to close it! To close it,
close(fig, 'force')
Adam Danz
on 4 Sep 2020
Your callback function is not working because it has no idea what "s1" is. That variable needs to be passed into the function. Also, don't use gcf when you have access to the figure's handle.
h = bar(x, data(2:11), 'DeleteFcn',@my_closereq);
function my_closereq(src,event,c)
% Close request function
delete(ancestor(src, 'figure'))
clear(c)
end
Chao
on 8 Sep 2020
Edited: Adam Danz
on 8 Sep 2020
Hi Adam,
Thanks very much for your answer. It gave me a better understanding of delete and close. But I still have this problem that I don't know how to solve. Below is my code. I collect data from serial communication and use bar graph to display the data (which update the graph whenever new data is received). I want to be able to close the port when user closes the figure window. What is the best way to do it? The code below doesn't work...
s1 = serialport('COM10', 115200); % define COM port #
while (1)
data = read(s1,11,"uint8")
if data(1) ~= 255
disp('Data error!');
end
fig = figure();
fig.CloseRequestFcn = @(){fprintf('Fig close req called!\n'); close fig; clear s1;}
bar(x, data(2:11));
ylim([0 70]);
close fig;
end
Walter Roberson
on 8 Sep 2020
fig.CloseRequestFcn = @(){fprintf('Fig close req called!\n'); close(fig); clear s1;}
Adam Danz
on 8 Sep 2020
That's not how to write a close request function. Model it after the DeleteFcn I provided above or the closeRequestFcn provided in the documentation.
Chao
on 8 Sep 2020
Sorry, but I still don't quite get it why I need the DeleteFcn, I don't want to detect the user "delete" anything from the bar chart, simply when they close the figure window...
Walter Roberson
on 8 Sep 2020
It depends what you want to do. Do you want the special action to be invoked only when the user clicks the X to delete the entire figure? If so then that is what CloseRequestFcn can do for you. But if you want the special action to be invoked in other circumstances, such as cla() or if the user plots something else, then DeleteFcn would be the better hook.
CloseRequestFcn is not invoked if you ask to close() a figure, or any other code action that might delete a figure: it is only invoked as the UI action of the user requesting to close the figure.
Steven Lord
on 8 Sep 2020
The user doesn't delete the bar chart when they close the figure window.
MATLAB will automatically delete all the graphics objects in the figure window when the figure is closed. If some or all of those graphics objects have DeleteFcn properties that are populated, it will invoke the functions stored in those properties.
theFile = tempname;
fid = fopen(theFile, 'wt');
h = bar(1:10);
h.DeleteFcn = @(varargin) fclose(fid);
counter = 0;
while ~isempty(fopen(fid)) % the file is still open
fprintf(fid, '%d\n', counter);
counter = counter + 1;
pause(1)
end
Let MATLAB wait for a couple seconds, then close the figure (which will close the file that we opened with fopen.) Look at the contents of the file:
edit(theFile)
Close it, wait a couple seconds, and reopen it. You should see that no one has written to it since the body of the while loop stopped executing.
A note on the DeleteFcn in the example above: we're not using any of the inputs with which MATLAB calls the DeleteFcn. So we just accept as many as MATLAB passes in (with varargin) and ignore them.
Adam Danz
on 9 Sep 2020
Edited: Adam Danz
on 9 Sep 2020
"BTW, how do you even trigger the "DeleteFcn" in your example above?"
My answer explains how the DeleteFcn is triggered: "Bars can be deleted using cla(), delete(h) where h is the bar handle, or when the figure closed".
So, if you're clearing the axis to restart the bar plot, use the DeleteFcn. If you're closing the figure you can use either the DeleteFcn or the CloseRequestFcn.
Clever to use varargin for the ignored callback inputs. I usually use @(~,~)myFun(__) but varargin is more flexible.
Chao
on 9 Sep 2020
Yes, I do want the special action to be invoked only when the user clicks the X to delete/close the entire figure. So I should use CloseRequestFcn instead of DeleteFcn?
Steven Lord
on 9 Sep 2020
So if a user clears the axes (using the cla function, which will delete the bar graph but leave the figure intact) or deletes the bar graph without closing the figure in some other way (turning hold off and plotting something new in the axes, for instance) you don't want the serial port to be closed?
Adam Danz
on 9 Sep 2020
That's a good question Steven is asking.
If the answer is no (ie you don't want the port to be closed when the axis is cleared), I wonder how you're generating the bar plots. The most efficient way to update the bar plot is to plot it once and only once and then update the YData and any other properties every time data arrives. In that case, you probably want to use the DeleteFcn so the serial port is closed after the bar handle is deleted. Of course you could have a condition that tests for a valid handle and recreate the bar graph if it's deleted.
But if you're clearing the bar graph completely and regenerating it every time data arrives, that's very inefficient and slow.
Steven Lord
on 9 Sep 2020
I'd considered suggesting onCleanup as well, but in order for it to trigger when the figure was closed (as the poster said was their goal) they'd need to store it somewhere that Goes Away when the figure gets closed like the UserData property of the figure. But if you're going to do that why not use the figure property that's dedicated for this sort of thing, the CloseRequestFcn?
Chao
on 9 Sep 2020
Edited: Walter Roberson
on 9 Sep 2020
Thanks very much for everyone's help! I decided to use neither CloseRequestFcn nor DeleteFcn (I found that once you use these functions, you couldn't even close figures anymore, unless you "force" close them, which was pretty annoying), but I use the following code instead, it worked!
s1 = serialport('COM10', 115200); % define COM port #
b = bar(zeros(1, 10));
ylim([0 70]);
while (ishandle(b))
data = read(s1,11,"uint8")
if data(1) ~= 255
disp('Data error!');
end
if (ishandle(b))
set(b,'YData',data(2:11));
end
end
clear s1;
disp('Session Terminated...');
Walter Roberson
on 9 Sep 2020
They are looping inside a function; they can make the onCleanup a local variable of the function. If the function ever terminates, the cleanup will happen automatically.
Adam Danz
on 9 Sep 2020
@Chao just for future reference, when you override the close request function, you must explicitly close the figure within the callback function if want it to close.
For example,
f = figure();
f.CloseRequestFcn = @closeFigureFcn;
function closeFigureFcn(h,~)
fprintf('\n\nGoodbye!\n\n')
delete(h) % <-- delete figure
end
Also, if you have the figure handle, you can delete the figure at any time using delete(f) even if its closeRequestFcn is otherwise blocking its closure.
See Also
Categories
Find more on Creating, Deleting, and Querying Graphics Objects in Help Center and File Exchange
Tags
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!An Error Occurred
Unable to complete the action because of changes made to the page. Reload the page to see its updated state.
Select a Web Site
Choose a web site to get translated content where available and see local events and offers. Based on your location, we recommend that you select: .
You can also select a web site from the following list
How to Get Best Site Performance
Select the China site (in Chinese or English) for best site performance. Other MathWorks country sites are not optimized for visits from your location.
Americas
- América Latina (Español)
- Canada (English)
- United States (English)
Europe
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom(English)
Asia Pacific
- Australia (English)
- India (English)
- New Zealand (English)
- 中国
- 日本Japanese (日本語)
- 한국Korean (한국어)