【Java基础开发】基于 Java Swing 开发的简易计算器 - 支持键盘

博主介绍:✌全网粉丝阅读量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开发学习/项目实战/源代码】 👇点击下方获取👇

相关推荐
光影少年1 小时前
vite+rust生态链工具链
开发语言·前端·后端·rust·前端框架
skywalk81631 小时前
当前有什么流行的lisp的web框架吗?
开发语言·前端·lisp
2501_913061341 小时前
网络原理知识(7)
java·网络·面试
天若有情6731 小时前
C++进阶:普通重载运算符 vs 隐式类型转换重载运算符,一篇讲透区别
开发语言·c++·算法
南境十里·墨染春水1 小时前
linux学习进程 线程同步——读写锁
java·jvm·学习
ZWZhangYu1 小时前
MCP 实战:从协议原理到 Java 自定义工具服务落地
java·开发语言·人工智能
Flittly1 小时前
【SpringSecurity新手村系列】(5)RBAC角色权限与账户状态校验
java·spring boot·笔记·安全·spring·ai
笨蛋不要掉眼泪1 小时前
面试篇-java基础下
java·后端·面试·职场和发展
知识分享小能手2 小时前
R语言入门学习教程,从入门到精通,R语言基础 - 完整知识点与案例代码(1)
开发语言·学习·r语言