JavaFX mini Taschenrechner!

ocsme

Top Contributor
Guten Tag,

ich versuche einen mini Taschenrechner zu Programmieren. Es sollen eigentlich nur 2 Zahlen über ein TextField eingetragen werden und sobald man auf den Button "berechne" klickt soll das Ergebnis raus kommen.

Meine Probleme damit sind:
- Wie sage ich dem TextField das es sich um Integer oder Double Werte handelt? Ich dachte an so etwas!
Code:
        TextField a = new TextField();
          a.setOnAction((ActionEvent event) -> {
                try{
                    Integer i = Integer.parseInt(a.getText());
                }catch (NumberFormatException e){
                  
                }
            });

- Wie sage ich dann dem Button "berechne" ob Addiert oder Subtrahiert werden soll? Und wie bekomme ich dann die Integer oder Double Werte in diese Methode?

Das Programm sieht bis jetzt so aus:
Java:
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import javafx.scene.layout.GridPane;




public class Taschenrechner extends Application {
    
    public void start(Stage primaryStage) {
        ObservableList<String> options =
                FXCollections.observableArrayList(
                    "+",
                    "-"
                );
        ComboBox<String> comboBox = new ComboBox<>(options);
        comboBox.setValue("+");
        
        Button button2 = new Button("Berechne");
        TextField a = new TextField();
          a.setOnAction((ActionEvent event) -> {
                try{
                    Integer i = Integer.parseInt(a.getText());
                }catch (NumberFormatException e){
                  
                }
            });
        
        TextField b = new TextField();
        TextField c = new TextField();
        c.setDisable(true);
        GridPane gridPane = new GridPane();
        gridPane.add(new Label("Zahl1"), 0, 0);
        gridPane.add(new Label("Zahl2"), 2, 0);
        gridPane.add(new Label("Ergebnis"), 4, 0);
        gridPane.add(a, 0,1);
        gridPane.add(b, 2,1);
        gridPane.add(c, 4,1);
        gridPane.add(comboBox, 1, 1);
        gridPane.add(button2, 3, 1);
        
        Scene scene = new Scene(gridPane, 700, 80);
        primaryStage.setTitle("Mein Taschenrechner");
        primaryStage.setScene(scene);
        primaryStage.show();
    }
    
    public static void main(String[] args) {
        Application.launch(args);       
    }

}

Kann mir dabei jemand weiter Helfen?

LG
 
So jetzt klappt die Berechnung. Das einzige Problem was ich jetzt habe ist zu erkennen was für ein Typ von Zahl der Benutzer eingeben würde!
Natürlich könnte ich das ganze auch einfach über Strings rechnen 🙂
Doch das gefällt mir nicht. Weiß jemand einen effektiven Weg um aus dem TextField die Zahl herauszubekommen?

Hier jetzt mal mein Code bis jetzt 🙂
Java:
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import javafx.scene.layout.GridPane;

public class Taschenrechner extends Application {
    ComboBox<String> comboBox = new ComboBox<>();
    TextField zahl1 = new TextField();
    TextField zahl2 = new TextField();
    TextField ergebnis = new TextField();
    
    public void start(Stage primaryStage) {
        ObservableList<String> options =
                FXCollections.observableArrayList(
                    "+",
                    "-"
                );
        comboBox.setItems(options);
        comboBox.setValue("+");
        ergebnis.setDisable(true);
        Button button2 = new Button("Berechne");
        button2.setOnAction( (ActionEvent event) -> ergebnis.setText(berechne()));
        
        GridPane gridPane = new GridPane();
        gridPane.add(new Label("Zahl1"), 0, 0);
        gridPane.add(new Label("Zahl2"), 2, 0);
        gridPane.add(new Label("Ergebnis"), 4, 0);
        gridPane.add(zahl1, 0,1);
        gridPane.add(zahl2, 2,1);
        gridPane.add(ergebnis, 4,1);
        gridPane.add(comboBox, 1, 1);
        gridPane.add(button2, 3, 1);
        
        Scene scene = new Scene(gridPane, 700, 80);
        primaryStage.setTitle("Mein Taschenrechner");
        primaryStage.setScene(scene);
        primaryStage.show();
    }
    
    private String berechne() {
        if(comboBox.getValue() == "+") {
            Number n = Integer.parseInt(zahl1.getText()) +     Integer.parseInt(zahl2.getText());
            return n.toString();
        }
        else {
            Number n = Integer.parseInt(zahl1.getText()) -     Integer.parseInt(zahl2.getText());
            return n.toString();
        }
                
            
    }
    
