How to prevent triggering 'SizeChangedFcn' callback too many times?

When I plot a figure and resize it manually (by clicking and dragging its window) I am triggering the SizeChangedFcn callback too many times.
In my application, it doesn't cause any time processing issues, but I was curious about how to avoid such behaviour if needed.
For my specific case, it would be enough if the event was triggered just when I release the mouse button after resize the figure window.
Here is my MWE to show how many times the event is being triggered:
clc; close all;
figure('SizeChangedFcn',@figureCallback)
function figureCallback(~,~)
disp('ok')
end

4 Comments

probably this post can help
https://de.mathworks.com/matlabcentral/answers/270022-how-to-prevent-resize-function-called-before-mouse-release
or maybe you could start/reset a timer when the resize is called and proceed only, if at least e.g. 5s are reached
Thank you @Jonas! That link indeed gave me a direction.
Since it seems to pass through an OS solution (by setting a Windows 10 option), solving the problem for me won't solve it for others on others PCs... so it doesn't worth the effort (at least for my case).
About the timer, I've tried putting a pause(2) and working with Interruptible and BusyAction but it didn't seem to work. The idea was to set Interruptible='off' and BusyAction='cancel', so that the following triggers would be automatically cancelled.
However, consulting the Interrupt Callback Execution documentation made me lose my hope of fixing this:
Certain commands that occur in the running callback cause MATLAB to process the rest of the callback queue. MATLAB determines callback interruption behavior whenever it executes one of these commands. These commands include drawnow, figure, uifigure, getframe, waitfor, and pause.
[...]
Finally, if the interrupting callback is a DeleteFcn, CloseRequestFcn, or SizeChangedFcn callback, then the interruption occurs regardless of the value of the Interruptible property.
Therefore, Interruptible and BusyAction will do nothing to SizeChangedFcn. Just in case, I've tried running the code below and got a lot of triggers:
clc; close all;
figure('Interruptible','off', 'BusyAction','cancel', 'SizeChangedFcn',@figureCallback)
function figureCallback(~,~)
disp('ok beginning')
pause(2)
disp('ok end')
end
As a final attempt, if you are desperately reading this post seeking a solution to your own problem, this other post might help. Here is an adaptation of it:
clc; close all; clear all;
figure('SizeChangedFcn',@figureCallback)
function figureCallback(~,~)
persistent CallbackRunning
if isempty(CallbackRunning) || ~CallbackRunning
CallbackRunning = true;
disp('ok beginning')
pause(2)
%%% DO YOUR STUFF HERE %%%
disp('ok end')
CallbackRunning = false;
end
end
P.S.: Note that the function is still being triggered many times though.
i was more thinking about a timer object. In the follwing example the plot data is changed after 2 seconds after stopping changing the window size
updateDelay=2;
yourTimer=timer("StartDelay",updateDelay,'ExecutionMode','singleShot');
close all;
figure()
plot(rand(5));
ax=gca;
set(yourTimer,"TimerFcn",@(~,~)writeDataToWindow(ax));
set(gcf,'SizeChangedFcn',@(~,~)figureCallback(yourTimer));
function []=writeDataToWindow(ax)
plot(ax,rand(5));
end
function figureCallback(yourTimer)
% restart timer repeatedly when window size is changed
stop(yourTimer);
start(yourTimer);
end
Thank you @Jonas! That's a pretty elegant solution.
Although the SizeChangedFcn is still being triggered multiple times, this way is much more organized.

Sign in to comment.

Answers (1)

4 Comments

Hmm I test your code on Windows and the callback is not triggered when I use the mouse to drag on bottom left corner. What callback I should assign?
close all
fig = figure('ButtonDownFcn', @resize)
function resize(FigH, EventData, AxesH)
persistent blockCalls % Reject calling this function again until it is finished
disp('resize is called'); % This line never get called
if any(blockCalls), return, end
blockCalls = true;
doResize = true;
while doResize % Repeat until the figure does not change its size anymore
siz = get(FigH, 'Position');
disp('toto')
pause(1.0); % Of course here are some real calculations
set(AxesH, 'Position', [5, 5, siz(3:4)-10]);
drawnow;
doResize = ~isequal(siz, get(FigH, 'Position'));
end
blockCalls = false; % Allow further calls again
end
set(FigH, 'ResizeFcn', {@resize, AxesH}); % Same for SizeChangedFcn
OK Thanks what leads me to the errir is this sentense in the Answer:
"One solution is to ignore the built-in resize methods and use a specific WindowsButtonDownFcn to emulate a resizing"
Thanks for the answer @Jan, but I think that the solution you came up with (using persistent variables) is similar to mine in the comments.
I have also tried using both WindowsButtonDownFcn and WindowButtonUpFcn, but I guess the clicking action (up and down) of resizing is not triggering any of those callbacks.

Sign in to comment.

Categories

Products

Release

R2018a

Asked:

on 18 Nov 2022

Commented:

on 28 Nov 2022

Community Treasure Hunt

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

Start Hunting!