Java Irgendwas stimmt mit meinem Taschenrechner Programm nicht, ich habe den Überblick verloren.. [JavaFX]

vram78

Lieutenant
Registriert
Dez. 2015
Beiträge
732
Hallo,

Ich möchte Java lernen und versuche mit JavaFX einen Taschenrechner zu coden. Nur habe ich total den Überblick verloren und verstehe selber nichts mehr.

Wenn ich beispielsweise auf die Enter Taste drücke, macht das Programm verrückte Sachen. Statt den Term auszurechnen, verschwindet der Term (Ergebnis wird gar nicht angezeigt) oder macht andere eigenartige Sachen.

Wenn ich sowas wie 999999999+8888888888 eingebe und auf die Enter Taste drücke, wird gar nichts ausgerechnet, stattdessen werden nur Nullen am Ende des Terms angehängt. Ich wollte es im Windows-Taschenrechner-Stil machen, aber es funktioniert nicht. Also bei sehr großen Zahlen sollte es sowas hier ausgeben "2,e+16", aber es funktioniert einfach nicht.

Mag mir jemand Tipps geben? :S

Der Code: Klasse GuiFX:

Java:
package taschenrechner;

import javafx.animation.PauseTransition;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import javafx.util.Duration;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

public class GuiFX extends Application {

    private TextField display;
    private final Map<String, Button> buttonMap = new HashMap<>();
    private final Function func = new Function();

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

    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("Taschenrechner");

        display = new TextField();
        display.setEditable(false);
        display.setFocusTraversable(false);
        display.setAlignment(Pos.CENTER_RIGHT);
        display.setFont(Font.font("Consolas", 28));
        display.setStyle("-fx-background-color: #1E1E1E; -fx-text-fill: white; " +
                "-fx-background-radius: 12; -fx-border-radius: 12; -fx-border-color: #333;");
        display.setPrefHeight(60);

        ScrollPane scrollPane = new ScrollPane(display);
        scrollPane.setFitToWidth(true);
        scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
        scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
        scrollPane.setStyle("-fx-background-color: transparent; -fx-border-color: transparent;");

        GridPane grid = new GridPane();
        grid.setHgap(8);
        grid.setVgap(8);
        grid.setAlignment(Pos.CENTER);

        for (int i = 0; i < 4; i++) {
            ColumnConstraints col = new ColumnConstraints();
            col.setHgrow(Priority.ALWAYS);
            grid.getColumnConstraints().add(col);
        }

        grid.add(scrollPane, 0, 0, 4, 1);

        // Ziffernbuttons
        Button[] zahlenButtons = new Button[10];
        for (int i = 0; i <= 9; i++) {
            int num = i;
            zahlenButtons[i] = createButton(String.valueOf(num), "#F0F0F0", "#000");
            zahlenButtons[i].setOnAction(e -> handleInput(String.valueOf(num)));
            buttonMap.put(String.valueOf(num), zahlenButtons[i]);
        }

        // Operatoren + "=" + "C"
        String[] ops = {"+", "-", "*", "/", "="};
        for (String op : ops) {
            Button btn = createButton(op, "#FF9500", "#fff");
            btn.setOnAction(e -> handleInput(op));
            buttonMap.put(op, btn);
        }

        Button cButton = createButton("C", "#FF3B30", "#fff");
        cButton.setOnAction(e -> display.setText(""));
        buttonMap.put("C", cButton);

        // Buttons im Grid
        grid.add(zahlenButtons[7], 0, 1);
        grid.add(zahlenButtons[8], 1, 1);
        grid.add(zahlenButtons[9], 2, 1);
        grid.add(buttonMap.get("+"), 3, 1);

        grid.add(zahlenButtons[4], 0, 2);
        grid.add(zahlenButtons[5], 1, 2);
        grid.add(zahlenButtons[6], 2, 2);
        grid.add(buttonMap.get("-"), 3, 2);

        grid.add(zahlenButtons[1], 0, 3);
        grid.add(zahlenButtons[2], 1, 3);
        grid.add(zahlenButtons[3], 2, 3);
        grid.add(buttonMap.get("*"), 3, 3);

        grid.add(zahlenButtons[0], 1, 4);
        grid.add(buttonMap.get("="), 2, 4);
        grid.add(buttonMap.get("/"), 3, 4);
        grid.add(buttonMap.get("C"), 0, 4);

