(IntelliJ IDEA) Development of simple four arithmetic operators based on JavaFX

Foreword

It was my first time to write in Java. I learned a lot of things while writing, so I wrote a lot of notes (not many actually, mainly because I had to post CSDN and so on, so I added some later). I have never written such a program before, so I guess there are irregularities and bugs.

Although I am still a Java novice, IntelliJ is so easy to use. Not to mention smart completion, it can even help you optimize your code. Really, I cried to death! ! !

Shocked by teacher’s development speed haha

Background

Write a calculator class that supports cascade calls and can complete four simple arithmetic operations. Call example:
var result=new Calc(100).add(10).subtract(5).multiply(10).getResult();
What is done above is the calculation of 100 + 10-5*10, regardless of priority, and is purely calculated sequentially from left to right.
Require:
(1) The calculator class must be a read-only type
(2) The length of the cascade calling method chain is not limited
(3) Finally, provide a “terminal method” to end the entire call and give the calculation results.

I just learned the basics of JavaFX and used it. Everything else is fine. The calculation part of the code is actually very similar to a question in the National Day homework on data structure. It just changes the C language implementation into Java implementation. Using Java is a little simpler. The main problem is that I write too quickly and write all the functions without considering all the functions, which makes it time-consuming to change the code later (poor memory, I forget which part is the function of which part). The main reason is that I didn’t comment much when I first wrote it. The method is commented out).

The calculator class is required to be read-only, but I don’t know much about this (I happened to not be attending the class at the time – I was studying other people’s software), so I’ll look at it later.

