【问题标题】:How to accept keyboard input alongside input from JButtons?如何接受键盘输入以及来自 JButtons 的输入?
【发布时间】:2015-01-12 01:50:16
【问题描述】:

我创建了一个计算器来帮助我练习 GUI 创建,因为我是新手。到目前为止它工作得很好。用户点击他们想要的相应数字/操作的按钮。但是,我想添加另一个功能,允许用户使用他们的键盘作为可选的输入源。从查看 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;
        }
    }
}

【问题讨论】:

    标签: java swing user-interface event-handling keyboard-events


    【解决方案1】:

    与其使用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 的新类,如下所示。您必须意识到,它只有在指定组件具有焦点时才能工作,除此之外,这是使用 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) {}
    }
    

    【讨论】:

    • 我实际上尝试了类似于您的 KeyHander 类的东西,但正如您所说,由于我无法让事件发生,因此具有焦点的组件存在问题。我将做进一步的研究并学习更多关于键绑定、输入映射和动作映射的知识。谢谢。
    • 很高兴我能帮上忙。 :)
    • :) 我刚刚意识到 JButtons 有一个 doClick 方法。这意味着一旦我确定是否按下了有效的键,我应该只需要使用相应按钮的 doClick 方法。这个选项将阻止我从我的 ActionListener 类中复制和粘贴并缩短程序。
    【解决方案2】:

    从查看 KeyListener 示例看来,这可能会有所帮助...

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

    添加另一个功能,允许用户使用他们的键盘作为可选的输入源。

    使用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();
                }
            });
        }
    }
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-21
      • 1970-01-01
      • 1970-01-01
      • 2011-05-23
      • 2023-03-09
      相关资源
      最近更新 更多