        Scene scene = new Scene(grid, 380, 500, Color.web("#121212"));
        scene.getRoot().requestFocus();
        scene.setOnKeyPressed(e -> handleKeyPress(e.getCode()));

        primaryStage.setScene(scene);
        primaryStage.setResizable(false);
        primaryStage.show();
    }

    private Button createButton(String text, String bgColor, String textColor) {
        Button btn = new Button(text);
        btn.setPrefSize(75, 75);
        btn.setFont(Font.font("Consolas", 22));
        btn.setStyle(
                "-fx-background-color: " + bgColor + ";" +
                "-fx-text-fill: " + textColor + ";" +
                "-fx-background-radius: 15;" +
                "-fx-border-radius: 15;" +
                "-fx-border-color: #333;"
        );
        return btn;
    }

    private void handleInput(String input) {
        String current = display.getText();

        if ("+-*/".contains(input)) {
            if (!current.isEmpty()) {
                String last = current.substring(current.length() - 1);
                if ("+-*/".contains(last)) {
                    display.setText(current.substring(0, current.length() - 1) + input);
                    return;
                }
            } else return;
        }

        if ("=".equals(input)) {
            calculateResult();
            return;
        }

        display.appendText(input);
    }

    private void calculateResult() {
        try {
            String text = display.getText();
            if (text.isEmpty()) return;

            String operator = "";
            int opIndex = -1;
            for (int i = 0; i < text.length(); i++) {
                char c = text.charAt(i);
                if ("+-*/".indexOf(c) >= 0) {
                    operator = String.valueOf(c);
                    opIndex = i;
                    break;
                }
            }

            if (operator.isEmpty() || opIndex <= 0 || opIndex >= text.length() - 1) return;

            BigDecimal a = new BigDecimal(text.substring(0, opIndex));
            BigDecimal b = new BigDecimal(text.substring(opIndex + 1));

            BigDecimal result = func.berechne(a.toString(), b.toString(), operator);

            String resultStr = result.stripTrailingZeros().toPlainString();

            // E-Notation wenn länger als 12 Zeichen
            if (resultStr.length() > 12) {
                resultStr = result.stripTrailingZeros().toEngineeringString();
            }

            display.setText(resultStr);

        } catch (Exception e) {
            display.setText("Error");
        }
    }

    private void simulateButtonPress(Button btn) {
        if (btn == null) return;
        btn.arm();
        btn.fire();
        PauseTransition pt = new PauseTransition(Duration.millis(120));
        pt.setOnFinished(e -> btn.disarm());
        pt.play();
    }

    private void handleKeyPress(KeyCode code) {
        switch (code) {
            case DIGIT0, NUMPAD0 -> simulateButtonPress(buttonMap.get("0"));
            case DIGIT1, NUMPAD1 -> simulateButtonPress(buttonMap.get("1"));
            case DIGIT2, NUMPAD2 -> simulateButtonPress(buttonMap.get("2"));
            case DIGIT3, NUMPAD3 -> simulateButtonPress(buttonMap.get("3"));
            case DIGIT4, NUMPAD4 -> simulateButtonPress(buttonMap.get("4"));
            case DIGIT5, NUMPAD5 -> simulateButtonPress(buttonMap.get("5"));
            case DIGIT6, NUMPAD6 -> simulateButtonPress(buttonMap.get("6"));
            case DIGIT7, NUMPAD7 -> simulateButtonPress(buttonMap.get("7"));
            case DIGIT8, NUMPAD8 -> simulateButtonPress(buttonMap.get("8"));
            case DIGIT9, NUMPAD9 -> simulateButtonPress(buttonMap.get("9"));

            case ADD -> simulateButtonPress(buttonMap.get("+"));
            case SUBTRACT -> simulateButtonPress(buttonMap.get("-"));
            case MULTIPLY -> simulateButtonPress(buttonMap.get("*"));
            case DIVIDE -> simulateButtonPress(buttonMap.get("/"));
            case ENTER, EQUALS -> simulateButtonPress(buttonMap.get("="));

            case BACK_SPACE -> {
                String current = display.getText();
                if (!current.isEmpty()) display.setText(current.substring(0, current.length() - 1));
            }
            default -> {}
        }
    }
}

Klasse Function:

Java:
package taschenrechner;

import java.math.BigDecimal;

public class Function {

