(IntelliJ IDEA)基于JavaFX的简易四则运算器开发

 前言

         第一次用Java写,好多东西都是边写边学的,所以写了很多备注(其实也不多,主要还是因为要发CSDN之类的所以后面加了一些)。没写过这种程序,估计有不规范的地方,可能还有bug之类的。

        虽然我还是Java小白,但是IntelliJ好用啊哈哈,智能补全就不说了,它甚至还能帮你优化代码,真的,我哭死!!!

        震惊老师的开发速度哈哈

背景

        写一个支持级联调用的计算器类,能完成简单的四则运算,调用示例:
                var result=new Calc(100).add(10).subtract(5).multiply(10).getResult();
        上面的完成的是100+10-5*10的计算,不考虑优先级,纯从左到右顺序计算。
        要求:
        (1)计算器类必须是只读类型
        (2)级联调用方法链的长度不限
        (3)最后提供一个“终端方法”,结束整个调用,并给出计算结果。

        正好学了一下JavaFX的基础就用一下。其他的都还好,计算那部分代码其实和数据结构的国庆作业有道题很像,只是把C语言实现变成Java实现而已,用Java还简单一点。主要问题还是写的太急,功能没考虑全就写了,导致后面改代码费时间(记性差,忘了哪部分是哪部分的功能了,主要第一次写的时候没怎么注释,就给方法注释了一下)。

        要求计算器类要是只读类,但是我不太懂这个(当时正好没听课——在研究别人的软件),等之后再看看。

         var result=new Calc(100).add(10).subtract(5).multiply(10).getResult();这段要求也好迷,不过我觉得我这样写也实现了连续计算和调用方法不限,不过嘛,要是字符超过文本框就看不见了,该写一个文本框内字体大小自动调节的,今天太晚了不想写,明天早八游泳,睡觉!!!

        

package com.example.hellofx;

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.text.Font;
import javafx.stage.Stage;

import java.util.HashMap;
import java.util.Map;
import java.util.Stack;

public class Calculator extends Application {
    private TextField inputField;

    @Override
    public void start(Stage primaryStage) {
        // 设置主舞台的标题
        primaryStage.setTitle("Calculator");
        // 创建网格布局容器
        GridPane gridPane = createGridPane();
        // 创建场景,将网格布局容器作为根节点,设置场景的宽度为 300 像素,高度为 400 像素
        Scene scene = new Scene(gridPane, 320, 502);
        // 将场景设置到主舞台
        primaryStage.setScene(scene);
        // 创建输入文本框,并将其添加到网格布局容器的第一行
        inputField = createInputField();
        gridPane.add(inputField, 0, 0, 4, 1);

        // 添加按钮到网格布局容器的指定位置
        addButtonToGrid(gridPane, "AC", 0, 1);
        addButtonToGrid(gridPane, "DEL", 1, 1);
        addButtonToGrid(gridPane, "(", 2, 1);
        addButtonToGrid(gridPane, ")", 3, 1);

        addButtonToGrid(gridPane, "7", 0, 2);
        addButtonToGrid(gridPane, "8", 1, 2);
        addButtonToGrid(gridPane, "9", 2, 2);
        addButtonToGrid(gridPane, "/", 3, 2);

        addButtonToGrid(gridPane, "4", 0, 3);
        addButtonToGrid(gridPane, "5", 1, 3);
        addButtonToGrid(gridPane, "6", 2, 3);
        addButtonToGrid(gridPane, "*", 3, 3);

        addButtonToGrid(gridPane, "1", 0, 4);
        addButtonToGrid(gridPane, "2", 1, 4);
        addButtonToGrid(gridPane, "3", 2, 4);
        addButtonToGrid(gridPane, "-", 3, 4);

        addButtonToGrid(gridPane, ".", 0, 5);
        addButtonToGrid(gridPane, "0", 1, 5);
        addButtonToGrid(gridPane, "00", 2, 5);
        addButtonToGrid(gridPane, "+", 3, 5);

        addButtonToGrid(gridPane, "=", 3, 6, 2);

        primaryStage.show();
    }

