Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
numberButtons ist aber doch ein Array (von JButton Elementen) und kein JButton.
Das ist wie mit dem Schuhschrank: Nur weil in dem Schuhschrank Schuhe sein können, kannst Du Dir diesen doch nicht anziehen. Du kannst den Schuhschrank doch auch nur dafür nutzen, Schuhe da rein zu tun oder welche raus zu nehmen. Aber du kannst den Schuhschrank nicht dazu nutzen, dass Du diesen anziehst.
Also so wie bei dem Schuchschrank: Wenn Du etwas mit allen Schuhen machen willst (z.B. diese putzen), dann putzt du nicht den Schrank sondern du greifst auf jedes Paar Schuhe im Schrank zu und putzt dann die Schuhe.
numberButtons ist aber doch ein Array (von JButton Elementen) und kein JButton.
Das ist wie mit dem Schuhschrank: Nur weil in dem Schuhschrank Schuhe sein können, kannst Du Dir die doch nicht anziehen. Du kannst den Schuhschrank doch auch nur dafür nutzen, Schuhe da rein zu tun oder welche raus zu nehmen. Aber du kannst den Schuhschrank nicht dazu nutzen, dass Du diese anziehst.
Also so wie bei dem Schuchschrank: Wenn Du etwas mit allen Schuhen machen willst (z.B. diese putzen), dann putzt du nicht den Schrank sondern du greifst auf jedes Paar Schuhe im Schrank zu und putzt dann die Schuhe.
Also ich bezweifle, dass es eine NullPointerException in der Zeile 8 des von dir gezeigten Code gab. Das ist eine for Schleife in der nichts null sein kann.
Daher wäre wichtig, dass Du mal den genauen Code zeigst. Wie erstellst Du das Array? wie füllst Du es?
Und statt im Event den Button heraus zu suchen, kannst Du direkt den Text des Buttons auslesen und hinzu fügen. Denn das ist ja die Zahl, oder nicht?
Wenn Du den Text unabhängig lassen willst, dann wäre ggf. action command (setActionCommand und getActionCommand) oder name (getName / setName) nutzbar.
public void appendNumberButtonTextAction(ActionEvent event) {
for(int i=0;i<numberButtons.length;i++) { //laut Compiler hier
if(event.getSource() == numberButtons[i]) {
display.setText(display.getText().concat(String.valueOf(i)));
}
}
}
Java:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at Frame.appendNumberButtonTextAction(Frame.java:160)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2348)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
at java.awt.Component.processMouseEvent(Component.java:6539)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3324)
at java.awt.Component.processEvent(Component.java:6304)
at java.awt.Container.processEvent(Container.java:2239)
at java.awt.Component.dispatchEventImpl(Component.java:4889)
at java.awt.Container.dispatchEventImpl(Container.java:2297)
at java.awt.Component.dispatchEvent(Component.java:4711)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4904)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4535)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4476)
at java.awt.Container.dispatchEventImpl(Container.java:2283)
at java.awt.Window.dispatchEventImpl(Window.java:2746)
at java.awt.Component.dispatchEvent(Component.java:4711)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:760)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:84)
at java.awt.EventQueue$4.run(EventQueue.java:733)
at java.awt.EventQueue$4.run(EventQueue.java:731)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:730)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:205)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
Ja, String ist eine Klasse und valueOf ist eine statische Methode. Daher liefert das durchaus das, was er erwartet: Einen String der die Variable i wiedergibt. (Also das gleiche wie "" + i oder Interger.toString(i)
Wenn die NPE in der Zeile 2 kommt, dann kann das eigentlich nur daran liegen, dass numberButtons null ist. Wieso das aber der Fall ist, dann ist so aus den Bruchstücken nicht heraus zu lesen.
Wenn die NPE in der Zeile 2 kommt, dann kann das eigentlich nur daran liegen, dass numberButtons null ist. Wieso das aber der Fall ist, dann ist so aus den Bruchstücken nicht heraus zu lesen.
Ja, String ist eine Klasse und valueOf ist eine statische Methode. Daher liefert das durchaus das, was er erwartet: Einen String der die Variable i wiedergibt. (Also das gleiche wie "" + i oder Interger.toString(i)
Wenn die NPE in der Zeile 2 kommt, dann kann das eigentlich nur daran liegen, dass numberButtons null ist. Wieso das aber der Fall ist, dann ist so aus den Bruchstücken nicht heraus zu lesen.
Ok stimmt aber im post #55 sagt er auch das in zeile 8 eine NPE kommt was nicht sein konnte. denn da hatte ers es auf 10 festgelegt..
da stimmt was nicht bei seinen angaben.
public Frame(){
//[...]
// numberButtons bestücken
JButton[] numberButtons = new JButton[10];
Im Konstruktor erzeugst Du eine lokale Variable numberButtons und die initialisierst Du. Die Instanzvariable numberButtons wird somit nie initialisiert.
Was Du da machen wolltest, war bestimmt die Initialisierung der Instanzvariable. Daher musst Du das JButton[] vor der Zuweisung löschen.
Wie wo und wann fügst du den Dezimalpunkt hinzu ?
So das du zu der kompletten eingegangen zahl kommst.
Die du ja dann wider für deine Berechnung brauchst.
Warum das ganze so kompliziert mit einer For Schleife?
Du bekommst doch in dem Listener das Event mit in dem der Text enthalten ist.
Wenn du nun auch dem Dezimalpunk das Zeichen punkt gibst ist das Thema auch gelöst.
Java:
public void appendNumberButtonTextAction(ActionEvent event) {
display.setText(display.getText().concate(event.getActionCommand()));
}
die Eingaben ins Textfeld funktionieren mittlerweile ja alle wie gewollt.
Ich bin jetzt abschließend noch dabei die Rechnung zu implementieren.
Dazu gab es ja schon diverse Vorüberlegungen.
Ich habe jetzt die Hilfsklasse für die Rechnungen:
Java:
public class Calculations {
public double result = 0;
public char operator = '+';
public double operand;
Calculations(){
}
public void calculate( double operand) {
switch (operator) {
case '+':
result += operand;
break;
case '-':
result -= operand;
break;
case '*':
result *= operand;
break;
case '/':
result /= operand;
break;
}
}
}
Den Operanden will ich aus dem ButtonAction Methoden abfragen und in diesen dann auch die calculate() Methode aufrufen.
Java:
public void doAddButtonAction(ActionEvent event){
Calculations.operand = Double.parseDouble(display.getText()); // soll operand holen
display.setText(display.getText().concat("+")); // soll Zeichen ins Textfeld printen
Calculations.calculate(Calculations.operand); // soll rechnen
operator = '+' ; // soll Operator setzen
}
so jetzt , die simple Überlegung.
Die Probleme sind, dass die ButtonAction Methoden in einer anderen Klasse stehen und operand und calculate() laut Compiler static sein müssen.
Gibts dafür noch einen anderen Weg ohne das bisherige Design grundlegend zu verändern?
Ich weiß es gab schon diverse Vorschläge um das ganze anders zu machen, aber ich würde gerne erstmal für Version 1.0 sozusagen, die Sache jetzt mit diesen, nicht perfekten Design lösen und dann später nochmal über eine grundlegende Veränderung nachdenken.
Ich hab jetzt noch ein anderes Problem und zwar undefiniertes Verhalten.
Java:
public class Calculations {
public static double result = 0;
public static char operator = '+';
public static double operand;
Calculations(){
}
public static void calculate( double operand) {
switch (operator) {
case '+':
result += operand;
break;
case '-':
result -= operand;
break;
case '*':
result *= operand;
break;
case '/':
result /= operand;
break;
}
}
}
Wenn ich jetzt z.B 2 + 2 eintippe und dann auf '=' kommt 4 raus. Soweit so gut. Wenn ich dann allerdings weiter rechne mit z.B. +1, also 4+1 kommt 10 raus.
Also scheinbar werden die Variablen nicht nicht richtig beschrieben.
Sieht es jemand wo der Fehler liegt?
Deine Logik stimmt ja auch nicht. Du musst Dir das noch einmal im im Detail überlegen.
Du hast 2+2= gerechnet, also Calculations.operand ist noch immer +, result ist 4.
Nun drückst Du +, also nimmt er den angezeigten Text und ruft calculate auf. Damit wird dann ja 4+4 gerechnet und in result gespeichert.
Im Display steht aber erst einmal 4+
Du musst Dir also wirklich im Detail überlegen, was Da bei jedem Schritt genau gemacht werden soll. Spiel es mit Stift und Papier durch!
Du wirst erst in der Lage sein, ein korrektes Programm zu schreiben, wenn Du jeden Schritt genau verstanden hast. (Mal von Glückstreffern abgesehen).
Eigentlich musst du es doch genauso machen wie in dem Beispiel was dir ohne gui gegeben wurde. #32
Am Anfang ist das Ergebnis 0 der Oberland plus.
Dann kommt eine zahlen Eingabe und die gespeicherte Operation wir mit dem Ergebnis (accumulator) ausgeführt.
Die orpperanten Eingabe brauchst du nur speichern. Rechnen nach der Zahlen Eingabe. Ergebnis ausgeben bei =.
Du musst Dir also wirklich im Detail überlegen, was Da bei jedem Schritt genau gemacht werden soll. Spiel es mit Stift und Papier durch!
Du wirst erst in der Lage sein, ein korrektes Programm zu schreiben, wenn Du jeden Schritt genau verstanden hast. (Mal von Glückstreffern abgesehen).
Ich hab das Problem glaube ich erkannt. Ich rechne zu spät oder?
ISt die Frage ob die Idee mit der Abfrage der Zahl mit der do..ButtonAction überhaupt sinnvoll ist oder ob ich das nochmal separieren sollte, weil ich ja im Prinzip mit jeder neuen Zahl eines neues result erhalten sollte.
Am Anfang ist das Ergebnis 0 der Oberland plus.
Dann kommt eine zahlen Eingabe und die gespeicherte Operation wir mit dem Ergebnis (accumulator) ausgeführt.
Die orpperanten Eingabe brauchst du nur speichern. Rechnen nach der Zahlen Eingabe. Ergebnis ausgeben bei =.
Eigentlich hab ich versucht mich daran zu orientieren. PS: kannst mal bitte auf deine Rechtschreibung und Satzbau achten, es macht es so recht schwierig zu lesen. Ist nicht böse gemeint
Eigentlich hab ich versucht mich daran zu orientieren. PS: kannst mal bitte auf deine Rechtschreibung und Satzbau achten, es macht es so recht schwierig zu lesen. Ist nicht böse gemeint
Es überschreibt also das Ergebnis(result) nicht korrekt.
Wenn ich nur 2 eingebe und auf "=" klicke, erwarte ich eigentlich, dass es 0, weil ja result zu Beginn auf 0 steht und der Operator auf +, +2 rechnet und damit result dann ebenso 2 wäre. Allerdings kommt dabei 0 raus. Das heißt es hat noch garnicht gerechnet nur die Zahl gemerkt aber noch nicht beachtet. Jetzt ist die Frage da, dass abfragen der Zahl ja schon an 1. Stelle steht, wo ich es denn sonst abfragen sollte, damit es richtig berücksichtigt wird?
Nimm mal bei Calculations überall das static weg. Und dann fügst Du der anderen Klasse eine Instanzvariable von Calculations hinzu: private final Calculations calculations = new Calculations();
Und dann nutzt Du bei allen Aufrufen die Instanzvariable calculations statt der Klasse Calculations.
Edit: Das ist nichts, das die Funktionalität groß ändern würde, d.h. alle Probleme die Du derzeit hast, sind weiter nicht gelöst. Aber du ersparst uns das ganze static Gedöns
Edit: Das ist nichts, das die Funktionalität groß ändern würde, d.h. alle Probleme die Du derzeit hast, sind weiter nicht gelöst. Aber du ersparst uns das ganze static Gedöns
Es ist ja nun immernoch so, dass ich irgend ein Detail nicht verstanden habe. #79 hab ich ja versucht mein Verständnis für den Vorgang nachzu zeichnen. Was mir komisch vorkommt ist noch ,dass der Operator quasi keinen zweiten Operanden bekommt. Neben dem Beschriebenen natürlich.
Kannst du mir nochmal vllt einen kleinen Arschtritt geben, sodass ich zufällig auf die richtige Stelle fliege?
public void doAddButtonAction(ActionEvent event){
Calculations.operand = Double.parseDouble(display.getText()); // Eingabe Zahl 2 // Zahl 1
Calculations.calculate(Calculations.operand);
Calculations.operator = '+' ; // Hier gehört der operator aus dem event rein
}
Das mit dem Hinzufügen des Operator in der Anzeige ist nicht gut.
Weil wenn du weiter rechnest was steht jetzt in der Anzeige und was ist dein Oberand bei der folgenden Rechen Aufgabe?
Was zeigt dir ein einfacher Taschenrechner immer an?
Neue Zaleneingabe da solltest du die Anzeige vorher Löschen wie ein Taschenrechner es auch macht.
Ich würde den zweiten Oberaden nicht aus der Anzeige holen. Sondern auch intern speichern.
Wenn du die gesamte Aufgabe in der Anzeige sehen willst.
public void doAddButtonAction(ActionEvent event){ Calculations.operand = Double.parseDouble(display.getText()); // Eingabe Zahl 2 // Zahl 1 Calculations.calculate(Calculations.operand); Calculations.operator = '+' ; // Hier gehört der operator aus dem event rein }
Ich habe jetzt den Thread heute nicht verfolgt, aber mir scheint, Du hast das Prinzip des Taschenrechners noch nicht verstanden.
1. Ein Ergebnis wird nur berechnet, wenn Du einen Operator (oder =) eingibst.
2. Wenn Du einen Operator eingibst, fehlt diesem Operator noch der zweite Operand.
3. Daher kann nur das Ergebnis des zuvor eingegebenen Operators berechnet werden.
Der zuvor eingegebene Operator hat natürlich zwei Operanden: das alte Ergebnis und die zuletzt eingegebene Zahl.
In der Anzeige solltest du das Plus nicht anzeigen.
Vor der erneuten Zahleneingabe soltest du die Anzeige löschen, du willst ja den nächsten Oberaden eingeben, und ihn beim Rechnen aus der Anzeige lesen.
Oder du musst nur den letzen Zahlen wert aus der Anzeige auslesen nicht alles.
Tipp setze beim Klick eines Button ein Flag was dir beim Ziffern eingeben zeigt das du die Anzeige löschen musst. Nach dem Löschen das Flag auch löschen.
Also irgendwie denke ich, dass es sch lohnen könnte, das noch einmal von Grund auf anzugehen.
So ein einfacher Taschenrechner braucht ein paar Dinge:
a) Das letzte Ergebnis
b) eine eingegebene Operation
c) eine angezeigte Zahl
Also bauen wir da erst einmal eine kleine Klasse draus:
Java:
public class Calculator {
@Getter
private double result;
@Getter
private Operator operator;
@Getter @Setter
private double displayValue;
}
Natürlich müssen wir die Operatoren noch definieren. Machen wir einfach einmal ein Enum mit nur einer Operation und einer neutralen Option:
Java:
public enum Operator {
NO_OPERATION, ADD
}
Nun müssen wir uns einfach mal überlegen, was es so alles gibt:
-> Es wird eine Zahl eingegeben - das kann man dann direkt setzen. Keine weitere Aktion notwendig, da der Setter von displayValue ausgeführt werden kann.
-> wenn ein Operator gesetzt werden soll, dann muss man die gespeicherte Operation ausführen. Das Ergebnis ist im result und danach ist die Operation NO_OPERATION. Bei NO_Operation wandert displayValue direkt in result.
Java:
protected void execute() {
// Execute the operator.
switch (operator) {
case NO_OPERATION:
result = displayValue;
break;
case ADD:
result += displayValue;
break;
default:
throw new NotImplementedException();
}
displayValue = 0;
}
Nun haben wir die Logik schon fast komplett. Wir können die gespeicherte Operation ausführen. Aber wir haben ja gesagt. dass execution() beim setzen des Operators passieren sollen:
Java:
public void setOperator(Operator operator) {
execute();
this.operator = operator;
}
Damit sind wir eigentlich schon durch was die Logik vom Calculator angeht. Nun kann man die UI schreiben.
Bei einem = wird NO_Operation gesetzt und danach kommt das result ins Display (Somit kann damit weiter gerechnet werden).
Noch irgendwas unklar? Immer erst die Logik aufbauen. Die Oberfläche kommt dann immer erst separat später. Alles zusammen verkompliziert alles nur. Was hier jetzt natürlich noch fehlte waren die Unit Tests.
Und man kann das Alles noch weiter umschreiben. Calculator könnte man so schreiben, dass es viele Methoden gibt, die direkt aufgerufen werden können:
Beschämt muss ich mich dennoch nochmals an dich wenden.
Ich habe deinen Code mal ausprobiert, das heißt die Logik genommen und versucht sie in die Oberfläche einzubauen.
Hier hab ich das setzen der zahl reingesteckt.
Wenn ich ausführe und dann auf den Plusbutton drücke kommt wieder eine NPE mit der Erklärung vom Compiler:
Cannot invoke "Calculations$Operator.ordinal()" because "this.operator" is null
Java:
public void doAddButtonAction(ActionEvent event){
calculations.add();
calculations.operator = Calculations.Operator.NO_OPERATION;
}
So sieht jetzt die doAddButtonAction(ActionEvent event) Methode aus.
Wie kann der operator null sein? die Add() setzt ihn doch auf ADD ?
Außerdem erwartet die
Java:
default:
throw new ExecutionControl.NotImplementedException();
Nein, an dem Code liegt es nicht. Du gibst irgendwo die Instanz von Calculations aus. Daher diese Ausgabe (durch die nicht überschriebene toString() Methode). Du willst aber doch ein Attribut ausgeben. Also fehlt da etwas wie getDisplayText() oder so.
Ich liebe dich !
Danke an alle Beteiligten(@kneitzel , @mihe7 , @Jw456 ) für eure Geduld und eure sehr guten Ratschläge. Als erste Erfahrung mit diesem Forum, bin ich wirklich positiv überrascht!
cheers,
Lou