    public BigDecimal berechne(String aStr, String bStr, String operator) {
        BigDecimal a = new BigDecimal(aStr);
        BigDecimal b = new BigDecimal(bStr);

        return switch (operator) {
            case "+" -> a.add(b);
            case "-" -> a.subtract(b);
            case "*" -> a.multiply(b);
            case "/" -> b.compareTo(BigDecimal.ZERO) != 0
                    ? a.divide(b, 10, BigDecimal.ROUND_HALF_UP)
                    : BigDecimal.ZERO;
            default -> BigDecimal.ZERO;
        };
    }
}

Gruß
 
Nutze einen Debugger, setze einen vernünftigen Breakpoint (z.B. Zeile 8 in Function, oder auch schon früher, Zeile 153 in GuiFX, oder ganz wo anders...), bei dem deine Anwendung "stoppen" soll und wann du dann schrittweise weiter ausführen willst. Damit kannst du in Echtzeit sehen, was passiert.
 
  • Gefällt mir
Reaktionen: BeBur
Aus der Hüfte ohne den ganzen Code gelesen zu haben. Unterscheidest Du zwischen RETURN und ENTER?
 
TorenAltair schrieb:
Du zwischen RETURN und ENTER?
Ja. Die RETURN Taste ist ja einprogrammiert, funktioniert ja auch. Ich kann die Ziffern einzeln löschen. (Später möchte ich noch STRG A und so weiter reinmachen, um alles auf einmal löschen zu können)

Nur mit der ENTER Taste stimmt irgendwas nicht
 
ich habe schon lang kein Java mehr gemacht und hab nun auch nur eine Vermutung. Überprüfe mal die Zeilen 143 bis 148. Ich schätze mal Input ist ungleich „=„ und er fügt dort einfach den Input zum Display hinzu.
 
Grede schrieb:
Überprüfe mal die Zeilen 143 bis 148. Ich schätze mal Input ist ungleich „=„ und er fügt dort einfach den Input zum Display hinzu.
Mit einem Debugger könnte man das sehr schnell prüfen, und müsste nicht raten.
 
  • Gefällt mir
Reaktionen: Yogi666, kali-hi und Grede
Problem:

Habs eben fix debuggt. Beim Drücken von Enter wird GuiFX#handleKeyPress nicht aufgerufen. Muss also etwas mit einem fehlenden Fokus auf der Scene zu tun haben.

Wenn du den .requestFocus() aus Zeile 108 hinter den .show() aus Zeile 113 setzt, dann funktioniert die Enter-Taste korrekt.

Java:
        primaryStage.setScene(scene);
        primaryStage.setResizable(false);
        primaryStage.show();
        scene.getRoot().requestFocus();
 
Zuletzt bearbeitet: (hab den original-post nicht richtig gelesen.)
  • Gefällt mir
Reaktionen: vram78 und TorenAltair
Mag sein, erfüllt aber trotzdem seinen Zweck als einfacher Einstieg in die Welt der UI-Programmierung. Deklarative Erstellung einer UI mit property Binding und MVVM sind Konzepte, die immer noch state-of-the Art sind (z. B. in Vaadin, ZK (Java) oder Blazor (C#)).

Einem Programmier-Anfänger gleich auch noch eine Frontend -Technologie wie Angular vor die Füße zu knallen bevor das Backend sitzt, wird wohl sehr schnell zu Frustration führen. Mag für Leute mit JS/TS Vorwissen etwas anders sein aber gerade als niedrigschwelliger Einstieg für blutige Anfänger scheint es mir zu taugen (hab es selbst nie benutzt).
 
  • Gefällt mir
Reaktionen: Bob.Sponge
@vram78 Er meint damit nicht Java, er meint damit JavaFX. JavaFX ist ein Framework von Java.
Ergänzung ()

Bob.Sponge schrieb:
Was immer wieder kolportiert wird ist, das GUI-Entwicklung unter Java quasi nicht mehr Existent ist.
Das trifft meiner Meinung aber nicht nur auf Java zu... immer wird egal welche Sprache auf Web Anwendungen verwiesen und dann als Frontend meist React oder Angular... was nicht immer die Lösung für alles ist ;)
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: kali-hi und Bob.Sponge
kali-hi schrieb:
Das ist nicht mehr zeitgemäß...
Diese Aussage ist in ihrer Absolutheit absoluter Unsinn.

JavaFX wird fleissig weiter entwickelt - aktuell neuestes stable Release 24.0.2 (Juni 2025).

Wenn etwas veraltet wäre, dürfte es Swing sein. Meines Wissens gibt es da nur noch Bugfixes. Und auch das heißt nicht, dass Swing nicht mehr zu gebrauchen wäre. Immerhin baut JetBrains seine IDEs auf der Grundlage von Swing, immer noch.

Was immer wieder kolportiert wird ist, das GUI-Entwicklung unter Java quasi nicht mehr Existent ist. Für jemanden der aber eine GUI-Anwendung mit Java bauen möchte, ist es dennoch nachwievor sehr gut möglich, ganz gleich ob mit Swing oder JavaFX.

Wäre ja auch albern für einen kleinen Taschenrechner 'mal eben' eine komplette Spring-Anwendung zu zimmern.. würde ich meinen.
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: Yogi666 und User38
User38 schrieb:
@vram78 Er meint damit nicht Java, er meint damit JavaFX. JavaFX ist ein Framework von Java.
Ergänzung ()


Das trifft meiner Meinung aber nicht nur auf Java zu... immer wird egal welche Sprache auf Web Anwendungen verwiesen und dann als Frontend meist React oder Angular... was nicht immer die Lösung für alles ist ;)

