Как принять ввод с клавиатуры наряду с вводом от JButtons?


Я создал калькулятор, чтобы помочь мне практиковать создание GUI, так как я новичок в этом. До сих пор это работает идеально. Пользователь нажимает на кнопку для соответствующего номера / операции, которую он желает. Однако я хотел бы добавить еще одну функцию, которая позволяет пользователю использовать свою клавиатуру в качестве дополнительного источника ввода. Глядя на примеры Кейлистеров, кажется, что это может быть полезно...но я не могу придумать простой способ использовать его для осуществления своей идеи.

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;
        }
    }
}
2 2

2 ответа:

Вместо использования KeyListener, лучше использовать привязки ключей, особенно если вы работаете с 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) {}
}

Глядя на примеры Кейлистеров, кажется, что это может быть полезно...

Не использовать KeyListener. Swing был разработан для использования с Key Bindings. Проверьте эту другую ссылку привязки ключей, которая показывает все привязки ключей, используемые для существующих компонентов 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();
            }
        });
    }
}
Конечно, вам нужно будет создать отдельные действия для каждой из ваших арифметических функций.