    private GridPane createGridPane() {
        // 创建一个网格布局容器对象
        GridPane gridPane = new GridPane();
        // 设置网格布局容器中列之间的水平间距为 6 像素
        gridPane.setHgap(6);
        // 设置网格布局容器中行之间的垂直间距为 9 像素
        gridPane.setVgap(9);
        // 设置网格布局容器的内边距为 10 像素
        gridPane.setPadding(new Insets(10));
        // 返回创建的网格布局容器对象
        return gridPane;
    }

    private TextField createInputField() {
        // 创建一个文本框对象
        TextField textField = new TextField();
        // 其实这块没懂怎么调的位置,就是搜了一下教程套了调位置的代码,试了几次数据
        textField.setStyle("-fx-alignment: bottom-left;");
        textField.setStyle("-fx-padding: 0 0 -30 0;");
        // 将文本框设置为不可编辑
        textField.setEditable(false);
        // 设置文本框的首选高度为 125 像素
        textField.setPrefHeight(125);
        // 设置字体大小为 21
        textField.setFont(Font.font(21));
        // 返回创建的文本框对象
        return textField;
    }

    private void addButtonToGrid(GridPane gridPane, String text, int col, int row) {
        addButtonToGrid(gridPane, text, col, row, 1);
    }

    //接受一个额外的 colSpan 参数,用于指定按钮在水平方向上跨越的列数,控制按钮在网格布局中的水平空间占用。
    private void addButtonToGrid(GridPane gridPane, String text, int col, int row, int colSpan) {
        // 创建按钮并设置按钮文本
        Button button = new Button(text);
        // 设置按钮点击事件的处理程序为 handleButtonAction 方法,传递按钮文本作为参数
        button.setOnAction(e -> handleButtonAction(text));
        // 设置按钮的首选大小
        button.setPrefSize(70, 50);
        // 设置字体大小为 16
        button.setFont(Font.font(16));
        // 将按钮添加到网格布局中的指定位置
        gridPane.add(button, col, row, colSpan, 1);
    }

    private void handleButtonAction(String text) {
        switch (text) {
            case "=" -> {
                // 点击 "=" 按钮时,计算表达式的结果并显示在输入框中
                // 折磨我半天的整数显示问题,我还一直在evaluateExpression里面改,后面忘了这里转化为String了
                String expression = inputField.getText();
                double result = evaluateExpression(expression);
                if (result % 1 == 0) {
                    int intResult = (int) result;
                    inputField.setText(String.valueOf(intResult));
                } else {
                    inputField.setText(String.valueOf(result));
                }
            }
            case "AC" ->
                // 点击 "AC" 按钮时,清空输入框
                    inputField.clear();
            case "DEL" -> {
                // 点击 "Delete" 按钮时,从输入框中删除一个字符
                String currentText = inputField.getText();
                if (!currentText.isEmpty()) {
                    inputField.setText(currentText.substring(0, currentText.length() - 1));
                }
            }
            default ->
                // 将点击的按钮文本追加到输入框中
                    inputField.appendText(text);
        }
    }

