简体   繁体   中英

keyPressed doesn't work unless JButton clicked first

I have created a small app that uses JButtons to increment numbers. The buttons aren't supposed to be clickable but rather be activated by keyboard (ie the numbers in the textField increase with the keyboard pushed and not by using a mouse to click the button). My issue is that when the app is first launched, the keyboard doesn't do anything until I first click one of the buttons - even though clicking the button doesn't progress anything. I have tried to make one of the buttons requestFocusInWindow() thinking that if it was already focused on, the the keys would work, but that hasn't seemed to work whether I put it in my main method or controller class. I've tried to figure out if I need to do a KeyboardFocusManager or a addFocusListener() (but I don't want something always happening if a button gains/loses focus). I've tried so many things my head is spinning, trying to add either to my main method with frame or my controller class. Below is what my current code is:

Class with Main

import javax.swing.JFrame;

public class Count {

    public static void main(String[] args) {
        CountController frame = new CountController();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(560, 150); 
        frame.setVisible(true); 
        //I've tried to add the button and requestFocusInWindow here
        //as well as tried a frame.addWindowFocusListener
    }
} // end class

Controller Class

imports ...
public class CountController extends JFrame implements KeyListener {
    private JLabel ...
    private JTextField ...
    private JButton ....
    int ...
    // no-argument constructor
    public CountController() {
        super("Title");
        setLayout(null); // position GUI components explicitly

        //set up JLabels in following manner
        label = new JLabel("some label");
        label.setBounds(47, 5, 45, 25);
        label.setHorizontalAlignment(JLabel.CENTER);
        add(label);

        //set up JTextFields in following manner
        textField = new JTextField("0");
        textField.setBounds(47, 30, 45, 25);
        textField.setHorizontalAlignment(JTextField.CENTER);
        textField.setBackground(Color.WHITE);
        textField.setEditable(false);
        add(textField);

        //set up JButtons in the following manner
        button = new JButton("some text");
        button.setBounds(15, 70, 110, 25);
        button.setBackground(Color.WHITE);
        add(button);
        button.addKeyListener(this);
        //I've tried adding requestFocusInWindow() here as well
    } // end constructor

    //begin KeyListener stuff
    @Override
    public void keyPressed(KeyEvent event){
        int keyCode = event.getKeyCode();
        switch(keyCode){
            case #: //# is ASCII #
                do some things;
                call a method();
                break;
        }
    }
    @Override
    public void keyReleased(KeyEvent event){
        button.setBackground(Color.WHITE);
    }
    @Override
    public void keyTyped(KeyEvent event){
        // nothing but this is needed for implementing KeyListener
    }

    //List of methods that are called from switch
        ...

    //I've tried to add a public void initialize(){}

}//end CountController class

I would appreciate any input on getting this to work so that I don't have to first click a button before my keys work. Thanks!

In order for the listener to trigger an event, the component it is registered to must first BE focused AND have focus. Use the key bindings API instead.

The following uses JComponent.WHEN_IN_FOCUSED_WINDOW to define the context under which the key events will be generated. In this configuration, it won't matter what has focus, the events will still be generated, so long as the window is currently focused

import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.KeyStroke;

public class Count {

  public static void main(String[] args) {
    CountController frame = new CountController();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(560, 150);
    frame.setVisible(true);
    //I've tried to add the button and requestFocusInWindow here
    //as well as tried a frame.addWindowFocusListener
  }

  public static class CountController extends JFrame {

    // no-argument constructor
    public CountController() {
      super("Title");
      setLayout(new GridBagLayout());
      GridBagConstraints gbc = new GridBagConstraints();
      gbc.gridwidth = GridBagConstraints.REMAINDER;

      //set up JLabels in following manner
      JLabel label = new JLabel("some label");
      label.setHorizontalAlignment(JLabel.CENTER);
      add(label, gbc);

      //set up JTextFields in following manner
      JTextField textField = new JTextField("0", 20);
      textField.setHorizontalAlignment(JTextField.CENTER);
      textField.setBackground(Color.WHITE);
      textField.setEditable(false);
      add(textField, gbc);

      //set up JButtons in the following manner
      JButton button = new JButton("some text");
      add(button, gbc);

      InputMap im = button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
      ActionMap am = button.getActionMap();

      im.put(KeyStroke.getKeyStroke(KeyEvent.VK_3, KeyEvent.SHIFT_DOWN_MASK), "Pressed.#");
      am.put("Pressed.#", new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent e) {
          textField.setText(textField.getText() + "#");
        }
      });

    } // end constructor

  }//end CountController class
} // end class

Although I'd register the bindings against the parent container and not the buttons, but that's just me.

And, reasons for not using null layouts ... this is what your original code looks like on my PC

不使用空布局的原因

Although it's not quite clear to me what your code should accomplish, your problem is that you addKeyListener(this) to the button but your button doesn't have the focus and the key doesn't do anything when pressed. Try adding the KeyListener() to some other GUI component, like the textfield for example, since it's the first component and has the focus on start(from the code you've provided), and see if it works.

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