How to detect the close window event for a "bar" graph

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!

Risposte (1)

Adam Danz
Adam Danz il 4 Set 2020
Modificato: Adam Danz il 4 Set 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 Commenti

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
'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')
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
Adam Danz
Adam Danz il 4 Set 2020
Modificato: Adam Danz il 7 Set 2020
I will summarize these points in my answer above to make them more visible.
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
fig.CloseRequestFcn = @(){fprintf('Fig close req called!\n'); close(fig); clear s1;}
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.
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...
BTW, how do you even trigger the "DeleteFcn" in your example above?
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.
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
Adam Danz il 9 Set 2020
Modificato: Adam Danz il 9 Set 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.
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?
CloseRequestFcn which is a propery of the figure.
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?
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.
Have you considered using onCleanup() to close the serial port?
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?
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...');
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.
@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.
Thanks very much for the information!

Accedi per commentare.

Categorie

Richiesto:

il 4 Set 2020

Commentato:

il 9 Set 2020

Community Treasure Hunt

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

Start Hunting!

Translated by