Java计算器课程设计如何实现核心功能?

99ANYc3cd6 课程介绍 1

Java计算器课程设计

项目概述

本项目旨在使用Java语言和Swing图形用户界面库,设计并实现一个功能完善、界面友好的桌面计算器,该计算器应具备基本的算术运算(加、减、乘、除)、小数点运算、正负号切换、清除功能(C, CE)以及一个简单的内存功能。

需求分析

在开始编码前,我们需要明确计算器需要具备哪些功能。

Java计算器课程设计如何实现核心功能?-第1张图片-指南针培训网

功能性需求:

  • 基本运算:
    • 加法 ()
    • 减法 ()
    • 乘法 ()
    • 除法 ()
  • 辅助功能:
    • 等号 (): 计算并显示结果。
    • 小数点 (): 支持浮点数运算。
    • 正负号切换 (): 改变当前数字的正负。
    • 清除输入: 类似于计算器上的 CE (Clear Entry),清除当前输入的数字,但保留上一次的计算结果。
    • 全部清除: 类似于计算器上的 C (Clear),清除所有内容,回到初始状态。
    • 退格: 删除最后输入的一位数字。
  • 内存功能 (可选,可作为加分项):
    • 记忆加 (M+): 将当前显示的数字加到内存中。
    • 记忆减 (M-): 将当前显示的数字从内存中减去。
    • 记忆 recall (MR): 调出内存中的数值。
    • 记忆清除 (MC): 清空内存。
  • 错误处理:
    • 除零错误: 当用户尝试除以零时,应显示 "Error" 或类似提示。
    • 运算符连续输入: 允许连续输入运算符,后一个运算符覆盖前一个(输入 5 + * 3 应视为 5 * 3)。
    • 数字溢出: 当计算结果超出double类型的表示范围时,应处理异常。

非功能性需求:

  • 界面美观: 界面布局清晰,按钮排列合理,符合标准计算器的样式。
  • 用户体验: 按钮点击有反馈(如颜色变化),计算过程和结果清晰可见。
  • 代码规范: 代码结构清晰,注释充分,变量命名规范,遵循良好的编程实践。

三. 系统设计

技术选型:

  • 编程语言: Java SE (Standard Edition)
  • GUI库: Java Swing (javax.swing)
  • 开发环境 (IDE): IntelliJ IDEA, Eclipse, 或 VS Code

类结构设计:

Java计算器课程设计如何实现核心功能?-第2张图片-指南针培训网

我们可以将整个计算器程序设计在一个主类中,Calculator.java

  • Calculator 类 (主类):
    • 职责: 创建主窗口,初始化所有UI组件(按钮、文本显示区),并管理事件监听器。
    • 成员变量:
      • JFrame: 主窗口。
      • JTextField: 用于显示输入和结果的文本框。
      • JButton[]: 存储所有数字和功能按钮的数组。
      • String: 存储当前输入的数字字符串。
      • String: 存储第一个操作数。
      • String: 存储当前选择的运算符。
      • double: 存储内存中的值(用于内存功能)。
      • boolean: 标记是否刚刚按下了等号,用于决定下一次输入是清屏还是继续在结果上输入。

界面布局设计:

使用 BorderLayout 作为主布局,将显示屏放在 NORTH 区域,将按钮面板放在 CENTER 区域,按钮面板内部使用 GridLayout 来整齐地排列按钮。

+-----------------------------------+
| [显示屏: JTextField]             |
+-----------------------------------+
| [按钮面板: JPanel]                |
| +---+---+---+---+                |
| | 7 | 8 | 9 | / |                |
| +---+---+---+---+                |
| | 4 | 5 | 6 | * |                |
| +---+---+---+---+                |
| | 1 | 2 | 3 | - |                |
| +---+---+---+---+                |
| | C | 0 | . | + |                |
| +---+---+---+---+                |
| | +/-| = | CE|<-|                |
| +---+---+---+---+                |
+-----------------------------------+

四. 核心代码实现

下面是 Calculator.java 的核心代码,包含了详细的注释。

