计算机模拟程序

一、项目简介

功能描述

一个简单的计算机程序,具有图形用户界面,在界面上可以点击相应按键执行加减乘除操作,也可在键盘上进行输入输出。可以进行简单的整数四则运算。

二、功能架构图或主要功能流程图

三、任务简述

序号

完成功能与任务

描述

1

窗口界面设计

使用了Java中的swing库来实现窗口界面的设计,使用了awt库中的一些类。如Jframe、JPanel,提供了一些基本的窗口和组件类

2

接收键盘和图形界面的输入

使用了KeyListener、ActionListener等技术来监听键盘、按钮的输入

3

文本框内容显示

通过JTextField组件实现的。

4

历史记录存储

使用了Java的文件操作技术,通过创建文件输出流和输出流写入器,将计算表达式和结果写入文件

5

移除空格

expression.replaceAll("\\s+", "") 用于移除输入表达式中的所有空格,确保空格不会影响表达式的解析。

6

拆分表达式

expression.split("(?<=\\d)(?=\\D)|(?<=\\D)(?=\\d)") 用正则表达式将输入的数学表达式拆分为数字和运算符

7

处理数字和运算符

通过遍历拆分后的元素(tokens),使用 isNumber 方法判断是否为数字。使用 isOperator 方法判断是否为运算符。

8

计算表达式

遇到运算符时,如果当前运算符的优先级低于或等于栈顶运算符的优先级,则使用 applyOperator 方法计算栈顶两个数字和一个运算符的结果,并将结果推回 numbers 栈。然后将当前运算符推入 operators 栈

9

计算剩余运算符

当所有的 tokens 都被处理完后,如果 operators 栈中还有运算符,继续使用 applyOperator 方法完成剩余的计算。。

10

判断数字和运算符

尝试将 token 转换为 double 类型来判断是否是数字。首先检查 token 的长度是否为 1,以确保只有一个字符。然后,使用 "+-*/".contains(token) 来判断 token 是否包含在运算符字符串中。如果是有效的运算符,则返回 true

11

给定相应运算的功能

ExpressionEvaluator 类中的私有方法 applyOperator,用于根据给定的运算符 operator 对两个操作数 operand1 和 operand2 进行相应的运算,并返回计算结果。

四、功能详解

 1. *窗口界面设计

  创建一个计算器界面,并初始化计算器的各个组件和属性。首先,代码设置计算器的标题为"计算器",并设置当关闭计算器窗口时退出程序。

  然后,使用BorderLayout布局管理器设置计算器的布局。在计算器的北部(上方),创建一个JTextField对象作为显示器(displayField)。设置显示器为只读(不可编辑),并将文本的对齐方式设置为右对齐。将显示器添加到容器中的北部区域。

  最后,创建一个JPanel对象作为按钮面板(buttonPanel),使用GridLayout布局管理器将按钮排列成5行4列的网格。定义一个字符串数组(buttonLabels),包含计算器的按钮标签。使用循环遍历按钮标签数组,创建JButton对象,并为每个按钮添加ActionListener监听器。将按钮添加到按钮面板中。

public class Calculator extends JFrame implements ActionListener, KeyListener {
    private JTextField displayField;
    private StringBuilder inputBuffer;

    public Calculator() {
        setTitle("计算器");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new BorderLayout());

        displayField = new JTextField();
        displayField.setEditable(false);
        displayField.setHorizontalAlignment(JTextField.RIGHT);
        add(displayField, BorderLayout.NORTH);

        JPanel buttonPanel = new JPanel(new GridLayout(5,4));
        String[] buttonLabels = {
                "AC","→",""," ",
                "7", "8", "9", "/",
                "4", "5", "6", "*",
                "1", "2", "3", "-",
                "0", ".", "=", "+"
        };
        for (String label : buttonLabels) {
            JButton button = new JButton(label);
            button.addActionListener(this);
            buttonPanel.add(button);
        }
        add(buttonPanel, BorderLayout.CENTER);

        inputBuffer = new StringBuilder();
        addKeyListener(this);
        setFocusable(true);
        setFocusTraversalKeysEnabled(false);
        pack();
        setLocationRelativeTo(null);
        setVisible(true);
    }