    public static void main(String[] args) {
        Application.launch(args);       
    }

}


Was mir noch nicht wirklich gefällt ist die Auswahl von + und -. Wenn man mehre Funktionalität zur Verfügung stellen möchte also z. B. hier jetzt noch durch *, / und %. Dann muss ich ja für jeden Fall eine if abfrage machen oder geht das auch irgendwie schöner?

LG
 
Wie 'ne Map aussieht? In Java 8 Syntax, z. B.

Java:
    static final Map<String, BiFunction<Number, Number, Number>> binaryOperations = new HashMap<>();

    static {
        binaryOperations.put("+", (a,b) -> a.doubleValue() + b.doubleValue());
        binaryOperations.put("-", (a,b) -> a.doubleValue() - b.doubleValue());
        binaryOperations.put("*", (a,b) -> a.doubleValue() * b.doubleValue());
        binaryOperations.put("/", (a,b) -> a.doubleValue() / b.doubleValue());
    }
 
Wie 'ne Map aussieht? In Java 8 Syntax, z. B.

Wie eine Map aussieht weiß ich ja 😀
Mein Problem war das ich nicht verstanden habe das du alles in eine Map machst 🙂 bzw. das so etwas überhaupt geht 😀

Jetzt habe ich nur immer noch die Frage:
Der Operator ist ja an die ComboBox gebunden muss ich nun comboBox.getValue() abfragen und das dann der Map binaryOperations übergeben?

Sorry ich weiß das sind sicherlich total doofe Fragen!!! Doch wenn man das noch nie gemacht hat ist so etwas echt ätzend 😀

LG
 
Du könntest erst nach Integer parsen und falls das nicht möglich ist, nach double.

Eigentlich wollte ich das TextField nur auf Zahlen beschränken. Hab dazu etwas gegooglet doch leider nicht verstanden.
Denn wenn eine Eingabe so aussehen würde: 23,17 <- ist es eine Zahl aber in Java eben nicht 😀 23.17 müsste dort stehen.
Wenn ich das TextField auf solche Zahlen also mit Punkt und Komma abbilden möchte muss ich das sicherlich alles über Strings rechnen und abfragen? oder?
 
Der Operator ist ja an die ComboBox gebunden muss ich nun comboBox.getValue() abfragen und das dann der Map binaryOperations übergeben?
So in etwa:
Java:
    private String berechne() {
        BiFunction<Number, Number, Number> b = binaryOperations.get(comboBox.getValue());
        if (b != null) {
            return b.apply(Integer.parseInt(zahl1.getText()), Integer.parseInt(zahl2.getText()))
                    .toString();
        }
        return "";
    }
 
auf so etwas komme ich sicherlich nie 🙁

Danke. Werde das mal zusammen bauen und schauen das es läuft 🙂
Der endgültige Taschenrechner Post ich hier dann nochmal 😀

LG
 
12291
Java:
import java.util.*;
import java.util.function.BiFunction;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import javafx.scene.layout.GridPane;




public class Taschenrechner extends Application {
    ComboBox<String> comboBox = new ComboBox<>();
    TextField zahl1 = new TextField();
    TextField zahl2 = new TextField();
    TextField ergebnis = new TextField();
    Map<String, BiFunction<Number, Number, Number>> binaryOperations = new HashMap<>();

     
   
    public void start(Stage primaryStage) {
       
        binaryOperations.put("+", (a,b) -> a.doubleValue() + b.doubleValue());
        binaryOperations.put("-", (a,b) -> a.doubleValue() - b.doubleValue());
        binaryOperations.put("*", (a,b) -> a.doubleValue() * b.doubleValue());
        binaryOperations.put("/", (a,b) -> a.doubleValue() / b.doubleValue());
        comboBox.setItems( (ObservableList<String>) FXCollections.observableArrayList("+","-","*","/"));
        comboBox.setValue("+");
        ergebnis.setDisable(true);
        Button button2 = new Button("Berechne");
        button2.setOnAction( (ActionEvent event) -> ergebnis.setText(berechne()));
       
        GridPane gridPane = new GridPane();
        gridPane.add(new Label("Zahl1"), 0, 0);
        gridPane.add(new Label("Zahl2"), 2, 0);
        gridPane.add(new Label("Ergebnis"), 4, 0);
        gridPane.add(zahl1, 0,1);
        gridPane.add(zahl2, 2,1);
        gridPane.add(ergebnis, 4,1);
        gridPane.add(comboBox, 1, 1);
        gridPane.add(button2, 3, 1);

       
        Scene scene = new Scene(gridPane, 700, 80);
        primaryStage.setTitle("Mein Taschenrechner");
        primaryStage.setScene(scene);
        primaryStage.show();
    }
   
