calculator

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;

public class Calculator extends Application {

    // --- UI 组件 ---
    private final Text processDisplay = new Text("");      // 上层:显示过程(小字)
    private final Text resultDisplay = new Text("0");     // 下层:显示结果(大字加粗)
    private final DecimalFormat df = new DecimalFormat("#,###.##########");

    // --- 逻辑变量 ---
    private BigDecimal num1 = BigDecimal.ZERO;
    private String operator = "";
    private boolean start = true;
    private String currentProcess = "";

    @Override
    public void start(Stage primaryStage) {
        // 1. 屏幕区域设计:大字结果 vs 小字过程
        processDisplay.setFont(Font.font("System", 16));
        processDisplay.setFill(Color.GRAY);

        resultDisplay.setFont(Font.font("System", FontWeight.BOLD, 38)); // 结果字体更大更显眼

        VBox screen = new VBox(8, processDisplay, resultDisplay);
        screen.setAlignment(Pos.CENTER_RIGHT);
        screen.setPadding(new Insets(15, 20, 15, 20));
        screen.setMinHeight(130);
        screen.setMaxWidth(380);
        screen.setStyle("-fx-background-color: #f8f9fa; -fx-background-radius: 15; -fx-border-color: #dee2e6; -fx-border-radius: 15; -fx-border-width: 2;");

        // 2. 按钮布局
        GridPane grid = new GridPane();
        grid.setHgap(12);
        grid.setVgap(12);

        // 按钮阵列:已将 +/- 换成 ⌫ (退格键)
        String[][] rows = {
                {"AC", "⌫", "%", "÷"},
                {"7", "8", "9", "×"},
                {"4", "5", "6", "-"},
                {"1", "2", "3", "+"}
        };

        for (int r = 0; r < rows.length; r++) {
            for (int c = 0; c < rows[r].length; c++) {
                String text = rows[r][c];
                Button btn = createButton(text);
                grid.add(btn, c, r);
                btn.setOnAction(_ -> handleAction(text));
            }
        }

        // 手动精准放置最后一行布局 [ 0 ] [ . ] [ = ]
        Button btn0 = createButton("0");
        btn0.setPrefWidth(162);
        grid.add(btn0, 0, 4, 2, 1);
        btn0.setOnAction(_ -> handleAction("0"));

        Button btnDot = createButton(".");
        grid.add(btnDot, 2, 4);
        btnDot.setOnAction(_ -> handleAction("."));

        Button btnEqual = createButton("=");
        grid.add(btnEqual, 3, 4);
        btnEqual.setOnAction(_ -> handleAction("="));

        // 3. 总体组装
        VBox root = new VBox(25, screen, grid);
        root.setPadding(new Insets(25));
        root.setStyle("-fx-background-color: white;");

        primaryStage.setTitle("JavaFX 高精度专业计算器");
        primaryStage.setScene(new Scene(root));
        primaryStage.setResizable(false);
        primaryStage.show();
    }

    private Button createButton(String text) {
        Button btn = new Button(text);
        btn.setFont(Font.font("System", FontWeight.BOLD, 22));
        btn.setPrefSize(75, 75);
        String style = "-fx-background-radius: 20; -fx-cursor: hand; ";

        if ("÷×-+= ".contains(text)) {
            style += "-fx-background-color: #ff9f0a; -fx-text-fill: white;"; // 橙色
        } else if ("AC⌫%".contains(text)) {
            style += "-fx-background-color: #a5a5a5; -fx-text-fill: black;"; // 浅灰
        } else {
            style += "-fx-background-color: #333333; -fx-text-fill: white;"; // 深灰
        }
        btn.setStyle(style);
        return btn;
    }

    private void handleAction(String value) {
        if ("0123456789.".contains(value)) {
            if (start) {
                resultDisplay.setText(value.equals(".") ? "0." : value);
                start = false;
            } else {
                if (value.equals(".") && resultDisplay.getText().contains(".")) return;
                if (resultDisplay.getText().replace(",", "").length() > 20) return;
                resultDisplay.setText(resultDisplay.getText() + value);
            }
            formatCurrentInput();
        } else if ("AC".equals(value)) {
            reset();
        } else if ("⌫".equals(value)) {
            handleDelete();
        } else if ("=".equals(value)) {
            executeCalculation(true);
        } else if ("%".equals(value)) {
            BigDecimal val = getDisplayValue().divide(new BigDecimal("100"), 10, RoundingMode.HALF_UP);
            resultDisplay.setText(formatNum(val));
        } else {
            if (!operator.isEmpty() && !start) executeCalculation(false);
            num1 = getDisplayValue();
            operator = value;
            currentProcess = formatNum(num1) + " " + operator + " ";
            processDisplay.setText(currentProcess);
            start = true;
        }
        adjustFontSize();
    }

    private void handleDelete() {
        if (start) return;
        String current = resultDisplay.getText();
        if (current.length() <= 1 || current.equals("0")) {
            resultDisplay.setText("0");
            start = true;
        } else {
            resultDisplay.setText(current.substring(0, current.length() - 1));
            formatCurrentInput();
        }
    }

    private void executeCalculation(boolean isFinal) {
        if (operator.isEmpty()) return;
        BigDecimal num2 = getDisplayValue();
        if (isFinal) {
            currentProcess += formatNum(num2) + " =";
            processDisplay.setText(currentProcess);
        }
        calculate(num2);
        if (isFinal) operator = "";
        start = true;
    }

    private BigDecimal getDisplayValue() {
        try { return new BigDecimal(resultDisplay.getText().replace(",", "")); }
        catch (Exception e) { return BigDecimal.ZERO; }
    }

    private void formatCurrentInput() {
        String currentText = resultDisplay.getText();
        if (currentText.endsWith(".")) return;
        String raw = currentText.replace(",", "");
        try {
            BigDecimal val = new BigDecimal(raw);
            String formatted = df.format(val);
            if (raw.startsWith("0.") || raw.startsWith("-0.")) {
                formatted = (raw.startsWith("-") ? "-" : "") + "0" + raw.substring(raw.indexOf("."));
            }
            resultDisplay.setText(formatted);
        } catch (Exception ignored) {}
    }

    private void adjustFontSize() {
        int len = resultDisplay.getText().length();
        double size = (len <= 12) ? 38 : (len <= 16) ? 28 : (len <= 22) ? 20 : 16;
        resultDisplay.setFont(Font.font("System", FontWeight.BOLD, size));
    }

    private String formatNum(BigDecimal d) {
        if (d.abs().compareTo(new BigDecimal("1e15")) > 0) {
            return new java.text.DecimalFormat("0.######E0").format(d);
        }
        return df.format(d.stripTrailingZeros());
    }

    private void calculate(BigDecimal num2) {
        BigDecimal result = BigDecimal.ZERO;
        try {
            switch (operator) {
                case "+" -> result = num1.add(num2);
                case "-" -> result = num1.subtract(num2);
                case "×" -> result = num1.multiply(num2);
                case "÷" -> result = (num2.compareTo(BigDecimal.ZERO) != 0) ?
                        num1.divide(num2, 10, RoundingMode.HALF_UP) : BigDecimal.ZERO;
            }
            resultDisplay.setText(formatNum(result));
        } catch (Exception e) { resultDisplay.setText("Error"); }
    }

    private void reset() {
        resultDisplay.setText("0"); processDisplay.setText("");
        currentProcess = ""; num1 = BigDecimal.ZERO; operator = ""; start = true;
        adjustFontSize();
    }

    static void main(String[] args) { launch(args); }
}

 

Scroll to Top