如何接受键盘输入以及来自 JButtons 的输入?

How to accept keyboard input alongside input from JButtons?

我创建了一个计算器来帮助我练习 GUI 创建,因为我是新手。到目前为止它工作得很好。用户单击他们想要的相应 number/operation 的按钮。但是我想添加另一个功能,允许用户使用他们的键盘作为可选的输入源。通过查看 KeyListener 示例,这似乎很有帮助......但我无法想出一个直接的方法来使用它来实现我的想法。

public class Calculator extends JFrame {

private ArrayList<JButton> numbers;   // holds numerical buttons
private ArrayList<JButton> operations; // holds math operation buttons
private ArrayList<JButton> aux;      // holds equals, clear and delete buttons

private JTextField answerField;   // text field which displays current operands/answer

// panels for numerical,  math operation and auxillary buttons
private JPanel numberPanel, functionPanel, answerPanel;

private double op1, op2;  // numerical value of each operand
private String op1Str, op2Str; // current String value of each operand
private String operation;  // current math operation

// true if value is set, false if not
private boolean op1HasValue, op2HasValue, operationHasValue;

private String answer;   // holds current equation

public Calculator()
{
    super("Java Calculator");
    setLayout(new GridLayout(1, 3));

    op1HasValue = op2HasValue = operationHasValue = false;
    answer = "";
    op1Str = "";
    op2Str = "";

    //create panels
    numberPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
    functionPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
    answerPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));

    //add number buttons to panel
    numbers = new ArrayList<>();
    for(int i = 0; i < 10; i++)
    {
        numbers.add(new JButton("" + i));
        numberPanel.add(numbers.get(i));
    }
    // also add decimal point button
    numbers.add(new JButton("."));
    numberPanel.add(numbers.get(10));

    // add function buttons to panel
    operations = new ArrayList<>();
    operations.add(new JButton("+"));
    operations.add(new JButton("-"));
    operations.add(new JButton("*"));
    operations.add(new JButton("/"));

    for(JButton button: operations)    
        functionPanel.add(button);


    // add auxillary buttons to panel
    aux = new ArrayList<>();
    aux.add(new JButton("\u21D0"));
    aux.add(new JButton("Clr"));
    aux.add(new JButton("="));

    for(JButton button: aux)    
        functionPanel.add(button);


    // add text field to panel
    answerField = new JTextField(15);
    answerField.setEditable(false);
    answerPanel.add(answerField);

    add(numberPanel);
    add(functionPanel);
    add(answerPanel);

    // add button listeners
    myHandler handler = new myHandler();

    for(JButton button: numbers)
        button.addActionListener(handler);

    for(JButton button: operations)
        button.addActionListener(handler);

    for(JButton button: aux)
        button.addActionListener(handler);

}

private class myHandler implements ActionListener
{
    public void actionPerformed(ActionEvent event)
    {
        if((event.getActionCommand()).equals("Clr"))
        {
            op1HasValue = op2HasValue = operationHasValue = false;
            op1Str = "";
            op2Str = "";
            operation = "";
            answer = "";
            answerField.setText("");
        }
        else if((event.getActionCommand()).equals("\u21D0"))
        {
            if(!operationHasValue)
            {
                if(!op1Str.isEmpty())
                {
                    op1Str = op1Str.substring(0, op1Str.length() - 1);
                    answer = answer.substring(0, answer.length() - 1);
                    if(op1Str.isEmpty())
                        op1HasValue = false;
                    answerField.setText(answer);
                }
            }
            else if(operationHasValue && !op2HasValue)
            {
                operation = "";
                operationHasValue = false;
                answer = answer.substring(0, answer.length() - 3);
                answerField.setText(answer);
            }
            else
            {
                op2Str = op2Str.substring(0, op2Str.length() - 1);
                answer = answer.substring(0, answer.length() - 1);
                    if(op2Str.isEmpty())
                        op2HasValue = false;
                answerField.setText(answer);
            }
        }  // wait for integer input event, add integer to operand #1
        else if((!op1HasValue || !operationHasValue) && (numbers.contains((JButton)event.getSource())))
        {
            answer = answer + event.getActionCommand();
            answerField.setText(answer);
            op1Str = op1Str + event.getActionCommand();
            op1HasValue = true;
        }   // wait for operation input event, save operand #1
        else if(!operationHasValue && op1HasValue && operations.contains((JButton)event.getSource()))
        {
            op1 = Double.parseDouble(op1Str);
            answerField.setText(answer + " " + event.getActionCommand() + " ");
            answer = answer + " " + event.getActionCommand() + " ";
            operation = event.getActionCommand();
            operationHasValue = true;
        }   // wait for integer input event, add integer to operand #2
        else if(operationHasValue && numbers.contains((JButton)event.getSource()))
        {
            answer = answer + event.getActionCommand();
            answerField.setText(answer);
            op2Str = op2Str + event.getActionCommand();
            op2HasValue = true;
        }  // wait for equals sign input event, save operand #2, calculate answer
        else if(op1HasValue && op2HasValue && operationHasValue && (event.getActionCommand()).equals("="))
        {
            op2 = Double.parseDouble(op2Str);

            if(operation.equals("+"))
                answerField.setText("" + (op1 + op2));
            else if(operation.equals("-"))
                answerField.setText("" + (op1 - op2));
            else if(operation.equals("*"))
                answerField.setText("" + (op1 * op2));
            else if(operation.equals("/"))
                answerField.setText("" + (op1 / op2));

            answer = "";
            op1HasValue = op2HasValue = operationHasValue = false;
        }
    }
}

