博主介绍:✌全网粉丝阅读量30W+,CSDN特邀作者、博客专家、CSDN新星计划导师,博客之星、平台优质作者、专注于Java技术领域和项目实战✌
🍅文末获取源码联系🍅
一、功能前言介绍
本程序实现了一个支持键盘和鼠标双模式操作的图形化简易计算器。界面采用经典的计算器布局,顶部为结果显示屏,下方为 5×4 的按钮矩阵,包含数字 0-9、小数点 .、四则运算符 + - * /、等号 =、清除键 C 以及退格键 ←。
核心特性:
- 双输入支持:既可以通过鼠标点击按钮,也可以通过键盘(包括主键盘区和小键盘区)直接输入,提升操作效率。
- 智能显示:结果若为整数则自动去掉小数部分(如 5.0 显示为 5),避免冗余的小数位。
- 防错处理:包含除以零检测、无效输入捕获(NumberFormatException),并通过弹窗提示用户。
- 输入优化:防止以 0 开头的多位数(如 012),但允许 0.x 形式的小数输入;退格键可逐位删除,删空后自动归零。
二、主要技术
| 技术点 | 说明 |
|---|---|
| Swing GUI 框架 | 使用 JFrame 作为主窗口,JTextField 作为显示屏,JButton 作为按钮,JPanel 作为按钮容器。 |
| 布局管理器 | 主窗口使用 BorderLayout(显示屏置北,按钮区居中);按钮面板使用 GridLayout(5, 4, 5, 5) 实现规则的网格排列。 |
| 事件监听机制 | 实现 ActionListener 处理按钮点击事件;实现 KeyListener 捕获键盘按键,实现鼠标与键盘的统一命令处理。 |
| 统一命令处理 | 通过 processCommand(String) 方法将按钮点击和键盘输入统一路由,避免代码重复。 |
| 状态管理 | 使用 currentInput(当前输入)、operator(当前运算符)、result(运算结果)、startNewInput(是否开始新输入)四个状态变量控制计算逻辑。 |
| 异常处理 | 在 calculate() 中捕获 NumberFormatException 和除零错误,使用 JOptionPane 弹出错误对话框。 |
| 系统外观适配 | 通过 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()) 使界面风格跟随操作系统(Windows/macOS/Linux)。 |
| 窗口控制 | 手动设置窗口大小(320×420)、禁止调整大小(setResizable(false))、窗口居中显示(setLocationRelativeTo(null))。 |
三、核心命令路由:processCommand(String)
这是整个程序的中央调度器,所有按钮点击和键盘输入最终都汇聚到这里。
3.1 数字输入(0-9)
java
if (startNewInput) {
currentInput = ""; // 清空旧值
startNewInput = false;
}
逻辑细节:
- 若当前显示为 "0" 且输入新数字,直接替换(避免 0123)
- 否则追加到末尾
3.2 小数点(.)
- 若刚启动新输入,自动补 "0."(如直接按 . 变成 0.)
- 若已含小数点则忽略重复输入
3.3 清除(C)
调用 reset():所有状态归零,显示 "0"
3.4 退格(←)
- 长度 > 1:删除最后一位
- 长度 = 1:归零并设置 startNewInput = true
3.5 运算符(+ - * /)------ 关键逻辑
java
if (!operator.isEmpty()) {
calculate(); // 若已有挂起运算符,先结算上一轮
} else {
result = Double.parseDouble(currentInput); // 首次设左操作数
}
operator = command; // 记录新运算符
startNewInput = true; // 下次输入开始新数字
支持连续运算:如输入 5 + 3 * 2 =,当按 * 时会先算 5+3=8,再以 8 为左操作数等待 2。
3.6 等号(=)
- 执行 calculate()
- 清空 operator,设置 startNewInput = true
- 结果保留在屏幕上,可继续基于该结果运算
四、 代码参考
4.1 构造函数:初始化计算器界面和组件
java
public SimpleCalculator() {
setTitle("简易计算器 - 支持键盘");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// setResizable(false);
// 显示屏
display = new JTextField("0");
display.setFont(new Font("Microsoft YaHei", Font.BOLD, 24));
display.setEditable(false);
display.setHorizontalAlignment(JTextField.RIGHT);
display.setFocusable(false); // 防止光标闪烁
add(display, BorderLayout.NORTH);
// 按钮面板
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(5, 4, 5, 5));
String[] buttons = {
"C", "←", "/", "*",
"7", "8", "9", "-",
"4", "5", "6", "+",
"1", "2", "3", "=",
"0", ".", " ", " "
};
for (String text : buttons) {
JButton btn = new JButton(text);
btn.setFont(new Font("Microsoft YaHei", Font.PLAIN, 18));
btn.addActionListener(this);
if (text.equals(" ") || text.isEmpty()) {
btn.setEnabled(false);
}
buttonPanel.add(btn);
}
add(buttonPanel, BorderLayout.CENTER);
// 启用键盘监听
setFocusable(true);
addKeyListener(this);
// pack(); // 自动计算大小
// 改为手动设置大小
setSize(320, 420); // 宽 320px,高 420px(适合 5x4 按钮布局)
setResizable(false); // 禁止用户调整大小(可选)
setLocationRelativeTo(null);// 然后居中
}
4.2 统一处理命令(来自按钮点击或键盘输入)
java
// ==================== 核心命令处理逻辑 ====================
/**
* 统一处理命令(来自按钮点击或键盘输入)
* 这是整个计算器的"中央调度器"
* @param command 输入的命令字符串(如 "1", "+", "=", "C" 等)
*/
private void processCommand(String command) {
switch (command) {
// ---------- 数字键 0-9 ----------
case "0": case "1": case "2": case "3": case "4":
case "5": case "6": case "7": case "8": case "9":
// 如果需要开始新输入(如刚按过运算符或等号),先清空当前值
if (startNewInput) {
currentInput = "";
startNewInput = false;
}
// 避免以 0 开头的多位数(如 012),但允许 0.x 形式
if (currentInput.equals("0")) {
currentInput = command; // 直接替换 "0"
} else {
currentInput += command; // 追加数字
}
display.setText(currentInput); // 更新显示屏
break;
// ---------- 小数点 ----------
case ".":
// 如果刚启动新输入,自动补 "0."(如直接按 "." 变成 "0.")
if (startNewInput) {
currentInput = "0";
startNewInput = false;
}
// 只有当当前输入不含小数点时,才允许添加
if (!currentInput.contains(".")) {
currentInput += ".";
display.setText(currentInput);
}
break;
// ---------- 清除键 C ----------
case "C":
reset(); // 调用复位方法
break;
// ---------- 退格键 ← ----------
case "←":
// 如果正在输入且长度大于1,删除最后一位
if (!startNewInput && currentInput.length() > 1) {
currentInput = currentInput.substring(0, currentInput.length() - 1);
display.setText(currentInput);
} else {
// 否则归零并标记为新的开始
currentInput = "0";
startNewInput = true;
display.setText("0");
}
break;
// ---------- 四则运算符 + - * / ----------
case "+": case "-": case "*": case "/":
// 如果已有挂起的运算符,先结算上一轮运算(支持连续运算)
if (!operator.isEmpty()) {
calculate();
} else {
// 第一次设置左操作数
result = Double.parseDouble(currentInput);
}
operator = command; // 记录当前运算符
startNewInput = true; // 标记下次输入为新数字
break;
// ---------- 等号 = ----------
case "=":
calculate(); // 执行计算
operator = ""; // 清空运算符
startNewInput = true; // 标记下次输入为新数字
break;
}
}
4.3 执行实际的数学运算
java
// ==================== 计算引擎 ====================
/**
* 执行实际的数学运算
* 根据 operator 中存储的运算符,对 result(左操作数)和 currentInput(右操作数)进行计算
*/
private void calculate() {
// 如果没有运算符,直接返回(无需计算)
if (operator.isEmpty()) return;
double currentValue; // 右操作数(当前输入的值)
try {
// 将当前输入字符串转换为浮点数
currentValue = Double.parseDouble(currentInput);
} catch (NumberFormatException ex) {
// 如果转换失败(如输入无效),弹出错误对话框并复位
JOptionPane.showMessageDialog(this, "输入无效!", "错误", JOptionPane.ERROR_MESSAGE);
reset();
return;
}
// 根据运算符执行相应计算
switch (operator) {
case "+":
result += currentValue; // 加法
break;
case "-":
result -= currentValue; // 减法
break;
case "*":
result *= currentValue; // 乘法
break;
case "/":
// 除法前检查除数是否为零
if (currentValue == 0) {
JOptionPane.showMessageDialog(this, "不能除以零!", "错误", JOptionPane.ERROR_MESSAGE);
reset(); // 除零错误,复位计算器
return;
}
result /= currentValue; // 除法
break;
}
// ---------- 结果格式化显示 ----------
// 如果结果是整数(如 5.0),去掉小数部分显示为 "5"
if (result == (long) result) {
currentInput = String.valueOf((long) result);
} else {
// 保留小数部分(如 5.5)
currentInput = String.valueOf(result);
}
display.setText(currentInput); // 显示计算结果
}
4.4 键盘事件处理
java
// ==================== 键盘事件处理 ====================
/**
* KeyListener 接口方法:处理键盘按键按下事件
* 这是键盘输入的核心处理方法
* @param e 键盘事件对象,包含按键信息
*/
@Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode(); // 获取按键的虚拟键码(如 VK_0, VK_ENTER 等)
char keyChar = e.getKeyChar(); // 获取按键对应的字符
// ---------- 数字键(主键盘区 0-9 和 小键盘区 0-9)----------
if ((keyCode >= KeyEvent.VK_0 && keyCode <= KeyEvent.VK_9) ||
(keyCode >= KeyEvent.VK_NUMPAD0 && keyCode <= KeyEvent.VK_NUMPAD9)) {
String digit = String.valueOf(keyChar);
// 小键盘数字的 keyChar 可能不是 '0'-'9',需要特殊处理
if (keyChar < '0' || keyChar > '9') {
// 通过键码偏移计算数字:VK_NUMPAD0 对应 0,VK_NUMPAD1 对应 1,以此类推
digit = String.valueOf(keyCode - KeyEvent.VK_NUMPAD0);
}
processCommand(digit); // 将数字作为命令处理
}
// ---------- 小数点(主键盘区 . 和 小键盘区 .)----------
else if (keyCode == KeyEvent.VK_PERIOD || keyCode == KeyEvent.VK_DECIMAL) {
processCommand(".");
}
// ---------- 运算符 ----------
else if (keyChar == '+') processCommand("+");
else if (keyChar == '-') processCommand("-");
else if (keyChar == '*') processCommand("*");
else if (keyChar == '/') processCommand("/");
// ---------- 等于 / 回车 ----------
else if (keyChar == '=' || keyCode == KeyEvent.VK_ENTER) {
processCommand("=");
}
// ---------- 清除(Esc 键 或 C/c 键)----------
else if (keyCode == KeyEvent.VK_ESCAPE || keyChar == 'c' || keyChar == 'C') {
processCommand("C");
}
// ---------- 退格(Backspace 键)----------
else if (keyCode == KeyEvent.VK_BACK_SPACE) {
processCommand("←");
}
}
4.5 主方法(程序入口)
java
// ==================== 主方法(程序入口) ====================
/**
* 程序入口点
* @param args 命令行参数(未使用)
*/
public static void main(String[] args) {
// 在事件调度线程(EDT)中创建和显示 GUI,确保线程安全
SwingUtilities.invokeLater(() -> {
try {
// 设置界面外观为当前操作系统的原生风格
// Windows 下像 Windows 计算器,macOS 下像 macOS 风格
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
ex.printStackTrace(); // 如果设置失败,打印异常信息
}
// 创建计算器实例并显示
SimpleCalculator calc = new SimpleCalculator();
calc.setVisible(true); // 设置窗口可见
});
}
五、 功能截图

六、 源码获取
【Java开发学习/项目实战/源代码】 👇点击下方获取👇