C# geht da einen schönen Mittelweg. Dort gibt es mit Blazor ein sehr mächtiges Frontend-Modul, das eine nahtlose Anwendung von C# Objekten sowohl im Backend-, als auch im Frontend erlaubt (Client-Server-Fusion). Frontend kann in Blazor mit einer Kombination aus C# und HTML Tags geschrieben werden. Man kann direkt im Frontend auf z. B. Listen des Backends zugreifen. Das ist mega bequem. Rest-Endpoints wie z. B. für Angular oder sonstige Drittanbieter Frontends werden nicht benötigt.

Man schreibt zwar eine Webanwendung, hat aber die nahtlose Einbindung ins Backend, wie das bei Swing/AWT/JavaFX auch der Fall ist.

Java bot das auch einmal vor Urzeiten in Form von JavaServerFaces (JSF), das ist aber mittlerweile total veraltet und nur noch ein absolutes Nischenprodukt.
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: Bob.Sponge und User38
d00d schrieb:
Java bot das auch einmal vor Urzeiten in Form von JavaServerFaces (JSF), das ist aber mittlerweile total veraltet und nur noch ein absolutes Nischenprodukt.
Auch das ist bisschen Ansichtssache. Es gibt z.B. mit PrimeFaces eine immer noch aktuell weiterentwickelte Implementierung von JSF:
https://www.primefaces.org/

Damit habe ich beruflich jahrelang gearbeitet, das ist gerade mal wenige Jahre her. Und zwar waren das mehrere Projekte im öffentlichen Dienst.

Beispiel, das Bewerbungsportal des Landes NRW ist mit PrimeFaces umgesetzt:
https://bewerbung-nrw.de/BVPlus
 
  • Gefällt mir
Reaktionen: d00d, User38, Bob.Sponge und eine weitere Person
vram78 schrieb:
und vor allen Dingen AWT ist doch noch älter
Swing basiert quasi auf AWT. Gegenüber FX ist es robust, also nicht so fehleranfällig, und wurde "damals" grundsolide/sauber implementiert (extreme diligent). Dass heute nur noch Bugs gefixt werden (so es welche gibt...), liegt neben der Robustheit auch ein wenig daran, dass man ältere Java-Anwendungen nicht zerstören will, also auch die Abwärtskompatibilität beibehalten will (eine wichtige Eigenschaft in der SE).

Mit Swing hättest du diese ganzen oben genannten Focus-Listener/-Request-Baustellen nicht... Nur, wie schon gesagt, die UIs fühlen sich vielleicht ein wenig altbacken an (also sehen nicht mehr ganz so hübsch aus).

Also, ich würde Swing als günstige "Alternative" zu FX sehen. Aber letztendlich entscheidest du
 
Die JavaFX Diskussion, bzw. ob es veraltet sei. Die wichtige Lektion an der Stelle ist, dass es zu jedem Ansatz Nörgler gibt. Gerade wenn diese Nörgeln ohne Quellen zur Aussage kommt und erst garnicht, oder nur nach längeren Triraden tragbare Gegenvorschläge gemacht werden, gehört sowas ignoriert.
Gerade als Anfänger geht es so oder so darum Prinzipien zu lernen und die sind bei den meisten Frameworks für GUIs zumindest ähnlich.