2. *接收键盘和图形界面的输入

  处理计算器界面上的按钮点击事件和键盘输入事件。

  在actionPerformed方法中,根据不同的按钮命令(command),执行相应的操作。如果命令是"AC",表示清空输入,将输入缓冲区(inputBuffer)清空并将显示器(displayField)的文本设置为空。如果命令是"=",表示计算结果,调用calculateResult方法进行计算。如果命令是"→",表示删除最后一个字符,如果输入缓冲区不为空,删除最后一个字符并更新显示器的文本。否则,将命令追加到输入缓冲区并更新显示器的文本。

  在keyTyped方法中,根据键盘输入的字符判断是否为数字、小数点或运算符,如果是,则将字符追加到输入缓冲区并更新显示器的文本。

  在keyPressed方法中,根据键盘按键的keyCode判断是否为回车键或退格键。如果是回车键,调用calculateResult方法进行计算。如果是退格键,如果输入缓冲区不为空,删除最后一个字符并更新显示器的文本。

@Override
    public void actionPerformed(ActionEvent e) {
        String command = e.getActionCommand();
        if (command.equals("AC")) {
            inputBuffer.setLength(0);
            displayField.setText("");
        } else if (command.equals("=")) {
            calculateResult();
        } else if (command.equals("→")) {
            if (inputBuffer.length() > 0) {
                inputBuffer.deleteCharAt(inputBuffer.length() - 1);
                displayField.setText(inputBuffer.toString());
            }
        } else {
            inputBuffer.append(command);
            displayField.setText(inputBuffer.toString());
        }
    }

    @Override
    public void keyTyped(KeyEvent e) {
        char keyChar = e.getKeyChar();
        if (Character.isDigit(keyChar) || keyChar == '.' || keyChar == '+' || keyChar == '-' || keyChar == '*' || keyChar == '/' || keyChar == '=') {
            inputBuffer.append(keyChar);
            displayField.setText(inputBuffer.toString());
        }
    }

    @Override
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_ENTER) {
            calculateResult();
        } else if (e.getKeyCode() == KeyEvent.VK_BACK_SPACE) {
            if (inputBuffer.length() > 0) {
                inputBuffer.deleteCharAt(inputBuffer.length() - 1);
                displayField.setText(inputBuffer.toString());
            }
        }
    }

@Override
    public void keyReleased(KeyEvent e) {
    }

3. *文本框内容显示

  初始化计算器的界面和输入缓冲区。使用BorderLayout布局管理器设置计算器的布局。在计算器的北部(上方),创建一个JTextField对象作为显示器(displayField)。设置显示器为只读(不可编辑),并将文本的对齐方式设置为右对齐。将显示器添加到容器中的北部区域。创建一个StringBuilder对象,并将其赋值给inputBuffer变量。inputBuffer用于存储用户输入的表达式。

private JTextField displayField;
    private StringBuilder inputBuffer;

    public Calculator() {
        setTitle("计算器");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new BorderLayout());

        displayField = new JTextField();
        displayField.setEditable(false);
        displayField.setHorizontalAlignment(JTextField.RIGHT);
        add(displayField, BorderLayout.NORTH);
        add(buttonPanel, BorderLayout.CENTER);//将名为buttonPanel的组件添加到容器中,并使用 
        BorderLayout布局管理器将其放置在容器的中心区域。

        inputBuffer = new StringBuilder();//创建一个StringBuilder对象,并将其赋值给 
        inputBuffer变量,用于存储用户输入的表达式。

4. 历史记录存储

  计算输入的表达式,并将结果显示在界面上。创建一个CalculationSaver对象(计算结果保存器),并调用saveCalculation方法,将表达式和结果保存到指定的文件路径中。如果在计算过程中出现异常,代码将显示器上的文本设置为"错误"。

private void calculateResult() {//计算输入的表达式,并将结果显示在界面上。
        try {
            String expression = inputBuffer.toString();
            ExpressionEvaluator expressionEvaluator = new ExpressionEvaluator();
            double result = expressionEvaluator.evaluateExpression(expression);
            displayField.setText(String.valueOf(result));// 将计算结果转换为字符串类型,并设置到显示器(displayField)上
            CalculationSaver calculationSaver = new CalculationSaver("文件路径");
            // 调用CalculationSaver对象的saveCalculation方法,传入表达式和结果,将其保存到文件中
            calculationSaver.saveCalculation(expression, result);
        } catch (Exception e) {// 如果在计算过程中出现异常,将显示器上的文本设置为"错误"
            displayField.setText("错误");
        } finally { // 最后,清空输入缓冲区(inputBuffer)
            inputBuffer.setLength(0);
        }
    }

5、计算

  根据给定的运算符和两个操作数,应用运算符进行计算并返回结果。

private double applyOperator(char operator, double operand2, double operand1) {
        // 应用运算符计算结果
        switch (operator) {
            case '+':
                return operand1 + operand2;
            case '-':
                return operand1 - operand2;
            case '*':
                return operand1 * operand2;
            case '/':
                return operand1 / operand2;
            default:
                throw new IllegalArgumentException("非法运算符: " + operator);
        }
    }