    private String berechne() {
         BiFunction<Number, Number, Number> b = binaryOperations.get(comboBox.getValue());
            if (b != null) {
                return b.apply(Double.parseDouble(zahl1.getText()), Double.parseDouble(zahl2.getText()))
                        .toString();
            }
            return "";          
    }
   
    public static void main(String[] args) {
        Application.launch(args);      
    }

}


So läuft der Rechner doch gar nicht so schlecht. Was mich jetzt noch stört ist das ich im TextField immer noch Buchstaben eingeben kann 😀 aber eins nach dem anderen.

vielleicht kannst du mir nochmal hiermit Helfen mit der Map @mihe7
Java:
Map<String, BiFunction<Number, Number, Number>> binaryOperations = new HashMap<>();

Verstehe ich das richtig? Wir erstellen eine Map mit dem Inhalt (String und BiFunction). Die BiFunction bekommt 2 Number übergeben und return einen Number. Die erforderliche apply Methode aus dem Interface wird durch die Lambda-Ausdrücke redefiniert:
Java:
binaryOperations.put("+", (a,b) -> a.doubleValue() + b.doubleValue());
Da wir oben Number, Number geschrieben haben, sind a und b Number Objekte.

Habe ich das so weit richtig verstanden?
 
auf so etwas komme ich sicherlich nie 🙁
Wobei b als Variablenname jetzt auch nicht der "Hit" ist 🙂

Ansonsten: durch die funktionalen Features kommt man auf Dinge, die man vorher versucht hätte, zu vermeiden. Das geht ja auch alles ohne, ist halt entsprechender Schreibaufwand:

Java:
interface BinaryOperation {
    Number perform(Number n1, Number n2);
}
Java:
class Subtraction implements BinaryOperation {
    public Number perform(Number n1, Number n2) {
        return n1.doubleValue() + n2.doubleValue();
    }
}
und dann die Map anlegen:
Java:
static Map<String, BinaryOperation> binaryOperations = new HashMap<>();
static {
    binaryOperations.put("-", new Subtraction());
    ...
}
und am Schluss dann noch:
Java:
    private String berechne() {
        BinaryOperation op = binaryOperations.get(comboBox.getValue());
        if (op != null) {
            return op.perform(Integer.parseInt(zahl1.getText()), Integer.parseInt(zahl2.getText()))
                    .toString();
        }
        return "";
    }
Das wird dann teilweise ganz schön lang.
 
Eine Frage hätte ich noch. Wie ermittelt man am besten die Layoutmanager? Ist das Übung?
Hier mal ein Beispiel:
12295

Wie könnte solch ein Programm aufgebaut sein?
Hätte jetzt First Name bist Nickname in GridPane also Zeile Spalte unterteilt. doch was macht man dann mit dem Display Format?
Und den Email Teil keine Ahnung rechts die Buttons vielleicht in eine HBox gepackt?

Gibt es da vielleicht eine Faustregel?
LG
 
Am Einfachsten ist es, alle Layouts zu kennen und dann ein Mock-up (oder Vorführmodell) am Reißbrett zu erstellen. 😀

Da Du das Mock-up schon hast, sollte das Layout eigentlich daraus ableitbar sein...
 
Wie ermittelt man am besten die Layoutmanager? Ist das Übung?
Ein gutes Layout ist nicht ganz trivial, wie Du ja schon festgestellt hast. Die Wahl der "LayoutManager" hängt dann in erster Linie vom ... Layout ab 🙂

Hätte jetzt First Name bist Nickname in GridPane also Zeile Spalte unterteilt. doch was macht man dann mit dem Display Format?
GridPane hört sich gut an. Was das "Display format" betrifft: die add-Methode gibt es auch mit colspan...
 
Meinst du das Verbinden von Zeilen und Spalten.
Ja. https://docs.oracle.com/javase/8/ja...e.html#add-javafx.scene.Node-int-int-int-int-

Dann könnte man ja alles in GridPane machen
Vieles.

