Taschenrechner in Java mit GUI verbinden?
Ich habe einen Taschenrechner gebaut. Keinen einfachen 1+1 Taschenrechner, sondern einen, wo man z.b. (2+2)/2+2 eingeben kann.
Gelöst habe ich das, indem man dem Taschenrechner jede stelle der Gleichung übergibt. Also drückt man Taste "+" übergibt man ihm den Operator, welcher die Addition vollführt.
Als GUI will ich JavaFX verwenden, frage mich dabei aber, wie ich die Struktur des GUIs Aufbauen muss, bzw sollte.
Gibts da ein Pattern welches leicht und gut dafür passt?
2 Antworten
(...) wie ich die Struktur des GUIs Aufbauen muss, bzw sollte.
Halte die grafische Oberfläche einfach und ordne die Komponenten in einem visuellen Grid. Orientiere dich am besten an üblichen Rechneranwendungen (so wie bei dem von Windows). Oben ist das Textfeld mit der Rechnung und dem Ergebnis, darunter werden die einzelnen Operationen angeordnet. Wenn es sich nur auf einen Berechne-jetzt-Button beschränkt (so verstehe ich deine Beschreibung jedenfalls), kann der vermutlich auch direkt rechts neben das Eingabefeld und deine grafische Oberfläche fasst somit nur eine einzige Zeile.
Für die jeweiligen Komponenten (Textfeld, Button, u.ä.) stellt JavaFX bereits eigene Komponenten, die du nutzen kannst. Für die Anordnung der Komponenten solltest du Layout Container einsetzen. In JavaFX gibt es schon einige vordefinierte Optionen (siehe hier oder hier), die sich wiederum schachteln lassen (= Composite Pattern).
Gibts da ein Pattern welches leicht und gut dafür passt?
Hierbei geht es dir wohl nicht um die Struktur der GUI, sondern eher um die Architektur deiner gesamten Anwendung.
Grundsätzlich ist eine Trennung der Datenebene von dem View zu bevorzugen. In Kombination mit FXML (und Properties, Bindings, Binding Expressions) kann man sich ein Gerüst nach MVVM aufbauen. Da dies, wenn man die Informationen aus deinen vorherigen Fragen mit einbezieht, nicht infrage kommt, wäre die klassische Trennung via MVC die Wahl. Für eine einfache Oberfläche, die eh nur ein paar Textfelder und Buttons fasst, ist das auch völlig ausreichend.
Du hast also eine View-Klasse, in der die Oberfläche zusammengebaut wird. Bei komplexeren, verschachtelten Layouts macht es Sinn, sich den Aufbau in unterschiedliche Methoden auszulagern. Also nur einmal als angedeutetes Beispiel:
private void init() {
var topBar = getTopBar();
var mainArea = getMainArea();
var statusBar = getStatusBar();
var stackPane = new StackPane();
stackPane.getChildren().addAll(topBar, mainArea, statusBar);
// etc. ...
}
private HBox getTopBar() {
/* ... */
}
private GridPane getMainArea() {
/* ... */
}
private HBox getStatusBar() {
/* ... */
}
Das Anlegen gleichartiger Komponenten (bei einem Rechner wären das bspw. Buttons für die Ziffern) lässt sich ebenfalls in abstraktere Helfermethoden auslagern.
private Button getButton(String title, String colorHexCode, /* etc. */) {
Button button = new Button(title);
button.setStyle("-fx-background-color: " + colorHexCode + ";");
/* ... */
return button;
}
Wenn sich die Klasse dadurch extrem aufblähen sollte, wären zusätzliche Klassen sinnvoll, die einzelne Komponenten / Oberflächenbereiche repräsentieren.
Bezüglich der Controller können anonyme EventHandler-Klassen oft schon ausreichen, wenn die Logik, die sie ausführen sollen, in wenigen Code-Zeilen formulierbar ist. Da Java auch Lambdas als sprachliches Mittel unterstützt, lässt sich so eine Anweisung auch ziemlich kurz schreiben:
button.setOnAction(event -> System.out.println("Clicked"));
Oder mit mehreren Zeilen:
button1.setOnAction(event -> {
/* ... */
});
Ab ungefähr vier Zeilen würde ich die Logik jedoch auslagern.
Bei einem Rechner könnte so ein Handler so aussehen:
class View {
private Calculator calculator;
private TextField numberField;
public View(Calculator calculator) {
this.calculator = calculator;
init();
}
private void init() {
// build GUI ...
Button addButton = new Button("+");
addButton.setOnAction(event -> {
double number = Double.valueOf(numberField.getValue());
calculator.add(number);
});
// ...
}
}
Und damit komme ich auch schon zu der Beschreibung des Datenmodells, welches durch eine Calculator-Instanz repräsentiert wird. Der Controller übergibt die Daten der Oberfläche nur weiter an das Model. Dieses wiederum kann die Daten verarbeiten.
Damit das View danach noch eine Information erhält, dass sich das Ergebnis geändert hat, welches vom Calculator berechnet wurde, kann es sich als Listener an dieses Objekt anhängen (Stichwort: Observer Pattern). Wie ein PropertyChangeListener implementiert werden kann, wird in den Oracle Tutorials gezeigt. Sobald der Änderungshinweis eingetrudelt ist, kann das View diesen auf seiner Oberfläche (in einem Label o.ä.) anzeigen.
Also drückt man Taste "+" übergibt man ihm den Operator, welcher die Addition vollführt.
Sicher dass das die richtige Methode ist? Wenn ich 2+3*5 eingeben würde, würde er ja dann erst 2+3 und erst dann *5 rechnen, also Punkt vor Strich nicht beachten.
Tschuldige, dann hatte ich deine Frage falsch interpretiert.
Merke gerade, dass man das wirklich falsch interpretieren kann. Aber er beachtet schon Strich vor Punkt, sowie Klammern etc
Hab ich doch schon erklärt, er hält alle mathematischen regeln ein.
https://ibb.co/98XL4ms hier nochmal :D
Nein, er übergibt den Operator nur. Sobald solve() aufgerufen wird berechnet er es. Du kannst ja bei Eingabe nicht wissen ob er das schon berechnen darf. Er wird also nur in einer Liste gespeichert