Swing是初学者做图形计算器的合理选择,因其JDK自带、无需额外依赖、事件模型直观,且避开JavaFX模块化配置;用GridLayout布局按钮、JTextField作只读显示屏,状态用current/previous/operator三字段管理,事件须在EDT中执行。

为什么 Swing 是初学者做图形计算器的合理选择
因为不需要额外依赖、JDK 自带、事件模型直观,且能避开 JavaFX 的模块化配置和 WebView 等干扰项。Swing 的 JFrame、JButton、JTextField 组合足够表达计算器的核心交互——输入、点击、显示结果。
注意:Java 11+ 已将 JavaFX 移出 JDK,而 Swing 仍完整保留在 java.desktop 模块中,无需添加任何 --add-modules 参数就能直接运行。
核心控件布局与事件绑定的关键写法
别用 BorderLayout 堆满整个窗口再硬塞按钮——那样会导致按钮大小失控、无法对齐。推荐用 GridLayout(4, 4) 管理数字和运算符按钮区域,顶部单独放一个 JTextField 作显示屏。
-
JTextField必须设为setEditable(false),否则用户键盘输入会破坏计算器状态逻辑 - 每个
JButton的addActionListener中,用evt.getActionCommand()获取按钮文本(如"+"、"5"),而不是监听getText()——后者在按钮文字变更时容易出错 - 避免在监听器里直接做计算:把解析表达式、执行运算的逻辑抽成独立方法,比如
evaluate(String expr),方便后续替换为更健壮的实现(如双栈算法)
处理“连续点击运算符”和“等号重复触发”的典型 bug
初学者常写出按下 "+" 后再按 "-" 就清空输入的逻辑,但实际应保留前一个操作数,仅更新当前运算符。同理,连续按 "=" 应复用上一次的完整表达式继续计算(如 5 + 3 = → 8,再按 = 应得 16)。
立即学习“Java免费学习笔记(深入)”;
建议用三个字段管理状态:
-
private String currentInput = ""(当前待输入的数字或新操作符) -
private String previousInput = ""(上一次输入的数字或表达式片段) -
private String operator = ""(挂起的运算符,如"+"、"*")
这样在点击 "=" 时,可拼接成 previousInput + operator + currentInput 再求值,而非简单地调用 eval()。
一个可直接运行的最小可工作示例(含关键注释)
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
<p>public class SimpleCalculator extends JFrame {
private JTextField display;
private String current = "";
private String previous = "";
private String op = "";</p><pre class='brush:java;toolbar:false;'>public SimpleCalculator() {
setTitle("简易计算器");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
display = new JTextField("0");
display.setFont(new Font("Monospaced", Font.BOLD, 20));
display.setHorizontalAlignment(JTextField.RIGHT);
display.setEditable(false);
add(display, BorderLayout.NORTH);
JPanel buttonPanel = new JPanel(new GridLayout(4, 4, 5, 5));
String[] keys = {"7","8","9","/","4","5","6","*","1","2","3","-","0","=","C","+"};
for (String key : keys) {
JButton btn = new JButton(key);
btn.setFont(new Font("SansSerif", Font.PLAIN, 18));
btn.addActionListener(new CalcListener());
buttonPanel.add(btn);
}
add(buttonPanel, BorderLayout.CENTER);
pack();
setLocationRelativeTo(null);
}
private class CalcListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
if (cmd.matches("\d")) {
current += cmd;
display.setText(current);
} else if (cmd.equals("C")) {
current = previous = op = "";
display.setText("0");
} else if (cmd.equals("=")) {
if (!previous.isEmpty() && !current.isEmpty() && !op.isEmpty()) {
double a = Double.parseDouble(previous);
double b = Double.parseDouble(current);
double result = switch (op) {
case "+" -> a + b;
case "-" -> a - b;
case "*" -> a * b;
case "/" -> b != 0 ? a / b : 0;
default -> b;
};
current = String.valueOf(result);
previous = "";
op = "";
display.setText(current);
}
} else {
if (!current.isEmpty()) {
if (!previous.isEmpty() && op.isEmpty()) {
op = cmd;
previous = current;
current = "";
} else if (!op.isEmpty()) {
// 更新运算符,不重新计算
op = cmd;
}
}
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new SimpleCalculator().setVisible(true));
}}
这个版本不支持小数点、括号或负数,但已覆盖加减乘除、连续运算、清屏等主干流程。真正容易被忽略的是:Swing 的事件必须在 Event Dispatch Thread 中执行,所以 SwingUtilities.invokeLater 不是可选装饰,而是强制要求——漏掉它可能导致界面卡死或组件不响应。