Java计算器课程设计如何实现核心功能?-第3张图片-指南针培训网
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Calculator extends JFrame {
    // --- UI Components ---
    private JTextField displayField;
    private JPanel buttonPanel;
    // --- Calculator Logic Variables ---
    private String currentInput = "";
    private String firstOperand = "";
    private String operator = "";
    private boolean isResultDisplayed = false;
    // --- Memory (Optional) ---
    private double memory = 0.0;
    public Calculator() {
        // 1. Initialize the main window
        setTitle("Java Calculator");
        setSize(400, 500);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new BorderLayout(10, 10));
        setLocationRelativeTo(null); // Center the window
        // 2. Create the display field
        displayField = new JTextField("0");
        displayField.setHorizontalAlignment(JTextField.RIGHT);
        displayField.setEditable(false);
        displayField.setFont(new Font("Arial", Font.BOLD, 24));
        add(displayField, BorderLayout.NORTH);
        // 3. Create the button panel
        buttonPanel = new JPanel();
        buttonPanel.setLayout(new GridLayout(5, 4, 10, 10)); // 5 rows, 4 columns
        add(buttonPanel, BorderLayout.CENTER);
        // 4. Define button labels
        String[] buttonLabels = {
            "7", "8", "9", "/",
            "4", "5", "6", "*",
            "1", "2", "3", "-",
            "C", "0", ".", "+",
            "+/-", "=", "CE", "<-"
        };
        // 5. Create and add buttons to the panel
        for (String label : buttonLabels) {
            JButton button = new JButton(label);
            button.setFont(new Font("Arial", Font.BOLD, 18));
            button.addActionListener(new ButtonClickListener());
            buttonPanel.add(button);
        }
    }
    // --- Inner class to handle button clicks ---
    private class ButtonClickListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            String command = e.getActionCommand();
            if (command.matches("[0-9]")) {
                // Number button clicked
                handleNumberInput(command);
            } else if (command.equals(".")) {
                // Decimal point clicked
                handleDecimalPoint();
            } else if (command.equals("+/-")) {
                // Sign change clicked
                handleSignChange();
            } else if (command.equals("C") || command.equals("CE")) {
                // Clear button clicked
                handleClear(command.equals("C"));
            } else if (command.equals("<-")) {
                // Backspace clicked
                handleBackspace();
            } else if (command.equals("=")) {
                // Equals button clicked
                handleEquals();
            } else {
                // Operator button clicked (+, -, *, /)
                handleOperator(command);
            }
        }
        private void handleNumberInput(String num) {
            if (isResultDisplayed) {
                currentInput = "";
                isResultDisplayed = false;
            }
            if (currentInput.equals("0")) {
                currentInput = num;
            } else {
                currentInput += num;
            }
            displayField.setText(currentInput);
        }
        private void handleDecimalPoint() {
            if (isResultDisplayed) {
                currentInput = "0";
                isResultDisplayed = false;
            }
            if (!currentInput.contains(".")) {
                currentInput += ".";
                displayField.setText(currentInput);
            }
        }
        private void handleSignChange() {
            if (!currentInput.isEmpty() && !currentInput.equals("0")) {
                if (currentInput.startsWith("-")) {
                    currentInput = currentInput.substring(1);
                } else {
                    currentInput = "-" + currentInput;
                }
                displayField.setText(currentInput);
            }
        }
        private void handleClear(boolean isFullClear) {
            if (isFullClear) { // 'C' button
                currentInput = "";
                firstOperand = "";
                operator = "";
                displayField.setText("0");
            } else { // 'CE' button
                currentInput = "";
                displayField.setText("0");
            }
        }
        private void handleBackspace() {
            if (currentInput.length() > 1) {
                currentInput = currentInput.substring(0, currentInput.length() - 1);
            } else {
                currentInput = "0";
            }
            displayField.setText(currentInput);
        }
        private void handleOperator(String newOperator) {
            if (!operator.isEmpty() && !isResultDisplayed) {
                // If an operator is already set, calculate with the new one
                handleEquals();
            }
            firstOperand = currentInput;
            operator = newOperator;
            isResultDisplayed = true;
        }
        private void handleEquals() {
            if (operator.isEmpty() || firstOperand.isEmpty()) {
                return;
            }
            double num1 = Double.parseDouble(firstOperand);
            double num2 = Double.parseDouble(currentInput);
            double result = 0;
            try {
                switch (operator) {
                    case "+":
                        result = num1 + num2;
                        break;
                    case "-":
                        result = num1 - num2;
                        break;
                    case "*":
                        result = num1 * num2;
                        break;
                    case "/":
                        if (num2 == 0) {
                            displayField.setText("Error");
                            currentInput = "";
                            firstOperand = "";
                            operator = "";
                            return;
                        }
                        result = num1 / num2;
                        break;
                }
                // Check for overflow
                if (Double.isInfinite(result)) {
                    throw new ArithmeticException("Overflow");
                }
                currentInput = String.valueOf(result);
                displayField.setText(currentInput);
                isResultDisplayed = true;
                operator = ""; // Reset operator for next calculation
            } catch (ArithmeticException ex) {
                displayField.setText("Error");
                currentInput = "";
                firstOperand = "";
                operator = "";
            }
        }
    }
    // --- Main method to run the application ---
    public static void main(String[] args) {
        // Use SwingUtilities to ensure GUI creation is thread-safe
        SwingUtilities.invokeLater(() -> {
            Calculator calculator = new Calculator();
            calculator.setVisible(true);
        });
    }
}

