Featured Post

Applying Email Validation to a JavaFX TextField Using Binding

This example uses the same controller as in a previous post but adds a use case to support email validation.  A Commons Validator object is ...

Thursday, October 15, 2015

The F1 Help Key with Java FX

This post shows how to implement a modifier-less F1 key help command.  I set up several standard modifier accelerators in Scene Builder, but use Java code in the @FXML initialize() method to hookup a help function to the F1 key.

F1 Key Binding Presented as Standard Accelerator

Keyboard shortcuts in JavaFX are implemented using a KeyCombination.  For example, pressing the Control key and the W key at the same time can execute a close command.  In Scene Builder, you can configure this type of shortcut using an accelerator.  The accelerator is one or more modifiers (Control, Shift, Alt, Command) plus another key of your choosing, say "W", "S", or "N".

Shortcut Accelerators

This screenshot of a PC app shows a set of accelerators applied to using the SHORTCUT modifier which bridges the difference between different platforms.  Note that the New, Save and Close commands are bound to the Control-N, Control-S, and Control-W KeyCombinations.

PC Version of the App's Shortcuts
SHORTCUT, rather than an explicit CONTROL or COMMAND modifier, lets me run the same app on the Mac with its traditional bindings in effect.

Mac Using Command Shortcuts
These types of key bindings can be set up entirely in Scene Builder.  See the following Properties pane which is from a selected MenuItem.  Note that there is an onAction function registered already for normal menuing operations.  That function, is also called when the Control-W accelerator is used.

Scene Builder Defining an Accelerator
The F1 Key

Although there is a "No" option in Scene Builder 2.0's ChoiceBox, I haven't been able to get a direct key binding working.  That is, I want to press the F1 key without a modifier to execute a showHelp() function.  I also want the F1 key to display a visual cue in the MenuItem itself as is done with the other accelerators.  In Scene Builder, my selection of No/F1 doesn't seem to be saved.  So, I define this in code.

First, I give my MenuItem an fx:id and add it as an @FXML member in the controller class.

    @FXML
    MenuItem miHelp;

Next, I add this KeyCombination to the @FXML initialize() method of the JavaFX controller.

     miHelp.setAccelerator( KeyCombination.keyCombination("F1") );

Finally, I place an EventFilter on each and every Scene in the app.  In this particular app, I'm using a common view base class so I'm in a leveraged position that allows me to add this in a single location.  My help isn't context-sensitive, so executing the same help command for all areas is fine.

        stage.getScene().addEventFilter(KeyEvent.KEY_PRESSED, (evt) -> {
         if( evt.getCode() == KeyCode.F1 ) {
          helpDelegate.showHelp();
         }
        });

helpDelegate() is a Guice-injected object that executes the help function.  This help function is also called from a standard MenuItem action handler for when the Help > Help item is selected.

Just adding the EventFilter to the Scene gives you a Scene-wide ability to call a global command like help.  Needing the define the modifier-less KeyCombination outside of Scene Builder is unfortunate, but important so that the UI is consistent and the users can learn about the shortcuts by using the app itself.

2 comments:

  1. No need to write code for that.

    Just define the accelerator in SceneBuilder with a modifier, e.g. 'shortcut_down'.

    Then open the fxml file in an editor, search for the accelerator and set "DOWN" to "UP", as in:

    KeyCodeCombination code="F1" alt="UP" control="UP" meta="UP" shift="UP" shortcut="UP"

    Save, re-open the scene in SceneBuilder, and it will display the shortcut correctly as "F1".

    ReplyDelete
    Replies
    1. Good tip, although I'm still looking for Scene Builder to do this so that I don't have to hand-edit the FXML (or write extra code).

      Delete