最好不要使用 KeyListener,而是使用 Key Bindings,尤其是在使用 Swing 时。按照本教程的示例,您可以尝试这样的操作(即如果用户按下 1 键):

functionPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
    .put(KeyStroke.getKeyStroke("1"),"1 key");

functionPanel.getActionMap().put("1 key",new AbstractAction() {
    @Override
    public void actionPerformed(ActionEvent ev) {
        // perform operation here
    }
});

这是一个更好的例子,因为你可以看到你应该在 actionPerformed 方法中输入什么(即如果用户按下 C 键清除):

InputMap inMap = functionPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
inMap.put(KeyStroke.getKeyStroke("C"),"Clear");

ActionMap actMap = functionPanel.getActionMap();
actMap.put("Clear",new AbstractAction() {
    @Override
    public void actionPerformed(ActionEvent ev) {
        op1HasValue = op2HasValue = operationHasValue = false;
        op1Str = "";
        op2Str = "";
        operation = "";
        answer = "";
        answerField.setText("");
    }
});

或者,如果您更愿意使用 KeyListener,您可以考虑创建一个实现 KeyListener 的新 class,如下所示。您必须意识到它只有在指定的组件具有焦点时才会起作用,这与其他一些事情相比,是使用 KeyListener 而不是键绑定的缺点。

KeyHandler keyHandler = new KeyHandler();
functionPanel.addKeyListener(keyHandler);

private class KeyHandler implements KeyListener {
    @Override
    public void keyPressed(KeyEvent ev) {
        if (ev.getKeyCode() == KeyEvent.VK_C) /* C for clear */ {
            op1HasValue = op2HasValue = operationHasValue = false;
            op1Str = "";
            op2Str = "";
            operation = "";
            answer = "";
            answerField.setText("");
        }
    }

    @Override
    public void keyReleased(KeyEvent ev) {}

    @Override
    public void keyTyped(KeyEvent ev) {}
}

From looking at KeyListener examples, it seems like that could be helpful...

不要使用 KeyListener。 Swing 旨在与 Key Bindings 一起使用。查看这个不同的 Key Binding link,它显示了用于现有 Swing 组件的所有键绑定。

add another feature which allows the user to use their keyboard as an optional source of input.

使用 Key Bindings 您可以创建一个简单的 Action 用于输入数字:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;

public class CalculatorPanel extends JPanel
{
    private JTextField display;

    public CalculatorPanel()
    {
        Action numberAction = new AbstractAction()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                display.setCaretPosition( display.getDocument().getLength() );
                display.replaceSelection(e.getActionCommand());
            }
        };

        setLayout( new BorderLayout() );

        display = new JTextField();
        display.setEditable( false );
        display.setHorizontalAlignment(JTextField.RIGHT);
        add(display, BorderLayout.NORTH);

        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout( new GridLayout(0, 5) );
        add(buttonPanel, BorderLayout.CENTER);

        for (int i = 0; i < 10; i++)
        {
            String text = String.valueOf(i);
            JButton button = new JButton( text );
            button.addActionListener( numberAction );
            button.setBorder( new LineBorder(Color.BLACK) );
            button.setPreferredSize( new Dimension(50, 50) );
            buttonPanel.add( button );

            InputMap inputMap = button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
            inputMap.put(KeyStroke.getKeyStroke(text), text);
            inputMap.put(KeyStroke.getKeyStroke("NUMPAD" + text), text);
            button.getActionMap().put(text, numberAction);
        }
    }

    private static void createAndShowUI()
    {
//      UIManager.put("Button.margin", new Insets(10, 10, 10, 10) );

        JFrame frame = new JFrame("Calculator Panel");
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        frame.add( new CalculatorPanel() );
        frame.pack();
        frame.setLocationRelativeTo( null );
        frame.setVisible(true);
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowUI();
            }
        });
    }
}

当然,您需要为每个算术函数创建单独的操作。