6、表达式求值器

  接受一个数学表达式作为输入,并计算出表达式的结果。

  expression.replaceAll("\\s+", "") 用于移除输入表达式中的所有空格,确保空格不会影响表达式的解析。

  expression.split("(?<=\\d)(?=\\D)|(?<=\\D)(?=\\d)") 用正则表达式将输入的数学表达式拆分为数字和运算符

public double evaluateExpression(String expression) {
        // 移除表达式中的空格
        expression = expression.replaceAll("\\s+", "");

        // 使用正则表达式将表达式拆分为数字和运算符
        String[] tokens = expression.split("(?<=\\d)(?=\\D)|(?<=\\D)(?=\\d)");

        for (String token : tokens) {
            if (isNumber(token)) {
                // 如果是数字,则将其转换为double类型并入栈
                numbers.push(Double.parseDouble(token));
            } else if (isOperator(token)) {
                // 如果是运算符,则根据优先级进行计算
                char operator = token.charAt(0);
                while (!operators.isEmpty() && hasHigherPrecedence(operators.peek(), operator)) {
                    double result = applyOperator(operators.pop(), numbers.pop(), numbers.pop());
                    numbers.push(result);
                }
                operators.push(operator);
            }
        }

        // 计算剩余的运算符
        while (!operators.isEmpty()) {
            double result = applyOperator(operators.pop(), numbers.pop(), numbers.pop());
            numbers.push(result);
        }

        // 返回最终结果
        return numbers.pop();
    }

7、判断优先级

  判断token是否为数字、运算符以及判断运算符的优先级。

  isNumber 方法用于判断 token 是否是一个有效的数字。它通过尝试将 token 转换为 double 类型来判断是否是数字。如果转换成功,则返回 true,否则捕获 NumberFormatException 异常并返回 false。

  isOperator 方法用于判断 token 是否是一个有效的运算符。它首先检查 token 的长度是否为 1,以确保只有一个字符。然后,使用 "+-*/".contains(token) 来判断 token 是否包含在运算符字符串中。如果是有效的运算符,则返回 true,否则返回 false。

private boolean isNumber(String token) {
        // 判断是否是数字
        try {
            Double.parseDouble(token);
            return true;
        } catch (NumberFormatException e) {
            return false;
        }
    }

    private boolean isOperator(String token) {
        // 判断是否是运算符
        return token.length() == 1 && "+-*/".contains(token);
    }

    private boolean hasHigherPrecedence(char operator1, char operator2) {
        // 判断运算符的优先级
        return (operator1 == '*' || operator1 == '/') && (operator2 == '+' || operator2 == '-');
    }

五、总结

  本次设计运用了Java编程语言和相关的GUI库(如javax.swing和java.awt)来实现计算器的界面和交互功能。它使用了面向对象的编程思想,将计算器的各个组件和功能封装成类,并通过继承和实现接口的方式进行扩展和重写。还使用了面向对象编程、布局管理器、事件处理、数据结构、正则表达式、异常处理和文件操作等技术。实现了一个简单的计算器程序,可以进行基本的数学运算,并将计算结果保存到文件中。

六、展望

  计算器不支持一些复杂的计算。未来可以增加功能使得计算器可以进行一些复杂的计算,比如三角函数,指数函数等。也可以增加打开多窗口来查看历史记录,复制粘贴等功能。

  • 25
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
C语言是一种通用的编程语言,可以用来编写模拟计算机程序。模拟计算机程序是指通过编写代码,使计算机实现对真实计算机行为的模拟。 在C语言中,我们可以使用各种变量、运算符和控制结构来实现模拟计算机的功能。例如,我们可以使用整数变量来表示计算机的寄存器,并使用运算符来进行加减乘除等计算操作。我们还可以使用条件语句和循环结构来实现判断和重复执行的功能。 通过编写适当的C语言代码,我们可以模拟计算机的各个组成部分和行为。例如,我们可以设计一个基于C语言的模拟CPU程序,其中包括指令解码、运算操作、数据读写等功能。我们还可以使用C语言来模拟计算机内存的读写操作,并设计数据结构来模拟计算机的缓存和存储器。 另外,C语言还提供了许多库函数和标准函数,这些函数可以帮助我们更方便地进行模拟计算机程序的编写。例如,我们可以使用标准输入输出函数来进行模拟计算机程序的输入输出操作。我们还可以使用时间函数来模拟计算机的时钟和计时功能。 总之,C语言可以很好地用于实现模拟计算机程序。通过编写适当的代码,我们可以建立一个功能完善的模拟计算机系统,使其具备实际计算机的各种行为和功能。这种模拟计算机程序不仅可以用于教学和学习目的,还可以用于开发和测试其他计算机软件。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值