How do I ignore double clicks in my GUI buttons?

18 views (last 30 days)
I have created a GUI containing a button that performs a callback. Sometimes, users accidentally double-click the button, causing the callback to fire twice. How do I stop that?

Accepted Answer

MathWorks Support Team
MathWorks Support Team on 5 Mar 2021
Edited: MathWorks Support Team on 5 Mar 2021
MATLAB UI buttons do not offer support for double-clicking. However, you can implement a mechanism that ignores the second click.
As an example, here is a function that implements such a mechanism. This function makes use of a persistent variable, "check", to count the number of recent clicks. If there are no recent clicks, then the single-click action is executed. However, if there are recent clicks, new clicks are ignored for a short period of time.
function pushbutton1_Callback(hObject, eventdata, handles)
persistent check % Shared with all calls of pushbutton1_Callback.
delay = 0.5; % Delay in seconds.
% Count number of clicks. If there are no recent clicks, execute the single
% click action. If there is a recent click, ignore new clicks.
if isempty(check)
check = 1;
disp('Single click action')
else
check = [];
pause(delay)
end
end
The trick here is to define "check" as a persistent variable, which means that its value doesn't get cleared after the function has stopped executing, but it persists through all calls to this function. This makes it possible to track the number of (recent) calls to this function, effectively identifying double clicks.
You can find more examples on how persistent variables work in MATLAB in the following documentation page:
  1 Comment
Allen
Allen on 21 Feb 2018
I have used the method provided by the MathWorks Support Team and still have the code for my pushbutton GUI execute each time on a multi-click by the user. However, a slight edit to their code does the trick. See example below:
function pushbutton1_Callback(hObject, eventdata, handles)
persistent check % Shared with all calls of pushbutton1_Callback.
% Count number of clicks. If there are no recent clicks, execute the single
% click action. If there is a recent click, ignore new clicks.
if isempty(check)
check = 1;
disp('Single click action')
else
% Ends Callback execution if pushbutton is clicked again before
% Callback has completed.
return
end
% -----Callback function code----- %
% Resets the 'check' variable for additional use of the Callback function
check = [];
end

Sign in to comment.

More Answers (2)

Dave!
Dave! on 11 Dec 2018
Edited: Dave! on 17 Dec 2018
I appreciate your answers. I attempted to solve this problem with an onCleanup object so that the process of allowing the callback to be executed again would always run. That way, it would "unlock" the callback even if it errored out or the user issued a Ctrl+C command to exit it. It still uses a persistent variable, but this one is an object that extends handle rather than a primitive.
Revised: I couldn't quite get what I posted here on 11 Dec 2018 to work with the onCleanup call to another function with a persistent variable in it. Basically, the chain for onCleanup buried the call to the function within several layers of additional workspaces and it did not have access to the external function's workspace anymore when trying to call delete.
I ended up making a Lock classdef that contained a single boolean property isLocked. Since this object extended handle, it would have access to its unlock function from inside the onCleanup delete function workspace, not matter how deep it was.
New Code:+
function pushbutton1_Callback(hObject, eventdata, handles)
persistent callbackLock;
if isempty(lock)
callbackLock = Lock();
end
if callbackLock.isLocked()
return;
end
% Lock the callback by setting the persistent variable inside of
% the Lock() class to true.
callbackLock.lock();
% Upon cleaning up this pushbutton1_Callback() function, unlock
% the callback lock so that this function can execute next time.
% Doing it with onCleanup ensures that this will unlock the callback
% even if the original callback fails or is Ctrl+C'ed
c = onCleanup(@(x)unlock(callbackLock));
%%% Your callback stuff goes here %%%
end
In a separate .m file:
classdef Lock < handle
properties (SetAccess = private)
% Is this lock locked? Since this is not publicly settable,
% I did not provide a get function
isLocked
end
methods
function obj = Lock()
obj.isLocked = false; %initialize as unlocked
end
function lock(obj)
obj.isLocked = true;
end
function unlock(obj)
obj.isLocked = false;
end
end
end
Happy coding!
  1 Comment
Bereketab Gulai
Bereketab Gulai on 3 Jul 2020
I tried this solution using struct() and works as shown:
% Button pushed function: ItemList
function ItemListButtonButtonPushed(app, event)
persistent callbackLock;
try
if isempty(callbackLock)
callbackLock = struct("isLocked", false);
end
if callbackLock.isLocked
return;
end
callbackLock.isLocked = true;
openWindow(app.windowManager, ItemList, app);
unlock();
catch x
unlock();
Utility.errorCallback(app, x);
end
function unlock()
callbackLock.isLocked = false;
end
end
But found Allen's solution simpler...

Sign in to comment.


Bereketab Gulai
Bereketab Gulai on 21 May 2020
Edited: Bereketab Gulai on 3 Jul 2020
Here are alternatives button.
Update: MATLAB Support Team's solution did not resolve the issue of using the button again, which was solved by Allen.
% Button pushed function: ItemList
function ItemListButtonButtonPushed(app, event)
persistent check; % Prevent double click
try
if isempty(check)
check = 1;
openWindow(app.windowManager, ItemList, app);
else
return
end
check = [];
catch x
check = [];
Utility.errorCallback(app, x);
end
end
%%%%%%%%%% Alternative with Singleton
% Button pushed function: CreateItemButton
function CreateItemButtonButtonPushed(app, event)
% Singleton
% If it is open bring to front...
persistent createItemApp;
try
if isempty(createItemApp) || not(isvalid(createItemApp))
pause(0.5) % This was taken from the Answer of this page, it works...
if app.openedAppsList.isKey('createItemApp')
createItemApp = app.openedAppsList('createItemApp');
if isvalid(createItemApp)
Utility.bringToFront(createItemApp.UIFigure);
else
createItemApp = CreateItem();
app.openedAppsList('createItemApp') = createItemApp;
pause(0.5)
openWindow(app.windowManager, createItemApp, app);
end
else
createItemApp = CreateItem();
app.openedAppsList('createItemApp') = createItemApp;
openWindow(app.windowManager, createItemApp, app);
end
else
Utility.bringToFront(createItemApp.UIFigure);
end
catch x
Utility.errorCallback(app, x);
end
end

Products


Release

R2016b

Community Treasure Hunt

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

Start Hunting!

Translated by