Anbei Kommentare im Code, orientiert an Javadoc /**[...] */.
Java:
package taschenrechner;

import javafx.animation.PauseTransition;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import javafx.util.Duration;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

public class GuiFX extends Application {

    private TextField display;
    private final Map<String, Button> buttonMap = new HashMap<>();
    private final Function func = new Function();

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

    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("Taschenrechner");

        display = new TextField();
        display.setEditable(false);
        display.setFocusTraversable(false);
        display.setAlignment(Pos.CENTER_RIGHT);
        display.setFont(Font.font("Consolas", 28));
        display.setStyle("-fx-background-color: #1E1E1E; -fx-text-fill: white; " +
                "-fx-background-radius: 12; -fx-border-radius: 12; -fx-border-color: #333;");
        display.setPrefHeight(60);

        ScrollPane scrollPane = new ScrollPane(display);
        scrollPane.setFitToWidth(true);
        scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
        scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
        scrollPane.setStyle("-fx-background-color: transparent; -fx-border-color: transparent;");

        GridPane grid = new GridPane();
        grid.setHgap(8);
        grid.setVgap(8);
        grid.setAlignment(Pos.CENTER);

        /** Verwenden von Schleifen zum Anlegen von Elementen ist gut, auch das Definieren von Operatioren im Array ops[] */       
        for (int i = 0; i < 4; i++) {
            ColumnConstraints col = new ColumnConstraints();
            col.setHgrow(Priority.ALWAYS);
            grid.getColumnConstraints().add(col);
        }

        grid.add(scrollPane, 0, 0, 4, 1);

        // Ziffernbuttons
        Button[] zahlenButtons = new Button[10];
        for (int i = 0; i <= 9; i++) {
            int num = i;
            zahlenButtons[i] = createButton(String.valueOf(num), "#F0F0F0", "#000");
            zahlenButtons[i].setOnAction(e -> handleInput(String.valueOf(num)));
            buttonMap.put(String.valueOf(num), zahlenButtons[i]);
        }

        // Operatoren + "=" + "C"
        String[] ops = {"+", "-", "*", "/", "="};
        for (String op : ops) {
            Button btn = createButton(op, "#FF9500", "#fff");
            btn.setOnAction(e -> handleInput(op));
            buttonMap.put(op, btn);
        }

        Button cButton = createButton("C", "#FF3B30", "#fff");
        cButton.setOnAction(e -> display.setText(""));
        buttonMap.put("C", cButton);

        // Buttons im Grid
        /** Gerade so schön Schleifen gebaut und jetzt die Anordnung in einzeln ausgeschriebenen Zeilen.
        * Pack das Definieren und Anordnen der Elemente in sinnvoll verschachtelte Schleifen */
        grid.add(zahlenButtons[7], 0, 1);
        grid.add(zahlenButtons[8], 1, 1);
        grid.add(zahlenButtons[9], 2, 1);
        grid.add(buttonMap.get("+"), 3, 1);

        grid.add(zahlenButtons[4], 0, 2);
        grid.add(zahlenButtons[5], 1, 2);
        grid.add(zahlenButtons[6], 2, 2);
        grid.add(buttonMap.get("-"), 3, 2);

        grid.add(zahlenButtons[1], 0, 3);
        grid.add(zahlenButtons[2], 1, 3);
        grid.add(zahlenButtons[3], 2, 3);
        grid.add(buttonMap.get("*"), 3, 3);

        grid.add(zahlenButtons[0], 1, 4);
        grid.add(buttonMap.get("="), 2, 4);
        grid.add(buttonMap.get("/"), 3, 4);
        grid.add(buttonMap.get("C"), 0, 4);

        Scene scene = new Scene(grid, 380, 500, Color.web("#121212"));
        scene.getRoot().requestFocus();
        scene.setOnKeyPressed(e -> handleKeyPress(e.getCode()));

