user1207217
user1207217

Reputation: 557

Matlab event passing to parent

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

Answers (2)

user1207217
user1207217

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

Rody Oldenhuis
Rody Oldenhuis

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

Related Questions