calculator
Typer | Posted on | |
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); }
}