        primaryStage.setScene(scene);
        primaryStage.setResizable(false);
        primaryStage.show();
    }

        /** Das ist was für die Zukunft, aber Styles/Designs würde ich nach Möglichkeit 
        * immer separat definieren (Javafx konnte glaub auch mit CSS). */
    private Button createButton(String text, String bgColor, String textColor) {
        Button btn = new Button(text);
        btn.setPrefSize(75, 75);
        btn.setFont(Font.font("Consolas", 22));
        btn.setStyle(
                "-fx-background-color: " + bgColor + ";" +
                "-fx-text-fill: " + textColor + ";" +
                "-fx-background-radius: 15;" +
                "-fx-border-radius: 15;" +
                "-fx-border-color: #333;"
        );
        return btn;
    }

    private void handleInput(String input) {
        String current = display.getText();

        if ("+-*/".contains(input)) {
            if (!current.isEmpty()) {
                String last = current.substring(current.length() - 1);
                if ("+-*/".contains(last)) {
                    display.setText(current.substring(0, current.length() - 1) + input);
                    return;
                }
            } else return;
        }

        if ("=".equals(input)) {
            calculateResult();
            return;
        }

        display.appendText(input);
    }

    private void calculateResult() {
        /** So richtig erkenne ich nicht, wieso hier überhaupt try genutzt wird. 
        * Der Fehlerfall, dass das Eingabefeld leer ist, fängst du ja
        * im Code ab. Für welche Fehlerfälle soll das "try" noch herhalten?
        */
        try {
            String text = display.getText();
            if (text.isEmpty()) return;

            String operator = "";
            int opIndex = -1;
            for (int i = 0; i < text.length(); i++) {
                char c = text.charAt(i);
                if ("+-*/".indexOf(c) >= 0) {
                    operator = String.valueOf(c);
                    opIndex = i;
                    break;
                }
            }
            /** ? Diese Fehlerbehandlung erscheint mir exessiv. 
            * An sich hast du bereits ein Array "ops" definiert und könntest schlicht prüfen, 
            * ob die Inhalte von ops[] mehr als !=1 in "text" auftauchen. Wenn dem der Fall ist,
            * kann dein Programm ein Fehler werfen. Sinnvoller wäre aber Imho das bereits bei der Eingabe
            * abzufangen. */
            if (operator.isEmpty() || opIndex <= 0 || opIndex >= text.length() - 1) return;

            BigDecimal a = new BigDecimal(text.substring(0, opIndex));
            BigDecimal b = new BigDecimal(text.substring(opIndex + 1));

            /** Du hast a und b gerade als BigDecimal definiert und einen Typecast von String zu 
            * BigDec vollführt. Wieso erfolgt jetzt sofort der Typcast BigDec zu String, um diesen Typecast
            * in der Methode berechne() wieder zu revidieren? 
            BigDecimal result = func.berechne(a.toString(), b.toString(), operator);

            /** Anstatt die Länge von result als String zu messen, du hast sowieso Zahlen. Vergleiche doch
            * die! Grob sollte result / 10^12 >= 1 und result * 10^12 >=1 der Wertebereich sein, der ohne
            * Exponentenschreibweise gewünscht ist (sollte getestet werden, of by one passiert ja schnell)
            * Ungarische Notation ist oftmals unbeliebt (resultStr) */
            String resultStr = result.stripTrailingZeros().toPlainString();

            // E-Notation wenn länger als 12 Zeichen
            if (resultStr.length() > 12) {
                resultStr = result.stripTrailingZeros().toEngineeringString();
            }
            /** an sich sollte nur hier BigDec to String gecastet werden */
            display.setText(resultStr);

        } catch (Exception e) {
            display.setText("Error");
        }
    }

    private void simulateButtonPress(Button btn) {
        if (btn == null) return;
        btn.arm();
        btn.fire();
        PauseTransition pt = new PauseTransition(Duration.millis(120));
        pt.setOnFinished(e -> btn.disarm());
        pt.play();
    }

   /** Uhhh, wie wäre es mit Keypress in Char umwandeln, prüfen ob dieser Char ne Ziffer oder in ops[] enthalten ist anstatt langweiligem copy&paste? :) */
    private void handleKeyPress(KeyCode code) {
        switch (code) {
            case DIGIT0, NUMPAD0 -> simulateButtonPress(buttonMap.get("0"));
            case DIGIT1, NUMPAD1 -> simulateButtonPress(buttonMap.get("1"));
            case DIGIT2, NUMPAD2 -> simulateButtonPress(buttonMap.get("2"));
            case DIGIT3, NUMPAD3 -> simulateButtonPress(buttonMap.get("3"));
            case DIGIT4, NUMPAD4 -> simulateButtonPress(buttonMap.get("4"));
            case DIGIT5, NUMPAD5 -> simulateButtonPress(buttonMap.get("5"));
            case DIGIT6, NUMPAD6 -> simulateButtonPress(buttonMap.get("6"));
            case DIGIT7, NUMPAD7 -> simulateButtonPress(buttonMap.get("7"));
            case DIGIT8, NUMPAD8 -> simulateButtonPress(buttonMap.get("8"));
            case DIGIT9, NUMPAD9 -> simulateButtonPress(buttonMap.get("9"));

            case ADD -> simulateButtonPress(buttonMap.get("+"));
            case SUBTRACT -> simulateButtonPress(buttonMap.get("-"));
            case MULTIPLY -> simulateButtonPress(buttonMap.get("*"));
            case DIVIDE -> simulateButtonPress(buttonMap.get("/"));
            case ENTER, EQUALS -> simulateButtonPress(buttonMap.get("="));

            case BACK_SPACE -> {
                String current = display.getText();
                if (!current.isEmpty()) display.setText(current.substring(0, current.length() - 1));
            }
            default -> {}
        }
    }
}