五. 测试方案

测试是确保程序质量的关键。

单元测试 (针对逻辑):

  • 数字输入测试:
    • 依次点击 1, 2, 3,显示屏应显示 "123"。
    • 输入 0 后再输入 1,应显示 "1"。
  • 小数点测试:
    • 输入 1, , 2,应显示 "1.2"。
    • 连续点击两次小数点,第二次应无效。
  • 运算符测试:
    • 输入 5, , 3, ,应显示 "8.0"。
    • 输入 10, , 2, ,应显示 "5.0"。
    • 输入 5, , , 3,应等价于 5 * 3,最终结果应为 "15.0"。
  • 清除功能测试:
    • 输入 123,点击 CE,应显示 "0"。
    • 输入 123,点击 C,应显示 "0",且后续输入 , 5, 应报错(因为操作数丢失)。
  • 正负号测试:
    • 输入 5,点击 ,应显示 "-5"。
    • 再次点击 ,应显示 "5"。
  • 退格测试:
    • 输入 1234,点击 <- 三次,应显示 "1"。
  • 错误处理测试:
    • 输入 5, , 0, ,应显示 "Error"。
    • 输入一个非常大的数(如 1E308),乘以 2,应显示 "Error" 或 "Infinity"。

集成测试 (针对流程):

  • 连续计算:
    • 10 + 5 = 15* 2 = 30- 10 = 20,结果应为 "20.0"。
  • 混合运算:
    • 100 * 2.5 / 10 - 5 =,结果应为 "20.0"。

六. 扩展与优化建议

如果你已经完成了基本功能,可以尝试以下扩展,让项目更出色:

  1. 科学计算器功能:
    • 添加 sin, cos, tan, sqrt, x^y, log 等按钮。
    • 需要引入 java.lang.Math 类。
  2. 历史记录功能:
    • 在计算器侧面或下方添加一个 JList 来显示历史计算记录。
    • 点击历史记录可以重新加载该表达式。
  3. 主题切换:
    • 提供深色模式和浅色模式切换。
    • 通过修改UI组件的背景色和前景色实现。
  4. 键盘支持:
    • 让计算器能够响应键盘输入(按键盘上的 键等同于点击 按钮)。
    • 需要为 JFrame 添加 KeyListener
  5. 代码重构:
    • 将事件处理逻辑从 ButtonClickListener 中分离出来,创建独立的 NumberHandler, OperatorHandler 等类,遵循单一职责原则。
    • 使用 enum 来管理运算符,使代码更清晰。

抱歉,评论功能暂时关闭!