var result=new Calc(100).add(10).subtract(5).multiply(10).getResult(); This requirement is also confusing, but I think if I write it this way, I can achieve continuous calculation and calling methods. There is a limit, but, if the characters exceed the text box, they will be invisible. I should write a method to automatically adjust the font size in the text box. It is too late today and I don’t want to write. I will swim at eight tomorrow morning and go to bed! ! !

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) {
        //Set the title of the main stage
        primaryStage.setTitle("Calculator");
        // Create grid layout container
        GridPane gridPane = createGridPane();
        //Create a scene, use the grid layout container as the root node, and set the width of the scene to 300 pixels and the height to 400 pixels
        Scene scene = new Scene(gridPane, 320, 502);
        //Set the scene to the main stage
        primaryStage.setScene(scene);
        // Create an input text box and add it to the first row of the grid layout container
        inputField = createInputField();
        gridPane.add(inputField, 0, 0, 4, 1);

        //Add a button to the specified position of the grid layout container
        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() {
        //Create a grid layout container object
        GridPane gridPane = new GridPane();
        // Set the horizontal spacing between columns in the grid layout container to 6 pixels
        gridPane.setHgap(6);
        // Set the vertical spacing between rows in the grid layout container to 9 pixels
        gridPane.setVgap(9);
        //Set the padding of the grid layout container to 10 pixels
        gridPane.setPadding(new Insets(10));
        // Return the created grid layout container object
        return gridPane;
    }

    private TextField createInputField() {
        //Create a text box object
        TextField textField = new TextField();
        // Actually, I don’t know how to adjust the position. I just searched the tutorial and found the code to adjust the position, and tried the data several times.
        textField.setStyle("-fx-alignment: bottom-left;");
        textField.setStyle("-fx-padding: 0 0 -30 0;");
        //Set the text box as non-editable
        textField.setEditable(false);
        // Set the preferred height of the text box to 125 pixels
        textField.setPrefHeight(125);
        // Set font size to 21
        textField.setFont(Font.font(21));
        // Return the created text box object
        return textField;
    }

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

    //Accepts an additional colSpan parameter, which is used to specify the number of columns that the button spans in the horizontal direction, and controls the horizontal space occupied by the button in the grid layout.
    private void addButtonToGrid(GridPane gridPane, String text, int col, int row, int colSpan) {
        //Create button and set button text
        Button button = new Button(text);
        //Set the handler of the button click event to the handleButtonAction method, passing the button text as a parameter
        button.setOnAction(e -> handleButtonAction(text));
        //Set the preferred size of the button
        button.setPrefSize(70, 50);
        //Set font size to 16
        button.setFont(Font.font(16));
        //Add the button to the specified position in the grid layout
        gridPane.add(button, col, row, colSpan, 1);
    }

    private void handleButtonAction(String text) {
        switch (text) {
            case "=" -> {
                // When the "=" button is clicked, the result of the expression is calculated and displayed in the input box
                // The integer display problem that has been tormenting me for a long time, I have been changing it in evaluateExpression, but later I forgot to convert it to 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" ->
                // Clear the input box when clicking the "AC" button
                    inputField.clear();
            case "DEL" -> {
                // When the "Delete" button is clicked, delete a character from the input box
                String currentText = inputField.getText();
                if (!currentText.isEmpty()) {
                    inputField.setText(currentText.substring(0, currentText.length() - 1));
                }
            }
            default->
                //Append the clicked button text to the input box
                    inputField.appendText(text);
        }
    }

    private double evaluateExpression(String expression) {
        //Remove spaces from expression
        expression = expression.replaceAll("\s + ", "");
        //Initialize operator stack and operand stack
        Stack<Character> operatorStack = new Stack<>();
        Stack<Double> operandStack = new Stack<>();
        //Define operator precedence
        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 == '.') {
                // Process numbers
                StringBuilder sb = new StringBuilder();
                i = getI(expression, operandStack, i, sb);
            } else if (ch == '(') {
                // handle left bracket
                operatorStack.push(ch);
                i + + ;
            } else if (ch == ')') {
                // Process the right bracket
                while (!operatorStack.isEmpty() & amp; & amp; operatorStack.peek() != '(') {
                    applyOperator(operatorStack.pop(), operandStack, operatorStack);
                }
                operatorStack.pop(); // Pop the left bracket
                i + + ;
            } else if (isOperator(ch)) {
                // processing operator
                if (ch == '-' & amp; & amp; (i == 0 || expression.charAt(i - 1) == '(')) {
                    // When the operator is a negative sign and is at the beginning of the expression or after the left parenthesis, push the negative sign onto the operand stack together with the operand
                    i + + ;
                    StringBuilder sb = new StringBuilder("-");
                    i = getI(expression, operandStack, i, sb);
                } else {
                    while (!operatorStack.isEmpty() & amp; & amp; operatorStack.peek() != '(' & amp; & amp; precedence.get(ch) <= precedence.get(operatorStack.peek()) ) {
                        //The operator is not a negative sign and meets the condition. Pop the operator on the top of the stack and apply it to the operand in the operand stack
                        applyOperator(operatorStack.pop(), operandStack, operatorStack);
                    }
                    // Push the current operator onto the operator stack
                    operatorStack.push(ch);
                    i + + ;
                }
            } else {
                // Ignore other characters (such as spaces)
                i + + ;
            }
        }
        // Process remaining operators
        while (!operatorStack.isEmpty()) {
            applyOperator(operatorStack.pop(), operandStack, operatorStack);
        }
        //Return the final result
        if (!operandStack.isEmpty()) {
            return operandStack.pop();
        } else {
            throw new IllegalArgumentException("Invalid expression");
        }
    }

    private int getI(String expression, Stack<Double> operandStack, int i, StringBuilder sb) {
        // Starting from the current position, continuously obtain numeric characters or decimal point characters, and add them to the StringBuilder until a non-numeric non-decimal point character is encountered
        while (i < expression.length() & amp; & amp; (Character.isDigit(expression.charAt(i)) || expression.charAt(i) == '.')) {
            sb.append(expression.charAt(i));
            i + + ;
        }
        // Parse the string in StringBuilder into double type operands
        double operand = Double.parseDouble(sb.toString());
        //Push the operand onto the operand stack
        operandStack.push(operand);
        // Return the updated position index
        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) {
            // The number of operands in the operand stack is insufficient and the operation cannot be performed.
            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) {
                    // Divisor is zero, exception
                    throw new ArithmeticException("Division by zero");
                }
                yield operand1 / operand2;
            }
            default -> 0; // By default, 0 is returned
        };
        //Push the operation result onto the operand stack
        operandStack.push(result);
        // Handle negative results
        if (!operandStack.isEmpty() & amp; & amp; operandStack.peek() < 0) {
            if (!operatorStack.isEmpty()) {
                char nextOperator = operatorStack.peek();
                if (nextOperator == ' + ' || nextOperator == '-') {
                    // Convert the negative result to a negative number when the next operator is a plus or minus sign
                    double negativeResult = operandStack.pop();
                    operandStack.push(-negativeResult);
                }
            }
        }
    }
    public static void main(String[] args) {
        launch(args);
    }
}

The knowledge points of the article match the official knowledge files, and you can further learn related knowledge. Java Skill TreeHomepageOverview 136733 people are learning the system