Klasse Function:

Java:
package taschenrechner;

import java.math.BigDecimal;

public class Function {

    public BigDecimal berechne(String aStr, String bStr, String operator) {
        BigDecimal a = new BigDecimal(aStr);
        BigDecimal b = new BigDecimal(bStr);
       
       /** Immer wenn es in den Fingern juckt switch-case Stamements zu schreiben sollte folgender
      * Gedanke kommen: "Geht das eleganter?". Sehr oft ist die Antwort JA! :)
      * Siehe weiter unten im Post für Beispielcode */

        return switch (operator) {
            case "+" -> a.add(b);
            case "-" -> a.subtract(b);
            case "*" -> a.multiply(b);
            case "/" -> b.compareTo(BigDecimal.ZERO) != 0
                    ? a.divide(b, 10, BigDecimal.ROUND_HALF_UP)
                    : BigDecimal.ZERO;
            default -> BigDecimal.ZERO;
        };
    }
}

Beispiel hat mir ChatGPT erzeugt, ich nenne es Faulheit :)
Du kanst Maps anlegen anstatt switch-case Blöcke zu schreiben. Tendenziell kannst du dir dann auch ne gescheite Datenstruktur definieren, und hast folgend weniger arbeit. Also grob sowas wie ops[][] wobei im 0. Index die Chars enthalten sind und im ersten Index die zugehörigen Methoden. Der Vorteil des Ganzen ist dann, dass die Erweiterung des Programms dann vergleichsweise wenig Arbeit macht. Potenzrechnung ist die Erweiterung von ops[][] um einen Eintrag (und Gefummel beim Grid). Das hätte auch den Vorteil, dass die Eingabeprüfung, auch nur gegen den 0ten Index von ops[][] prüfen müsste.
Code:
import java.util.HashMap;
import java.util.Map;

public class CharMethodCaller {

    public static void main(String[] args) {
        char c = 'A'; // Example char input
        callMethodBasedOnChar(c);
    }

    public static void callMethodBasedOnChar(char c) {
        // Map each char to a method (as Runnable)
        Map<Character, Runnable> methodMap = new HashMap<>();
        methodMap.put('A', CharMethodCaller::methodA);
        methodMap.put('B', CharMethodCaller::methodB);
        methodMap.put('C', CharMethodCaller::methodC);

        // Call the corresponding method or a default if not found
        Runnable method = methodMap.get(c);
        if (method != null) {
            method.run();
        } else {
            System.out.println("Unknown char: " + c);
        }
    }

    public static void methodA() {
        System.out.println("Method A called!");
    }

    public static void methodB() {
        System.out.println("Method B called!");
    }

    public static void methodC() {
        System.out.println("Method C called!");
    }
}


Dein eigentliches Problem, was falsch läuft leuchtet mir nicht sofort ein. Brakepoint an void handleKeyPress(KeyCode code) wäre mein Ansatz. An sich sollte Javafx Return und Enter als Keycode "ENTER" interpretieren. Nach [1] gibt es keinen Untschied zwischen Return, Enter und/oder Numpad_Enter.

[1] https://javadoc.io/doc/org.openjfx/...vafx.graphics/javafx/scene/input/KeyCode.html
 
  • Gefällt mir
Reaktionen: Bob.Sponge und vram78
Zurück
Oben