Continuously pressing GUI slider arrow causes hanging

The solution proposed doen't woks for me.
I've created a GUI with a slider control that update a graph. When I make distinct individual clicks of the slider arrows, it works fine, even if it takes some seconds to update the figure. When I hold the arrow buttons down continuously the figure is updated to the final value of the slider, however, matlab is still busy processing the long function repeatedly.
What appears to be happening is that by holding down the arrow, the slider callback and the corresponding slow function gets launched many times repeatedly. The BusyAction and the interrupting callback don't apply to the slow function that has already been lunched. Ultimately, it is accoumulated in the queue and keep the program busy.
Is there some way that the continuous-arrow-press condition is suppressed? Or might there be some way to force the GUI to wait until all other graphics and uicontrol data in the figure are refreshed before re-executing the callback?
Here there is part of the code to better understand the problem
S.Slider = uicontrol('style','slider', 'callback', @Slider_A); %generate the slider
function Slider_A(My_Slider, ~, ~)
S = guidata(My_Slider); % Get S struct from the figure
S.Value = get(My_Slider, 'Value');
% w = waitforbuttonpress; %this would work if exist waitforbuttonRELEASE
update(S); %slow function and plotting
guidata(My_Slider, S); % Store modified S in figure
end

 Accepted Answer

Rik
Rik on 20 Apr 2022
Edited: Rik on 22 Apr 2022
I would suggest setting a flag (and storing it in the guidata struct). That way you can immediately exit the function if it is already running.
The function below implements such a flag. This function also checks whether the Value has changed since the last call, in which case it will run another time.
Since an empty array is equivalent to false, you don't even need to initialize the UserData property.
function Slider_A(My_Slider, ~)
S = guidata(My_Slider); % Get S struct from the figure
% Exit this function call.
if get(My_Slider,'UserData'),return,end
% Set the flag to exit the function call if it is called before it exits.
set(My_Slider,'UserData',true);drawnow;
while true
S=guidata(My_slider); % Reload S in case it was changed in the updater.
S.Value = get(My_Slider, 'Value');
update(S);
drawnow; % Trigger the processing of callbacks and graphics object interactions
if isequal(get(My_Slider, 'Value'),S.Value)
% Value has not changed, break the loop and exit the function.
break
end
% The value has changed, rerun the updater with the new value.
end
set(My_Slider,'UserData',false);
guidata(My_slider,S)
end

8 Comments

I am trying to figure out how it should be. I am also trying with a timer. I don't know how to relate the timer or the flag with the slider being pressed continuously. Any hint?
See if my edit works out for you. As long as continuous pressing results in a stream of calls to the callback function, this should work. I have not tested it myself, so there might be some bugs.
I found a couple of bugs. One in about get and set, that have too many inputs. I have replaced them with:
get(My_Slider,'UserData')
set(My_Slider,'UserData',false);
Is it correct?
The other is just about capital letters.
However the problem is not fixed.
I don't understand why you use 'UserData'. It is always empty or false inside the callback.
When you use isequal, it will be always true because everytime that the slider change value (due to one long press or multiple short press on the arrows), the function Slider_A start again and it stores the new value inside S.Value. I am right?
The problem is that the function update has been triggered too many time, and it has been added to the queue.
I need to lunch update(S) just once, possibily when de mouse button is released.
Apparently I needed one more coffee when I wrote that. I forgot to set the flag to true. See my edits.
The point of using the UserData is that it can be updated without affecting the guidata struct.
The isequal test will not always return true. If the slider value changes while update is running, the drawnow call will make sure this change is reflected in My_Slider.Value, but there is no way S.Value could have been changed (unless you are using bad code design).
Thanks Rik. The code is working quite well. Icurious because while the arrow is held down for a long time, the graph updates (once every cycle of update(S)). When you leave the arrow, the graph updates one last time and the queue is clean again. That's even better of what I was looking for.
That is indeed the intended effect.
How this works is that the first time the value changes a callback is launched. Every subsequent callback is ignored, until this initial callback exits again. Just before the callback exits, it will check if the current value matches the value used for the last call to update. If it doesn't, it repeats the loop.
Glad to be of help.
I played with your code and I found that I can obtain the same results with a simpler version:
function Slider_A(My_Slider, ~)
% Exit this function call.
if get(My_Slider,'UserData'),return,end
% Set the flag to exit the function call if it is called before it exits.
set(My_Slider,'UserData',true);drawnow;
S = guidata(My_Slider); % Get S struct from the figure
S.Value = get(My_Slider, 'Value');
S.Value = round(S.Value,14) %sometimes the value change by 1e-15
update(S);
guidata(My_slider,S)
set(My_Slider,'UserData',false);
end
Again, the figure is updated continuosly, but when the slider is released the queue is empty. Apparently the key part is return. At the first launch of the callback the flag is set to true. Every subsequent callback is ignored while update(S) is busy.
I realized that sometimes Value changes from the expected number becuse update(S) is very sensible and even a change of +-1e-15 make a difference. With round that problem is fixed (even if I don't understand where the problem comes from).
That is the difference between the two versions: mine will run one last time, and yours will not. Other than that there isn't a fundamental difference between the two. But glad you have something you like.

Sign in to comment.

More Answers (0)

Categories

Find more on Creating, Deleting, and Querying Graphics Objects in Help Center and File Exchange

Products

Release

R2021a

Tags

Asked:

on 19 Apr 2022

Commented:

Rik
on 29 Apr 2022

Community Treasure Hunt

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

Start Hunting!