    private double evaluateExpression(String expression) {
        // 去除表达式中的空格
        expression = expression.replaceAll("\\s+", "");
        // 初始化运算符栈和操作数栈
        Stack<Character> operatorStack = new Stack<>();
        Stack<Double> operandStack = new Stack<>();
        // 定义运算符优先级
        Map<Character, Integer> precedence = new HashMap<>();
        precedence.put('+', 1);
        precedence.put('-', 1);
        precedence.put('*', 2);
        precedence.put('/', 2);

        int i = 0;
        while (i < expression.length()) {
            char ch = expression.charAt(i);

            if (Character.isDigit(ch) || ch == '.') {
                // 处理数字
                StringBuilder sb = new StringBuilder();
                i = getI(expression, operandStack, i, sb);
            } else if (ch == '(') {
                // 处理左括号
                operatorStack.push(ch);
                i++;
            } else if (ch == ')') {
                // 处理右括号
                while (!operatorStack.isEmpty() && operatorStack.peek() != '(') {
                    applyOperator(operatorStack.pop(), operandStack, operatorStack);
                }
                operatorStack.pop(); // 弹出左括号
                i++;
            } else if (isOperator(ch)) {
                // 处理运算符
                if (ch == '-' && (i == 0 || expression.charAt(i - 1) == '(')) {
                    // 当运算符是负号且位于表达式开头或左括号后时,将负数符号与操作数一起推入操作数栈
                    i++;
                    StringBuilder sb = new StringBuilder("-");
                    i = getI(expression, operandStack, i, sb);
                } else {
                    while (!operatorStack.isEmpty() && operatorStack.peek() != '(' && precedence.get(ch) <= precedence.get(operatorStack.peek())) {
                        //运算符不是负号且满足条件.弹出栈顶运算符并将其应用于操作数栈中的操作数
                        applyOperator(operatorStack.pop(), operandStack, operatorStack);
                    }
                    // 将当前运算符压入运算符栈
                    operatorStack.push(ch);
                    i++;
                }
            } else {
                // 忽略其他字符(例如空格)
                i++;
            }
        }
        // 处理剩余的运算符
        while (!operatorStack.isEmpty()) {
            applyOperator(operatorStack.pop(), operandStack, operatorStack);
        }
        // 返回最终结果
        if (!operandStack.isEmpty()) {
            return operandStack.pop();
        } else {
            throw new IllegalArgumentException("Invalid expression");
        }
    }

    private int getI(String expression, Stack<Double> operandStack, int i, StringBuilder sb) {
        // 从当前位置开始,连续获取数字字符或小数点字符,将其添加到 StringBuilder 中,直到遇到非数字非小数点的字符
        while (i < expression.length() && (Character.isDigit(expression.charAt(i)) || expression.charAt(i) == '.')) {
            sb.append(expression.charAt(i));
            i++;
        }
        // 将 StringBuilder 中的字符串解析为 double 类型的操作数
        double operand = Double.parseDouble(sb.toString());
        // 将操作数压入操作数栈中
        operandStack.push(operand);
        // 返回更新后的位置索引
        return i;
    }

    private boolean isOperator(char ch) {
        return ch == '+' || ch == '-' || ch == '*' || ch == '/';
    }

    private void applyOperator(char operator, Stack<Double> operandStack, Stack<Character> operatorStack) {
        if (operandStack.size() < 2) {
            // 操作数栈中的操作数数量不足,无法进行运算
            throw new IllegalArgumentException("Invalid expression");
        }
        double operand2 = operandStack.pop();
        double operand1 = operandStack.pop();
        double result = switch (operator) {
            case '+' -> operand1 + operand2;
            case '-' -> operand1 - operand2;
            case '*' -> operand1 * operand2;
            case '/' -> {
                if (operand2 == 0) {
                    // 除数为零,异常
                    throw new ArithmeticException("Division by zero");
                }
                yield operand1 / operand2;
            }
            default -> 0;  // 默认情况下,返回0
        };
        // 将运算结果压入操作数栈
        operandStack.push(result);
        // 处理负数结果的情况
        if (!operandStack.isEmpty() && operandStack.peek() < 0) {
            if (!operatorStack.isEmpty()) {
                char nextOperator = operatorStack.peek();
                if (nextOperator == '+' || nextOperator == '-') {
                    // 当下一个运算符是加号或减号时,将负数结果转换为负数
                    double negativeResult = operandStack.pop();
                    operandStack.push(-negativeResult);
                }
            }
        }
    }
    public static void main(String[] args) {
        launch(args);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值