Tales of the TeenyTyper #3 – The ActionBinder

In building the TeenyTyper, I decided that I wanted  to avoid the usual window decorations (like a close button).  A special key combination of <CTRL-D> would be instead used to shut down the toy once we’d finished playing.

I’ve tried implementing  Swing’s KeyListener interface in the past, but I’ve experienced the occasional KeyListener event not firing when it should have.  Sure enough, my first attempts at using a KeyListener misbehaved as expected.  A quick trawl of StackOverflow, and I hit gold.   Seems that I’d be far better off using key bindings instead.

So, in essence, I’m binding a particular action to perform for a given Swing component every time the component catches a relevant keystroke event.  Below is the reusable library function I settled on to establish this relationship:

public static void bindKeyStrokeToAction(
                     JComponent component,
                     String keyStrokeLabel,
                     KeyStroke keyStroke,
                     AbstractAction actionToPerform) {

  InputMap inputMap = component.getInputMap(
    JComponent.WHEN_IN_FOCUSED_WINDOW
  );

  inputMap.put(
    keyStroke,
    keyStrokeLabel
  );

  component.getActionMap().put(
    keyStrokeLabel,
    actionToPerform
  );
} 

I’m not a big fan of that keystroke label requirement in the mapping. I have no need for the string itself once the mapping has been established. The string really could be anything for all I care (at least for this application).  To hide this string detail, and make the interface even easier to use, I implemented a wrapper to auto-generate a unique string mapping via Java’s UUID functionality like so:

public static void bindKeyStrokeToAction(
                     JComponent component,
                     KeyStroke keyStroke,
                     AbstractAction actionToPerform) {

  bindKeyStrokeToAction( 
    component,
    UUID.randomUUID().toString(),
    keyStroke,
    actionToPerform
  );
}

So, implementing an action that shuts the TeenyTyper down gracefully when <CTRL-D> is pressed on the editor pane is achieved with the following call:

    ActionBinder.bindKeyStrokeToAction(
        components.editor, 
        KeyStroke.getKeyStroke(
            KeyEvent.VK_D, 
            KeyEvent.CTRL_DOWN_MASK), // <CTRL-D>
        new AbstractAction() {
          private static final long serialVersionUID = 1L;

          public void actionPerformed(ActionEvent arg0) {
            System.exit(0);
          }
        }
    );

And that’s it. No more KeyListener event misfire blues for yours-truly.

Keybind your actions long and prosper.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s