简体   繁体   中英

Need class to facilitate key binding

With help from SO and @kleopatra, I got the code immediately below to assign Ctrl-Shift-U to a JButton . (I used CAPS where I shouldn't to clearly show ME what must match.)

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import static java.awt.event.InputEvent.CTRL_DOWN_MASK;
import static java.awt.event.InputEvent.SHIFT_DOWN_MASK;
import static java.awt.event.KeyEvent.VK_U;
import javax.swing.*;
import static javax.swing.KeyStroke.getKeyStroke;

public class FirstTry {
  private static JButton MYACTIONBUTTON;
  private static JFrame frame;
  private static JPanel panel;

  public FirstTry(){
    Action MYACTION = new AbstractAction(){
      @Override
      public void actionPerformed(ActionEvent e){
          JOptionPane.showMessageDialog(null,"do this");
      }};

    MYACTIONBUTTON = new JButton(MYACTION);
    MYACTIONBUTTON.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
                          .put(getKeyStroke(VK_U, CTRL_DOWN_MASK | SHIFT_DOWN_MASK),
                                      "MAKE_THESE_MATCH"); 
    MYACTIONBUTTON.getActionMap().put("MAKE_THESE_MATCH", MYACTION);

    frame = new JFrame();
    panel = new JPanel();
    panel.add(MYACTIONBUTTON);
    frame.add(panel);
    frame.setVisible(true);
    frame.pack();
}

public static void main(String[] args) {
  new FirstTry();
}

That's a lot to go through next time I want to make a similar key binding, so I figured it should be possible to extrapolate the logic to form an abstract class that would painlessly enable assigning keystrokes (eg, Ctrl-X ) to actions (eg, "Ctrl-X was pressed", as shown) via a statement such as:

button = new KeyBoundButton("WHATEVER", VK_X, CTRL_DOWN_MASK) 
{
  @Override
  public void actionPerformed(ActionEvent e)
  {
    JOptionPane.showMessageDialog(null,"Ctrl-X was pressed!");
  }
};

I've worked all (half-)day on this and am getting nowhere. I have 3 classes: main, UI, and KeyBoundButton. I confess I'm in over my head.

public class NewMain {

  static UI ui;

  public static void main(String[] args) 
  {
    java.awt.EventQueue.invokeLater(new Runnable() 
    {
      @Override
      public void run() 
      {
        ui = new UI();
      }
    }); 
  }
}

UI:

import java.awt.event.ActionEvent;
import static java.awt.event.InputEvent.CTRL_DOWN_MASK;
import static java.awt.event.KeyEvent.VK_X;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import static javax.swing.WindowConstants.DISPOSE_ON_CLOSE;

public class UI {

  static JFrame frame;
  static JPanel panel;
  static KeyBoundButton button;

  UI(){
    frame = new JFrame();
    panel = new JPanel();

    button = new KeyBoundButton("WHATEVER", VK_X, CTRL_DOWN_MASK) 
    {
      @Override
      public void actionPerformed(ActionEvent e)
      {
        JOptionPane.showMessageDialog(null,"Ctrl-X was pressed!");
      }
    };

    panel.add(button);
    frame.add(panel);
    frame.setVisible(true);
    frame.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
    frame.pack();
  }
}

KeyBoundButton:

import java.awt.event.ActionEvent;
import javax.swing.*;
import static javax.swing.KeyStroke.getKeyStroke;

public abstract class KeyBoundButton extends JButton{

  public abstract void actionPerformed(ActionEvent e);

  public KeyBoundButton(String actionMapKey, int key, int mask)
  {
    Action myAction = new AbstractAction()
    {
      @Override
      public void actionPerformed(ActionEvent e)
      { // to be overridden   
      }
    };    

     new JButton(myAction);

    getInputMap(WHEN_IN_FOCUSED_WINDOW)
                  .put(getKeyStroke(key, mask),actionMapKey);
    getActionMap().put(                        actionMapKey, myAction);
  }
}

Am I at all close in making this class to enable easy keybinding as shown above (and below)? Or is it just so much wishful thinking with not enough knowledge of key bindings among other things?

button = new KeyBoundButton("WHATEVER", VK_X, CTRL_DOWN_MASK) 
{
  @Override
  public void actionPerformed(ActionEvent e)
  {
    JOptionPane.showMessageDialog(null,"Ctrl-X was pressed!");
  }
};

You don't need new JButton(myAction); in side your KeyBoundButton , instead use setAction(myAction)

The creation of the second button has no relation to anything, in fact, immediately after you call new JButton(myAction) , the object becomes eligible for garbage collection

I wrote a utility class a while back which does something similar, but means I don't need to create "custom" classes for each one I want to use, so I can simply pass it a Component , name, KeyStroke and Action (and optional focus levl), this has made life much simpler

@MadProgrammer got me started; here's what DOES work. Changes to original code are marked with /////////////// . (I'm not sure why the original line public abstract void actionPerformed(ActionEvent e) didn't work.... Looks good.[?])

import java.awt.event.ActionEvent;
import javax.swing.*;
import static javax.swing.KeyStroke.getKeyStroke;

public abstract class KeyBoundButton extends JButton{

  public abstract void doThis(ActionEvent e); //////////////////////

  public KeyBoundButton(String actionMapKey, int key, int mask)
  {
    Action myAction = new AbstractAction()
    {

      @Override
      public void actionPerformed(ActionEvent e)
      {
        doThis(e); ///////////////////////////
      }
    };    

    setAction(myAction); //////////////////////////////

    getInputMap(WHEN_IN_FOCUSED_WINDOW)
                  .put(getKeyStroke(key, mask),actionMapKey);
    getActionMap().put(                        actionMapKey, myAction);
  }
}

My original intent was (as Mad also suggests) to make this work for ANY component within reason; on to that now. I'll probably be back for more help.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM