Reputation: 557
I've a user interface I've designed that I wish to make certain keypresses initiate some action in the user interface. I've tried defining a function for the keypressfcn callback of the figure, but if any other UI element is the active element the keypressfcn for that element is invoked (which is empty). How can I go about capturing key presses for the entire figure without assigning the same keypressfcn function handle to all child elements within the UI?
Upvotes: 3
Views: 907
Reputation: 557
I found the WindowKeyPressFcn callback does what I want. This is a property of the figure, but beware, it does exactly what it says - it captures keypresses while this is the active figure (regardless of what the active element is). Consider if you really want this, e.g when an edit element has focus, the WindowKeyPressFcn will fire as it is typed into.
Upvotes: 3
Reputation: 38032
I'm afraid you'll have to define each and every uicontrol
's KeyPressFcn
. Think about it: if you designed Matlab, how would you simultaneously keep the option open for users to assign different keypress-functions for different uicontrols
, while also allowing for them to use only one master function for all uicontrols
?
Each new uicontrol
will have to know that you want to do that, which is equal to assigning it's KeyPressFcn
.
The easiest way to do this is to write some generic function like
function KeyPressFcnFwd(obj,event)
prn = get(obj, 'parent')
fcn = get(prn, 'KeyPressFcn');
fcn(prn,event);
end
and then define uicontrols like this:
button = uicontrol(...
'style', 'pushbutton', ...
...
'KeyPressFcn', @KeyPressFcnFwd);
Doing it like this will make key presses on some radio button call its parent's KeyPressFcn
, which is a radio group, which in turn forwards the call to its parent's KeyPressFcn
, which is a uipanel, which in turn forwards the calls to its parent's KeyPressFcn
, which is finally your figure's KeyPressFcn
.
In short: no matter how deeply nested your uicontrol
is, the call will always be forwarded all the way to the figure.
If you define this function as a nested function in the function where the "main" figure is created, you can do it all a bit more efficiently:
function main %# toplevel function
...
mainFig = figure(...) %# your main figure
...
%# nested function
function KeyPressFcnFwd(obj,event)
fcn = get(mainFig, 'KeyPressFcn');
fcn(mainFig,event);
end
...
%# Function to build the GUI
%# can be a subfunction, nested function or external function
populateMainWin(mainFig, @KeyPressFcnFwd);
...
end
so that you don't have the overhead of calling the whole tree of KeyPressFcn
's.
In situations where there's potentially a lot of boilerplate (and this is an excellent candidate), I usually define some shorthands like
function handle = uibutton(parent, text, varargin)
handle = uicontrol(...
'parent', parent, ...
'style' , 'pushbutton', ...
'units' , 'normalized', ...
'string', text, ...
'KeyPressFcn', @KeyPressFcnFwd, ...
varargin{:});
end
so that my code remains readable.
Upvotes: 2