How to disable uicontrol 'mouseless' interaction

2 views (last 30 days)
Jonas
Jonas on 21 Apr 2022
Edited: Jonas on 3 May 2022
Dear community,
at the moment I'm creating a gui using normal figures and uicontrol elements. One side is a plotting window in which the user can interact using key press and mouse klick, the other half of the figure are some additional settings like visibility of certain elements etc using checkboxes for example
If I click on a checkbox and afterwards i press 'space' in the plotting window which is processed by ''WindowButtonDownFcn''.
My Problem is, that at the same time the 'space' changes the checkbox value
Similar things happen if I changed the value of a popupmenu and I want to navigate in the plotting window using the arrow keys.
The Callbacks of the 'WindowButtonDownFcn' are processed correctly, but at the same time i change the value of the uicontrol
How can I remove this behavior such that the user can not interact with uicontrol elements using keyboard button press (and also navigating using TAB once an uicontrol element was used) but only mouse clicks
I am using Win10 and Matlab 2021a
here a short "working" example
close all;
fig=figure;
% create plots and disable interactivity
s=subplot(1,2,1);
p=plot(rand(1,1000));
axtoolbar(s,'Visible','off');
disableDefaultInteractivity(s);
%% create buttons and set window key press function
pressedButton= uicontrol(fig,'Style','text');
pressedButton.Units='normalized';
pressedButton.Position = [0.7 0.7 0.2 0.04];
pressedButton.String = 'no key pressed yet';
fig.WindowKeyPressFcn=@(~,ev) set(pressedButton,'String',ev.Key);
colorPopup = uicontrol(fig,'Style','popupmenu');
colorPopup.Units='normalized';
colorPopup.Position = [0.7 0.5 0.2 0.04];
colorPopup.String = {'r','b','k','c'};
colorPopup.Value = 1;
colorPopup.Callback =@(~,~) set(p,'Color',colorPopup.String{colorPopup.Value});
visibilityCheckbox = uicontrol(fig,'Style','checkbox');
visibilityCheckbox.Units='normalized';
visibilityCheckbox.Position = [0.7 0.6 0.2 0.04];
visibilityCheckbox.String='Visibility';
visibilityCheckbox.Value=1;
visibilityCheckbox.Callback=@(~,~) set(p,'Visible',visibilityCheckbox.Value);
best regards
Jonas

Accepted Answer

Jan
Jan on 25 Apr 2022
If you click on an uicontrol element, it gets the focus. Then following keyboard events are caught be the keyboard handling of the uicontrol. A solution is to give the focus back to the figure or the axes in the callback of the uicontrol. This should work by figure(fighandle) according to the documentation, but this was not successful at least for Matlab 6.5 to 2018b (the newest version I have).
Workarounds:
  • Insert code in the callbacks, which sets the "Enable" property of the uicontrol to 'off' temporarily:
function checkBoxCallback(ObjH, EventData)
set(ObjH, 'Enable', 'off');
drawnow;
set(ObjH, 'Enable', 'on');
pause(0.02); % Voodoo!
end
WindowAPI(figHandle, 'setFocus')
  10 Comments
Jonas
Jonas on 3 May 2022
and another comment: i don't know why, but we can't set the Focusable attribute, if the UIControl element is Invisible and it seems to reset it's proeprty when made visible. for that reason i used @Jan's solution with the Release callback
Jan included an HList Object, but there was no such object available and i was too dumb to get the Matlab handle from the java jPopH handle
uiButtons=findall(fig,'type','uicontrol');
for count=1:numel(uiButtons)
if uiButtons(count).Visible
jobj=findjobj(uiButtons(count));
jobj.MouseReleasedCallback=@(H, E) KillFocus(uiButtons(count));
end
end
function KillFocus(obj)
set(obj, 'Enable', 'off');
drawnow;
set(obj, 'Enable', 'on');
end

Sign in to comment.

More Answers (1)

Jonas
Jonas on 3 May 2022
for better visiblity here the last state of our discussion. thanks @Jan!
long question, short answer: the java objects have a focusable attribute which can be set to 0 and solve all the problems, no need for any listeners or callbacks. I just added the following after creation of all uicontrol elements
objs=findall(fig,'type','uicontrol'); % get the uicontrol elements
for nr=1:numel(objs)
jobj=findjobj(objs(nr),'persist'); % findjobj can hadnle only one obj at a time, the persistent argument speeds up the finding process of jobj
jobj.Focusable=false;
end
% instead of the for loop we could also use
% arrayfun(@(in) set(findjobj(in,'persist'),'Focusable',false),objs)
thanks again to @Jan for his help!
  1 Comment
Jonas
Jonas on 3 May 2022
and another comment: i don't know why, but we can't set the Focusable attribute, if the UIControl element is Invisible and it seems to reset it's proeprty when made visible. for that reason i used @Jan's solution with the Release callback
uiButtons=findall(fig,'type','uicontrol');
for count=1:numel(uiButtons)
if uiButtons(count).Visible
jobj=findjobj(uiButtons(count));
jobj.MouseReleasedCallback=@(H, E) KillFocus(uiButtons(count));
end
end
function KillFocus(obj)
set(obj, 'Enable', 'off');
drawnow;
set(obj, 'Enable', 'on');
end

Sign in to comment.

Products


Release

R2021a

Community Treasure Hunt

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

Start Hunting!

Translated by