bug修复:
1. 括号隔开两数输出后为一个数,例如:4()5=5,或者一个数后跟括号,括号内为数字或表达式,输出为括号内值,例如:4(5-7)=-2。
2. 除数为零时文本框缺少输出。(其实这个应该不算bug,只是没写显示的内容,导致文本框内容不变,我记得是这样的,控制台那边是有显示的,异常处理是写了的)。
优化:
1.JavaFX的按钮创建改成了用二维数组循环创建,其实这应该不算是优化,毕竟复杂一点性能就会差,好在计算器比较简单,用二维数组创建还更为直观,我觉得。
2. 去除了不需要的一些代码,本来写了两个addButtonToGrid方法,第二个多一个参数方便直接指定按钮的列跨度,免得第一个多次调用,结果发现其实用不到。
3. 使用常量替换字符串,虽然最后只改了报错的地方的字符串,主要其他字符串都比较短,个人美观上不接受换为常量。
4. 将界面和逻辑分离,写在两个不同的Java文件中——放Calculator 类的文件和放CalculatorLogic 类的文件。
Calculator文件包含主应用程序和界面的创建逻辑。
CalculatorLogic文件包含计算器的逻辑和按钮事件处理的方法。
哦对了,因为之前注释太长,看之前代码好麻烦,(虽然其实可以折叠代码,但是我真的很懒,点开、折叠好麻烦),我把注释都删了好像,懒得写了,其实大体上没变什么,可以参照上一个读。
Calculator.java 代码如下:
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 static com.example.hellofx.CalculatorLogic.ERROR_EXPRESSION;
import static com.example.hellofx.CalculatorLogic.evaluateExpression;
public class Calculator extends Application {
public static TextField inputField;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("简易四则计算器");
GridPane gridPane = createGridPane();
Scene scene = new Scene(gridPane, 320, 502);
primaryStage.setScene(scene);
inputField = createInputField();
gridPane.add(inputField, 0, 0, 4, 1);
addButtonsToGrid(gridPane);
primaryStage.show();
}
private GridPane createGridPane() {
GridPane gridPane = new GridPane();
gridPane.setHgap(6);
gridPane.setVgap(9);
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);
textField.setPrefHeight(125);
textField.setFont(Font.font(21));
return textField;
}
private void addButtonToGrid(GridPane gridPane, String text, int col, int row) {
Button button = new Button(text);
button.setOnAction(e -> handleButtonAction(text));
button.setPrefSize(70, 50);
button.setFont(Font.font(16));
gridPane.add(button, col, row);
}
private void addButtonsToGrid(GridPane gridPane) {
String[][] buttonLabels = {
{"AC", "DEL", "(", ")"},
{"7", "8", "9", "/"},
{"4", "5", "6", "*"},
{"1", "2", "3", "-"},
{".", "0", "00", "+"},
{"", "", "", "="}
};
for (int row = 1; row < buttonLabels.length + 1; row++) {
for (int col = 0; col < buttonLabels[row - 1].length; col++) {
String label = buttonLabels[row - 1][col];
if (!label.isEmpty())
addButtonToGrid(gridPane, label, col, row);
}
}
}
private void handleButtonAction(String text) {
switch (text) {
case "=" -> {
String expression = inputField.getText();
if (isParenthesesMatched(expression)) {
if (containsArithmeticOperator(expression)) {
double result = evaluateExpression(expression);
if (result % 1 == 0) {
int intResult = (int) result;
inputField.setText(String.valueOf(intResult));
} else
inputField.setText(String.valueOf(result));
} else
inputField.setText(ERROR_EXPRESSION);
} else
inputField.setText(ERROR_EXPRESSION);
}
case "AC" -> inputField.clear();
case "DEL" -> {
String currentText = inputField.getText();
if (!currentText.isEmpty())
inputField.setText(currentText.substring(0, currentText.length() - 1));
}
default -> inputField.appendText(text);
}
}
private boolean containsArithmeticOperator(String expression) {
return expression.matches(".*[+\\-*/].*");
}
private boolean isParenthesesMatched(String expression) {
int count = 0;
for (char ch : expression.toCharArray()) {
if (ch == '(')
count++;
else if (ch == ')')
count--;
if (count < 0)
return false;
}
return count == 0;
}
}
CalculatorLogic.java 代码如下:
package com.example.hellofx;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
import static com.example.hellofx.Calculator.inputField;
public final class CalculatorLogic {
static final String ERROR_EXPRESSION = "非法输入";
static final String ERROR_BY_ZERO = "除数不可为零";
private CalculatorLogic() {
}
public static 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(ERROR_EXPRESSION);
}
private static int getI(String expression, Stack<Double> operandStack, int i, StringBuilder sb) {
while (i < expression.length() && (Character.isDigit(expression.charAt(i)) || expression.charAt(i) == '.')) {
sb.append(expression.charAt(i));
i++;
}
double operand = Double.parseDouble(sb.toString());
operandStack.push(operand);
return i;
}
private static boolean isOperator(char ch) {
return ch == '+' || ch == '-' || ch == '*' || ch == '/';
}
private static void applyOperator(char operator, Stack<Double> operandStack, Stack<Character> operatorStack) {
if (operandStack.size() < 2) {
inputField.setText(ERROR_EXPRESSION);
throw new IllegalArgumentException(ERROR_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) {
inputField.setText(ERROR_BY_ZERO);
throw new ArithmeticException(ERROR_BY_ZERO);
}
yield operand1 / operand2;
}
default -> 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);
}
}
}
}
}