javaswingfocusmnemonics

JCheckBox mnemonic without transferring focus


As per title, is it possible to change a JCheckBox selection state using a mnemonic key without transferring the focus to the component?

Current behavior as per GIF.
The wanted behavior would be the focus remaining on the "Type" text field.

enter image description here


Solution

  • Given that the mnemonic is registered as a key binding, in the scope of

    JComponent.WHEN_IN_FOCUSED_WINDOW
    

    See BasicButtonListener#updateMnemonicBinding


    We can simply override the key binding actions with our own ones.

    private class MnemonicCheckBox : JCheckBox(...) {
      override fun setMnemonic(mnemonic: Int) {
        super.setMnemonic(mnemonic)
    
        if (mnemonic != 0) {
          overrideMnemonicActions()
        }
      }
    
      private fun overrideMnemonicActions() {
        val mnemonicMask = UIUtilities.getSystemMnemonicKeyMask()
        val altGraphDownMask = InputEvent.ALT_GRAPH_DOWN_MASK
    
        getInputMap(WHEN_IN_FOCUSED_WINDOW).apply {
          // Pressed
          put(KeyStroke.getKeyStroke(mnemonic, mnemonicMask), "mnemonicPressed")
          put(KeyStroke.getKeyStroke(mnemonic, mnemonicMask or altGraphDownMask), "mnemonicPressed")
    
          // Released
          put(KeyStroke.getKeyStroke(mnemonic, mnemonicMask, true), "mnemonicReleased")
          put(KeyStroke.getKeyStroke(mnemonic, mnemonicMask or altGraphDownMask, true), "mnemonicReleased")
        }
    
        actionMap.apply {
          put("mnemonicPressed", object : AbstractAction() {
            override fun actionPerformed(event: ActionEvent) {
              model.isArmed = true
              model.isPressed = true
            }
          })
          put("mnemonicReleased", object : AbstractAction() {
            override fun actionPerformed(event: ActionEvent) {
              model.isPressed = false
              model.isArmed = false
            }
          })
        }
      }
    }
    

    To maintain the semantic expressed in BasicButtonListener.Actions, we have overridden both the pressed and released actions to change the ButtonModel state.

    Example:

    enter image description here