我不会深入讨论您在问题中发布的代码,而是试图帮助您实现编写计算器演示的总体目标。
第一步应该是通过写下来清楚地了解问题:
我需要一个带有显示屏的计算器和一个带有数字 0-9 的小键盘以及运算符 +、-、x 和一个 = 按钮。计算器应该从键盘读取一系列数字,然后是数学运算符,然后是另一系列数字,依此类推。每个不间断的数字序列都应转换为整数值。
计算器应计算将数学运算符应用于第一个和第二个整数值的结果。如果输入了更多的运算符和整数,则应将数学运算符应用于先前计算的结果和进一步的整数。这个过程应该一直持续到等号按钮被按下。当数字在键盘上被按下时,它们应该出现在附加到目前输入的这些数字的文本显示中。
当按下操作符或等号按钮时,这表示整数输入的结束,如果计算完成,则结果应显示在显示屏上,否则整数应保留在显示屏中,直到按下另一个数字 - 然后应清除显示并显示新数字,并像以前一样附加后续数字。
从这个描述中,我们可以识别出一些名词:Calculator、Button、Display、Keypad、Digit、Operator、Integer、Result ...和一些动词:Read、Press、Convert、Calculate、Apply、Enter、Complete、Show、Remain、Clear , 显示, 追加
这些让我们了解程序所需的状态和行为。然后我们决定如何在我们的实现中对这些进行建模。通常,名词可以建模为类/实例变量(状态),动词可以建模为方法(行为)。
这是一种可能的设计:
一个名为 Calculator 的类,使用 Swing 组件来表示 Buttons/Keypad 和 Display;使用原始 int 类型来表示 Integer/Result/Digit;使用 Java 数学运算符来表示运算符。
让我们开始制作它的骨骼:
public class Calculator {
private JFrame window;
private List<JButton> keypad;
private JLabel display;
private int result;
private StringBuffer digitsEntered;
private int integerEntered;
}
现在我们需要弄清楚我们将如何阅读/按下按钮。我们将需要设置我们JButton
的 s 以响应被激活并将该事件连接到我们在 Calculator 类中定义的方法。
一种方法是创建JButton
s 并向它们添加监听器。我们可以Calculator
实现ActionListener
接口,这迫使它定义一个actionPerformed
带有单个ActionEvent
参数的方法。JButton
我们可以通过创建inCalculator
的构造函数来了解它是如何工作的。
public class Calculator implements ActionListener {
private JFrame window;
private List<JButton> keypad;
private JLabel display;
private int result;
private StringBuffer digitsEntered;
private int integerEntered;
public Calculator() {
JButton zeroButton = new JButton("0");
zeroButton.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
// this would get executed when zeroButton is pressed
}
}
请注意,此代码不会做任何事情,因为我们还没有设置窗口并将按钮连接到它。但是,代码应该说明我们如何通过按下按钮来运行代码。
让我们通过设置一切来让这段代码处于工作状态:
public class Calculator implements ActionListener {
private JFrame window;
private List<JButton> keypad;
private JLabel display;
private int result;
private StringBuffer digitsEntered;
private int integerEntered;
public Calculator() {
window = new JFrame("Calculator");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton zeroButton = new JButton("0");
zeroButton.addActionListener(this);
window.add(zeroButton, BorderLayout.CENTER);
window.pack();
window.setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
// this would get executed when zeroButton is pressed
JOptionPane.showMessageDialog(window, "Button pressed");
}
public static void main(String[] args) {
new Calculator();
}
}
好的,我们需要不止一个按钮,我们需要一个完整的负载。让我们将数字设为 0-9:
for (int digit = 0; digit <=9; digit++) {
JButton button = new JButton(Integer.toString(digit));
button.addActionListener(this);
window.add(button);
}
嗯,这不正常- 窗口上只出现一个按钮。那是因为我们有默认的窗口布局,这不是我们需要的。我们希望按钮出现在网格中,在窗口中组合在一起。让我们创建一个JPanel
来将按钮组合在一起并使用一个GridLayout
面板,然后我们可以将面板添加到窗口中。
public Calculator() {
window = new JFrame("Calculator");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel digitsPanel = new JPanel();
digitsPanel.setLayout(new GridLayout(4, 3));
for (int digit = 0; digit <=9; digit++) {
JButton button = new JButton(Integer.toString(digit));
button.addActionListener(this);
digitsPanel.add(button);
}
window.add(digitsPanel);
window.pack();
window.setVisible(true);
}
这还不错,但是数字并没有按照您在小键盘上看到的通常顺序出现。那是因为它们按照从左上角到右下角的添加顺序出现。我们可以通过用数组指定我们想要的顺序来解决这个问题,然后迭代它(我们为此使用for-each样式迭代器,因为它更整洁)。当我们这样做时,我们可以对数学运算符和等号按钮做类似的事情,并将它们也添加到框架中(这里我们将明确用于窗口的布局,我们将使用 a BorderLayout
)。
public Calculator() {
window = new JFrame("Calculator");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLayout(new BorderLayout());
JPanel digitsPanel = new JPanel();
digitsPanel.setLayout(new GridLayout(4, 3));
int[] digitOrder = new int[] { 7,8,9,4,5,6,1,2,3,0 };
for (int digit : digitOrder) {
JButton button = new JButton(Integer.toString(digit));
button.addActionListener(this);
digitsPanel.add(button);
}
window.add(digitsPanel, BorderLayout.CENTER);
JPanel operatorsPanel = new JPanel();
operatorsPanel.setLayout(new GridLayout(5,1));
String[] operators = new String[] { "+","-","x","/","=" };
for (String operator : operators) {
JButton button = new JButton(operator);
button.addActionListener(this);
operatorsPanel.add(button);
}
window.add(operatorsPanel, BorderLayout.EAST);
window.pack();
window.setVisible(true);
}
好的,我们几乎完成了组件。我们只需要添加一个显示器。
...
private JLabel display;
...
public Calculator() {
window = new JFrame("Calculator");
...
display = new JLabel();
display.setHorizontalAlignment(JLabel.RIGHT);
display.setText("0");
window.add(display, BorderLayout.NORTH);
...
window.pack();
window.setVisible(true);
}
现在我们只需要实现响应按钮按下的逻辑。首先,让我们看看如果按下数字,我们需要做什么。我们需要处理 Append 和 Show 动词,并将该数字附加到我们的输入并显示它。
StringBuffer digitsEntered;
...
public Calculator() {
...
digitsEntered = new StringBuffer();
...
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() instanceof JButton) {
String buttonText = ((JButton)e.getSource()).getText();
if (Character.isDigit(buttonText.charAt(0))) {
digitsEntered.append(buttonText.charAt(0));
display.setText(digitsEntered.toString());
}
}
}
凉爽的。现在我们需要实现 Convert 动词并将我们的数字转换为整数。这将在按下运算符或等于时发生。我们需要记住按下了哪个运算符,这样我们就知道在输入第二个整数时要进行什么计算。
private String currentOperator;
...
public void actionPerformed(ActionEvent e) {
if (e.getSource() instanceof JButton) {
String buttonText = ((JButton)e.getSource()).getText();
if (Character.isDigit(buttonText.charAt(0))) {
digitsEntered.append(buttonText.charAt(0));
display.setText(digitsEntered.toString());
} else {
integerEntered = Integer.parseInt(digitsEntered.toString());
digitsEntered.setLength(0); // clear out the input so a new integer can be entered
currentOperator = buttonText; // remember the operator
}
}
}
现在我们实际上需要处理第二次按下运算符或等于时,我们已经保存了一个整数和运算符。在这里我们可以实现Calculate/Apply动词的+部分并显示结果。
...
} else {
if (currentOperator == null) {
integerEntered = Integer.parseInt(digitsEntered.toString());
} else {
int previousInteger = integerEntered;
integerEntered = Integer.parseInt(digitsEntered.toString());
if ("+".equals(currentOperator)) {
result = previousInteger + integerEntered;
display.setText(Integer.toString(result));
}
}
digitsEntered.setLength(0); // clear out the input so a new integer can be entered
currentOperator = buttonText; // remember the operator
}
...
这不太对。它将把前两个整数的总和而不是到目前为止输入的所有整数的总和放入结果中。我们需要将第一个值存储在中,result
然后将每个后续整数添加到存储在中的值中result
。这意味着我们不再需要该变量,并且我们在和previousInteger
中都有一些重复的代码,我们可以在.if
else
if
...
integerEntered = Integer.parseInt(digitsEntered.toString());
if (currentOperator == null) {
result = integerEntered;
} else {
if ("+".equals(currentOperator)) {
result = result + integerEntered;
display.setText(Integer.toString(result));
}
}
...
让我们实现其他运算符。
...
integerEntered = Integer.parseInt(digitsEntered.toString());
if (currentOperator == null) {
result = integerEntered;
} else {
if ("+".equals(currentOperator)) {
result = result + integerEntered;
} else if ("-".equals(currentOperator)) {
result = result - integerEntered;
} else if ("x".equals(currentOperator)) {
result = result * integerEntered;
} else if ("/".equals(currentOperator)) {
result = result / integerEntered;
} else if ("=".equals(currentOperator)) {
result = integerEntered;
} else {
// Unrecognised operator
}
display.setText(Integer.toString(result));
}
...
在这里,我们将 = 设为一个操作符,其作用类似于重置并允许我们开始新的计算。如果您尝试点击 = then +(在结果中添加一个数字),您可能会注意到您得到一个错误;这是因为输入中没有数字可以转换为 + 运算符的整数。在这种情况下,我们可以通过跳过计算来解决这个问题。
...
if (digitsEntered.length() > 0) {
integerEntered = Integer.parseInt(digitsEntered.toString());
if (currentOperator == null) {
result = integerEntered;
} else {
if ("+".equals(currentOperator)) {
result = result + integerEntered;
} else if ("-".equals(currentOperator)) {
result = result - integerEntered;
} else if ("x".equals(currentOperator)) {
result = result * integerEntered;
} else if ("/".equals(currentOperator)) {
result = result / integerEntered;
} else if ("=".equals(currentOperator)) {
result = integerEntered;
} else {
// Unrecognised operator
}
display.setText(Integer.toString(result));
}
}
...
这是到目前为止的完整代码。它不处理除以 0,keypad
从不使用并且可以删除,并且integerEntered
实际上只需要是局部变量而不是实例变量。但是,代码应该大部分都可以工作,如果您发现任何问题,请告诉我。我也有一个更简洁的版本(我所做的第一个实现),但解释起来并不那么简单。
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class Calculator implements ActionListener {
private JFrame window;
private List<JButton> keypad;
private JLabel display;
private int result;
private StringBuffer digitsEntered;
private int integerEntered;
private String currentOperator;
public Calculator() {
window = new JFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLayout(new BorderLayout());
digitsEntered = new StringBuffer();
display = new JLabel();
display.setHorizontalAlignment(JLabel.RIGHT);
display.setText("0");
window.add(display, BorderLayout.NORTH);
JPanel digitsPanel = new JPanel();
digitsPanel.setLayout(new GridLayout(4, 3));
int[] digitOrder = new int[] { 7,8,9,4,5,6,1,2,3,0 };
for (int digit : digitOrder) {
JButton button = new JButton(Integer.toString(digit));
button.addActionListener(this);
digitsPanel.add(button);
}
window.add(digitsPanel, BorderLayout.CENTER);
JPanel operatorsPanel = new JPanel();
operatorsPanel.setLayout(new GridLayout(5,1));
String[] operators = new String[] { "+","-","x","/","=" };
for (String operator : operators) {
JButton button = new JButton(operator);
button.addActionListener(this);
operatorsPanel.add(button);
}
window.add(operatorsPanel, BorderLayout.EAST);
window.pack();
window.setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() instanceof JButton) {
String buttonText = ((JButton)e.getSource()).getText();
if (Character.isDigit(buttonText.charAt(0))) {
digitsEntered.append(buttonText.charAt(0));
display.setText(digitsEntered.toString());
} else {
if (digitsEntered.length() > 0) {
integerEntered = Integer.parseInt(digitsEntered.toString());
if (currentOperator == null) {
result = integerEntered;
} else {
if ("+".equals(currentOperator)) {
result = result + integerEntered;
} else if ("-".equals(currentOperator)) {
result = result - integerEntered;
} else if ("x".equals(currentOperator)) {
result = result * integerEntered;
} else if ("/".equals(currentOperator)) {
result = result / integerEntered;
} else if ("=".equals(currentOperator)) {
result = integerEntered;
} else {
// Unrecognised operator
}
display.setText(Integer.toString(result));
}
}
digitsEntered.setLength(0); // clear out the input so a new integer can be entered
currentOperator = buttonText; // remember the operator
}
}
}
public static void main(String[] args) {
new Calculator();
}
}
这是更清洁但更复杂的版本:
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
public class CalculatorDemo extends JFrame {
private static final long serialVersionUID = 1L;
private StringBuffer inputBuffer = new StringBuffer();
private String queuedOperator = null;
private int leftHandSide = 0;
private JLabel inputDisplay;
private JLabel operatorIndicator;
private class DigitButtonAction extends AbstractAction {
private static final long serialVersionUID = 1L;
private final int digit;
public DigitButtonAction(final int digit) {
super(Integer.toString(digit));
this.digit = digit;
}
@Override
public void actionPerformed(ActionEvent e) {
enterDigit(digit);
}
}
private class OperatorButtonAction extends AbstractAction {
private static final long serialVersionUID = 1L;
private final String operator;
public OperatorButtonAction(final String operator) {
super(operator);
this.operator = operator;
}
@Override
public void actionPerformed(ActionEvent e) {
performOperation(operator);
}
}
public CalculatorDemo() {
super("Calculator");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
setSize(100, 200);
// Create display text field
inputDisplay = new JLabel();
inputDisplay.setHorizontalAlignment(JLabel.RIGHT);
inputDisplay.setText(Integer.toString(leftHandSide));
operatorIndicator = new JLabel();
operatorIndicator.setBorder(new EmptyBorder(0, 4, 0, 4));
final JPanel display = new JPanel();
display.setLayout(new BorderLayout());
display.add(inputDisplay, BorderLayout.CENTER);
display.add(operatorIndicator, BorderLayout.WEST);
// Create number buttons
final JPanel digitPanel = new JPanel();
digitPanel.setLayout(new GridLayout(4,3));
final int[] digitKeyOrder = new int[] { 7,8,9,4,5,6,1,2,3 };
for (int digit : digitKeyOrder) {
digitPanel.add(new JButton(new DigitButtonAction(digit)));
}
digitPanel.add(new JPanel()); // Blank spacer panel
digitPanel.add(new JButton(new DigitButtonAction(0)));
// Create operators
final String[] OPERATORS = { "+","-","*","/","=" };
final JPanel operatorPanel = new JPanel();
operatorPanel.setLayout(new GridLayout(OPERATORS.length, 1));
for (String op : OPERATORS) {
operatorPanel.add(new JButton(new OperatorButtonAction(op)));
}
add(digitPanel, BorderLayout.CENTER);
add(operatorPanel, BorderLayout.EAST);
add(display, BorderLayout.NORTH);
pack();
}
private void enterDigit(final int digit) {
if (digit == 0 && inputBuffer.length() == 0) return;
inputBuffer.append(Integer.toString(digit));
inputDisplay.setText(inputBuffer.toString());
}
private int calculate(final int leftHandSide, final String operator, final int rightHandSide) {
if (operator == null) return rightHandSide;
else if ("+".equals(operator)) return leftHandSide + rightHandSide;
else if ("-".equals(operator)) return leftHandSide - rightHandSide;
else if ("*".equals(operator)) return leftHandSide * rightHandSide;
else if ("/".equals(operator)) return leftHandSide / rightHandSide;
else if ("=".equals(operator)) return rightHandSide;
else {
throw new IllegalStateException("Unrecognised operator " + operator);
}
}
private void performOperation(final String operator) {
try {
final int rightHandSide = Integer.parseInt(inputBuffer.toString());
leftHandSide = calculate(leftHandSide, queuedOperator, rightHandSide);
} catch (NumberFormatException e) {
// Ignore failure to parse inputBuffer to integer
// calculate() not called, just carry on and clear the
// inputBuffer and queue a new operator
} catch (ArithmeticException e) {
// Divide by 0 in calculate()
operatorIndicator.setText("");
inputDisplay.setText(e.getMessage());
queuedOperator = null;
return;
} catch (IllegalStateException e) {
// Unrecognised operator
operatorIndicator.setText("");
inputDisplay.setText(e.getMessage());
queuedOperator = null;
return;
}
inputBuffer.setLength(0); // Clear inputBuffer
queuedOperator = operator; // Queue next operator
// Update display
operatorIndicator.setText(queuedOperator);
inputDisplay.setText(Integer.toString(leftHandSide));
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new CalculatorDemo().setVisible(true);
}
});
}
}