Das finde ich überhaupt nicht leicht
Ich habe ja geschrieben, dass man ein gutes Layout nicht aus dem Ärmel schüttelt. Das gilt zumindest für etwas komplexere UIs.

Nicht umsonst gibt es Style Guidelines, in denen mehr oder weniger genau beschrieben wird, wie die Oberfläche aussehen sollte. Siehe z. B. https://docs.microsoft.com/en-us/windows/win32/uxguide/vis-layout. Das soll jetzt aber nicht als Referenz gelten, sondern nur zeigen, dass dahinter durchaus einiges an Hirnschmalz stecken kann.
 
Das mit dem Zusammenschmieden versuch ich später mal 🙂
Dann werde ich diese Oberfläche mal noch versuchen zusammen zu bauen.

Jetzt hätte ich noch eine Frage zum Taschenrechner. Ich möchte gerne noch ein Menü oben rein bauen.
Der Code dazu ist dieser:
Java:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class MenuDemo extends Application {

    @Override
    public void start(Stage stage) {

        // Create MenuBar
        MenuBar menuBar = new MenuBar();
       
        // Create menus
        Menu fileMenu = new Menu("File");
        Menu editMenu = new Menu("Edit");
        Menu helpMenu = new Menu("Help");
       
        // Create MenuItems
        MenuItem newItem = new MenuItem("New");
        MenuItem openFileItem = new MenuItem("Open File");
        MenuItem exitItem = new MenuItem("Exit");
       
        MenuItem copyItem = new MenuItem("Copy");
        MenuItem pasteItem = new MenuItem("Paste");
       
        // Add menuItems to the Menus
        fileMenu.getItems().addAll(newItem, openFileItem, exitItem);
        editMenu.getItems().addAll(copyItem, pasteItem);
       
        // Add Menus to the MenuBar
        menuBar.getMenus().addAll(fileMenu, editMenu, helpMenu);
       
        BorderPane root = new BorderPane();
        root.setTop(menuBar);
        Scene scene = new Scene(root, 350, 200);
       
        stage.setScene(scene);
        stage.show();
    }

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

}

Das Menü ist derzeit in einer BorerPane und der Rechner in in der GridPane.
Jetzt muss ich doch noch einen Layoutmanager nehmen und beide Panes drauf packen oder geht das irgendwie auch anders da es ja ein "Menu" ist!?

LG
 
Das scheint unter FX der richtige Weg zu sein, wobei in den Beispielen als Root-Container einfach eine VBox genommen wird.
 
Super geht 🙂
Doch wer soll sich bitte all die Methoden behalten! Verrückt so etwas 😛

Java:
import java.util.*;
import java.util.function.BiFunction;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;

public class Taschenrechner extends Application {
    ComboBox<String> comboBox = new ComboBox<>();
    TextField zahl1 = new TextField();
    TextField zahl2 = new TextField();
    TextField ergebnis = new TextField();
    Map<String, BiFunction<Number, Number, Number>> binaryOperations = new HashMap<>();

    public void start(Stage primaryStage) {
        //Menu
        // Create MenuBar
        MenuBar menuBar = new MenuBar();
       // Create menus
        Menu fileMenu = new Menu("File");
        Menu editMenu = new Menu("Edit");
        Menu helpMenu = new Menu("Help");
        // Create MenuItems
        MenuItem newItem = new MenuItem("New");
        MenuItem openFileItem = new MenuItem("Open File");
        MenuItem exitItem = new MenuItem("Exit");
      
        MenuItem copyItem = new MenuItem("Copy");
        MenuItem pasteItem = new MenuItem("Paste");
        // Add menuItems to the Menus
        fileMenu.getItems().addAll(newItem, openFileItem, exitItem);
        editMenu.getItems().addAll(copyItem, pasteItem);
        // Add Menus to the MenuBar
        menuBar.getMenus().addAll(fileMenu, editMenu, helpMenu);
      
        BorderPane root = new BorderPane();
        root.setTop(menuBar);

        //Taschenrechner
        binaryOperations.put("+", (a,b) -> a.doubleValue() + b.doubleValue());
        binaryOperations.put("-", (a,b) -> a.doubleValue() - b.doubleValue());
        binaryOperations.put("*", (a,b) -> a.doubleValue() * b.doubleValue());
        binaryOperations.put("/", (a,b) -> a.doubleValue() / b.doubleValue());
        comboBox.setItems( (ObservableList<String>) FXCollections.observableArrayList("+","-","*","/"));
        comboBox.setValue("+");
        ergebnis.setDisable(true);
        Button button2 = new Button("Berechne");
        button2.setOnAction( (ActionEvent event) -> ergebnis.setText(berechne()));

        GridPane gridPane = new GridPane();
        gridPane.add(new Label("Zahl1"), 0, 0);
        gridPane.add(new Label("Zahl2"), 2, 0);
        gridPane.add(new Label("Ergebnis"), 4, 0);
        gridPane.add(zahl1, 0,1);
        gridPane.add(zahl2, 2,1);
        gridPane.add(ergebnis, 4,1);
        gridPane.add(comboBox, 1, 1);
        gridPane.add(button2, 3, 1);
        root.setCenter(gridPane);
        Scene scene = new Scene(root, 700, 80);
        primaryStage.setTitle("Mein Taschenrechner");
        primaryStage.setScene(scene);
        primaryStage.show();
    }
    
    private String berechne() {
         BiFunction<Number, Number, Number> b = binaryOperations.get(comboBox.getValue());
            if (b != null) {
                return b.apply(Double.parseDouble(zahl1.getText()), Double.parseDouble(zahl2.getText()))
                        .toString();
            }
            return "";           
    }
    
    public static void main(String[] args) {
        Application.launch(args);       
    }

}


Eine aller Letzte Frage zu diesem Programm hätte ich jetzt noch (sind eigentlich zwei) 😀
Wie bekomme ich jetzt wenn ich das Fenster groß mache die Fenster mit groß? und wie bleibt das Fenster auf der Minimal größe von 700 * 80 Pixel? Denn wenn ich es klein Ziehe geht es bis ich gar nichts mehr sehe 🙁

LG
 
Das mit den Fenstern meine ich heißt property binding?
Wenn ich das Fenster auf Maximal umschalte sollen die Fenster sich auch vergrößern 😀 sieht zwar komisch aus aber das ist erst einmal egal 🙂

LG
 
Meinst Du, dass die Felder sich vergrößern sollen, wenn das Fenster vergrößert wird? Also etwas wie
Java:
ColumnConstraints grow = new ColumnConstraints();
grow.setHgrow(Priority.ALWAYS);
ColumnConstraints normal = new ColumnConstraints();
gridPane.getColumnConstraints().addAll(grow, normal, grow, normal, grow);
 
😀 Genau das meinte ich 🙂

Ich verstehe es zwar nicht! doch das liegt vor allem daran das es soooo viele Methoden und Objekte in JavaFX gibt! Das ist zu viel.

Ein kleines Problem habe ich noch. Was ich meinte mit dem Minimieren ist z. B. wie im FireFox. Wenn ich diesen klein mache hat er eine gewisse Größe. Wie stellt man diese Größe ein? Und er hat eine Minimieren Minimum Größe denn wenn ich Ihn nun an den Ecken klein ziehe geht das bis zu einem gewissen Punkt. Bei meinem Taschenrechner geht das so lange bis alles verschwunden ist.
Lässt sich scher erklären!

LG
 
doch das liegt vor allem daran das es soooo viele Methoden und Objekte in JavaFX gibt!
Man kann im GridPane alles mögliche einstellen. Das liegt vor allem daran, dass Du nicht in die Doku schaust 🙂

Was ich meinte mit dem Minimieren ist z. B. wie im FireFox. Wenn ich diesen klein mache hat er eine gewisse Größe. Wie stellt man diese Größe ein?
Mit "klein machen" meinst Du meinst vermutlich das "Wiederherstellen", nachdem Du zuvor das Fenster maximiert hast. Das dürfte einfach die Größe sein, die das Fenster vor dem Maximieren hatte.

Ansonsten schaust Du Dir am besten auch mal https://docs.oracle.com/javase/8/javafx/api/javafx/stage/Stage.html#setMinHeight-double- & Co. an.
 
Nochmals danke für deine Mühe 🙂 @mihe7
Ja in die Doku schaue ich echt wenig 🙁 mir fehlen dann auch sehr oft die zusammen hänge 🙁

Kennst du ein paar Bücher dazu? Ich hab mal schnell gesucht und vielleicht ist ja das hier ganz gut dafür?

Denn das Thema ist ja sehr schön und wird heute ja eh gebraucht 🙂

lg
 

Zurück
Oben