actionListener für Button

LimDul

Top Contributor
aber addButton ist doch auch in JButton warum funktioniert es da, aber hier nicht?
nein, numberButtons ist kein JButton - es ist ein Array von JButtons.

Das heißt, du musst für jeden Eintrag die Methode addActionListenre aufrufen, also in der Form
Code:
for (int i = 0; i<numberButtons.length; i++) {
numberButtons[i].addActionListener(this::appendNumberButtonTextAction);
}
Alternativ mittels Arrays.forEach, für eine kürzere Schreibweise
 
K

kneitzel

Gast
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.

Edit: Typos
 

LouCyphre

Bekanntes Mitglied
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.
Wenn du noch kein Lehrer bist, solltest du mal drüber nachdenken einer zu werden! :)
 

LouCyphre

Bekanntes Mitglied
Java:
for (JButton numberButton : numberButtons) {
            numberButton.addActionListener(this::appendNumberButtonTextAction);
        }

// [...]

public void appendNumberButtonTextAction(ActionEvent event) {
        for(int i=0;i<10;i++) {

            if(event.getSource() == numberButtons[i]) {

                display.setText(display.getText().concat(String.valueOf(i)));
            }
        }
    }

Es komiliert erstmal, aber wenn ich ein Event auslöse, bekomme ich eine NullPointerException.
Heißt das es zeigt ins nichts?

Java:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at Frame.appendNumberButtonTextAction(Frame.java:hier in Zeile 8)
 
Zuletzt bearbeitet:
K

kneitzel

Gast
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.
 

LouCyphre

Bekanntes Mitglied
Okay.
Also

Java:
private JButton[] numberButtons; // alsInstanzvariable

// [...]

JButton[] numberButtons = new JButton[10];  // befüllen
        for(int i = 0; i<numberButtons.length; i++) {

            numberButtons[i] = new JButton(String.valueOf(i));
            
        }

und dann wie in #55

du meinst ich schmeiße

Java:
numberButtons[i].addActionListener(this::appendNumberButtonTextAction);

mit in die Schleife zum befüllen mit rein?
 
K

kneitzel

Gast
Das kann mit in die Schleife rein - das erspart die zweite Schleife.

Das ändert aber nichts an der Funktionalität - daher wäre wirklich die Frage, wo genau die NPE auftritt.
 

LouCyphre

Bekanntes Mitglied
Das kann mit in die Schleife rein - das erspart die zweite Schleife.
hab ich abgeändert.

Das ändert aber nichts an der Funktionalität - daher wäre wirklich die Frage, wo genau die NPE auftritt.
Java:
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)
 

Jw456

Top Contributor
hab ich abgeändert.


Java:
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)));
            }
        }
    }
String.valueOf(i)
Wird wohl nicht das liefern was du erwartest. Da wird deine Exception entstehen.

"String" ist eine Klasse und keine Variable.
 
K

kneitzel

Gast
String.valueOf(i)
Wird wohl nicht das liefern was du erwartest. Da wird deine Exception entstehen.

"String" ist eine Klasse und keine Variable.
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.
 

LouCyphre

Bekanntes Mitglied
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.
okay.

Java:
public class Frame extends JFrame{
    
    //
    
    private JButton[] numberButtons;
    
    public Frame(){
        
        //[...]
    // numberButtons bestücken
        JButton[] numberButtons = new JButton[10];
        for(int i = 0; i<numberButtons.length; i++) {

            numberButtons[i] = new JButton(String.valueOf(i));
            numberButtons[i].addActionListener(this::appendNumberButtonTextAction);
            numberButtons[i].setFocusable(false);
        }
    
    panel.add(numberButtons[1]);
        panel.add(numberButtons[2]);
        panel.add(numberButtons[3]);
        panel.add(addButton);
        panel.add(numberButtons[4]);
        panel.add(numberButtons[5]);
        panel.add(numberButtons[6]);
        panel.add(subButton);
        panel.add(numberButtons[7]);
        panel.add(numberButtons[8]);
        panel.add(numberButtons[9]);
        panel.add(mulButton);
        panel.add(decButton);
        panel.add(numberButtons[0]);
        panel.add(equButton);
        panel.add(divButton);
    }
    
    public void appendNumberButtonTextAction(ActionEvent event) {
        for(int i=0;i<numberButtons.length;i++) {                                   

            if(event.getSource() == numberButtons[i]) {

                display.setText(display.getText().concat(String.valueOf(i)));
            }
        }
    }
 

Jw456

Top Contributor
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.
 
K

kneitzel

Gast
Java:
    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.
 

Jw456

Top Contributor
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.
 

Jw456

Top Contributor
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()));
           
    }
 

LouCyphre

Bekanntes Mitglied
Hallo nochmal,

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.
 

LouCyphre

Bekanntes Mitglied
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;
        }
    }
}

Java:
public void doAddButtonAction(ActionEvent event){

        Calculations.operand = Double.parseDouble(display.getText());
        Calculations.calculate(Calculations.operand);
        display.setText(display.getText().concat("+"));
        operator = '+' ;
    }

//[...]

public void doEquButtonAction(ActionEvent event) {

        Calculations.calculate(Calculations.operand);
        display.setText(String.valueOf(Calculations.result));
        Calculations.result = Calculations.operand;
    }

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?
 
K

kneitzel

Gast
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).
 

Jw456

Top Contributor
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 =.
 
Zuletzt bearbeitet:

LouCyphre

Bekanntes Mitglied
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
 

Jw456

Top Contributor
Das rechnen musst du nach der Zahleneingabe machen.
Nicht nach der Operatoreingabe (zB + Button) denn musst du dir nur merken.

In der doEquButtonAction rechnest du gar nicht.
Da merkst du dir die Rechenart in der Variablen.


So wie in dem Code ohne GUI auch .
 

LouCyphre

Bekanntes Mitglied
Java:
    public void doAddButtonAction(ActionEvent event){

        Calculations.operand = Double.parseDouble(display.getText()); // Eingabe Zahl 2 // Zahl 1
        Calculations.calculate(Calculations.operand);                  // result = 0 + 2    // result 2 +1
        Calculations.operator = '+' ;                                  // merken (+)        // merken (+)

        display.setText(display.getText().concat("+"));

    }

Java:
    public void doEquButtonAction(ActionEvent event) {

        display.setText(String.valueOf(Calculations.result)); // erwartet 3 tatsächlich 2

    }

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?

Da merkst du dir die Rechenart in der Variablen.
Wie meinst du das?Da gebe ich doch nur das aktuelle result aus.
 

Jw456

Top Contributor
Die Rechenart bekommst du doch sicher auch in dem event übergeben.
Ggenau so wie du die Zahl übergeben bekommst wenn du auf eine Ziffer Klickst.

In diesem Listener wird nicht gerechnet.
 
K

kneitzel

Gast
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 :)
 

LouCyphre

Bekanntes Mitglied
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
alright.

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?
 

Jw456

Top Contributor
Java:
 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.
 

LouCyphre

Bekanntes Mitglied
[CODE lang="java" title="aus #79" highlight="3-5"]

public void doAddButtonAction(ActionEvent event){

calculations.operand = Double.parseDouble(display.getText()); // Eingabe Zahl 2 // Zahl 1
calculations.calculate(calculations.operand); // result = 0 + 2 // result 2 +1
calculations.operator = '+' ; // merken (+) // merken (+)

display.setText(display.getText().concat("+"));

}

[/CODE]
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 }
Wo ist der Unterschied?

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.
Gut, das merkt ich mir mal. Aber das Problem besteht damit immer noch
 

mihe7

Top Contributor
Was mir komisch vorkommt ist noch ,dass der Operator quasi keinen zweiten Operanden bekommt.
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.

Jetzt klar?
 

Jw456

Top Contributor
Wo ist der Unterschied?
Den Operator hast du dir ja gemerkt.


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.
 
Zuletzt bearbeitet:

Jw456

Top Contributor
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.
 

Jw456

Top Contributor
Java:
Calculations.operator = '+' ;  // Hier gehört der operator aus dem event rein

Ist nicht die Lösung sondern ein Hinweis was du machen musst, oder woher du den Operator, den gerückten Button bekommst. Eben aus dem event.

Wenn dein Button vielleicht so ausschaut.

JButton addButton = new JButton(String.valueOf("+"));
JButton addButton = new JButton("+");

Was hast du jetzt in deiner Event Variablen?
 
K

kneitzel

Gast
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:

Java:
public Calculator number(final double value) {
    displayNumber = value;
    return this;
}

public Calculator add() {
    setOperator(Operator.ADD);
    return this;
}

public Calculator equal() {
    setOperator(operator.NO_OPERATOR);
    displayNumber = result;
    return this;
}

Dann hat man etwas, das man wie einen Builder aufbauen kann:
Java:
double result = new Calculator()
    .number(2)
    .add()
    .number(3)
    .equal()
    .getDisplayNumber();

Aber das sind Dinge, da kann man überlegen, was man wie haben will... Optionen gibt es da halt viele ...
 

LouCyphre

Bekanntes Mitglied
Das liest sich wirklich wie Prosa. Danke dafür, das hilft wirklich sehr sich vorzustellen, wie man es beim nächsten mal besser machen kann.
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
}

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.

[CODE lang="java" highlight="5"] private void appendNumberButtonTextAction(ActionEvent event) {
if (event.getSource() instanceof JButton button) {
String input = button.getText();
display.setText(display.getText().concat(input));
calculations.setDisplayNumber(Double.parseDouble(input));
}
}[/CODE]

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();

noch ein Argument.

Ich habe dafür, wie vom Compiler vorgeschlagen
Java:
import jdk.jshell.spi.ExecutionControl;
importiert.
 
K

kneitzel

Gast
Operator sollte im Konstruktor auf NO_OPERATION gesetzt werden. Das Feld wurde bisher nicht mit einem default Wert belegt.
 

LouCyphre

Bekanntes Mitglied
Operator sollte im Konstruktor auf NO_OPERATION gesetzt werden. Das Feld wurde bisher nicht mit einem default Wert belegt.
Okay das habe ich gemacht.

Jetzt zeigt es mir eine Speicher Adresse auf dem Display an.

Java:
Calculations@292bf89f

Ich ahne, der Fehler könnte hier liegen!?

Java:
 private void appendNumberButtonTextAction(ActionEvent event) {
        if (event.getSource() instanceof JButton button) {
            String input = button.getText();
            display.setText(display.getText().concat(input));
            calculations.setDisplayNumber(Double.parseDouble(input));
        }
    }
 
K

kneitzel

Gast
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.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
F Wie bekomme ich den Wert der ComboBox in eine Variable gespeichert welche ich für meinen ActionListener nutzen kann? AWT, Swing, JavaFX & SWT 3
L Ein Actionlistener für ein Textfeld, anstatt viele Actionlistener für ein Textfeld AWT, Swing, JavaFX & SWT 7
S ActionListener für alle Buttons AWT, Swing, JavaFX & SWT 26
A Gui für Vokabeltrainer (ActionListener) AWT, Swing, JavaFX & SWT 14
M ActionListener für mehrere Klassen AWT, Swing, JavaFX & SWT 4
J ActionListener für Buttons AWT, Swing, JavaFX & SWT 3
W actionListener für JButton "Step" AWT, Swing, JavaFX & SWT 5
R Swing ActionListener für JButton bei Drücken AWT, Swing, JavaFX & SWT 3
D Swing ActionListener für JComboBox AWT, Swing, JavaFX & SWT 8
GilbertGrape ActionListener implementieren oder Eigenen für jede Komponente? AWT, Swing, JavaFX & SWT 9
B Actionlistener für MenuItem AWT, Swing, JavaFX & SWT 19
M ActionListener für JButton AWT, Swing, JavaFX & SWT 2
C ActionListener für dynamisches Menü AWT, Swing, JavaFX & SWT 8
C Button ActionListener funktioniert nicht AWT, Swing, JavaFX & SWT 1
B Actionlistener mit Java Swing AWT, Swing, JavaFX & SWT 2
L jComboBox Actionlistener wird beim erstmaligen Befüllen getriggert AWT, Swing, JavaFX & SWT 7
H Viele ActionListener (MouseListener) - Performance AWT, Swing, JavaFX & SWT 24
pkm MainFrame durch Actionlistener auffrischen, aber wie? AWT, Swing, JavaFX & SWT 2
R Actionlistener funktioniert nicht AWT, Swing, JavaFX & SWT 4
N Bilder auf Button einfügen und mehrmals ändern (ein Button, mehrere ActionListener) AWT, Swing, JavaFX & SWT 2
R ActionListener in Actionlistener AWT, Swing, JavaFX & SWT 6
S Swing Variable in Actionlistener aufrufen AWT, Swing, JavaFX & SWT 10
P Swing ActionListener überschreibt einen Wert aus der Hauptklasse nicht AWT, Swing, JavaFX & SWT 5
N Aufruf einer anderen Klasse durch Button ActionListener AWT, Swing, JavaFX & SWT 2
M AWT Kann meinen Fehler beim ActionListener nicht finden AWT, Swing, JavaFX & SWT 5
coolian ActionListener funktonirt nicht richtig auf JMenuItem AWT, Swing, JavaFX & SWT 4
L ActionListener zu Button in Panel hinzufügen AWT, Swing, JavaFX & SWT 10
R Kann JLabel in ActionListener nicht aufrufen AWT, Swing, JavaFX & SWT 4
Blender3D einzelner ActionListener vs anonyme ActionListener AWT, Swing, JavaFX & SWT 10
T Swing Änderung des ActionListener Events nach Klick auf JButton AWT, Swing, JavaFX & SWT 2
xYurisha ActionListener Methoden Buttons zuweisen! AWT, Swing, JavaFX & SWT 16
J ActionListener bei Buttons AWT, Swing, JavaFX & SWT 14
S Swing Problem mit Button und ActionListener AWT, Swing, JavaFX & SWT 5
it_is_all ActionListener umlenken/ updaten mit AddActionListener funktioniert nicht AWT, Swing, JavaFX & SWT 3
it_is_all Event Handling ActionListener in anderer Klasse klappt nicht AWT, Swing, JavaFX & SWT 4
F "ActionListener" funktioniert nicht AWT, Swing, JavaFX & SWT 4
Z ActionListener Variable übergeben AWT, Swing, JavaFX & SWT 12
T JProgressbar während actionListener updaten AWT, Swing, JavaFX & SWT 1
S While Schleife im Actionlistener AWT, Swing, JavaFX & SWT 1
R Swing ActionListener bei JButton AWT, Swing, JavaFX & SWT 9
T ActionListener nimmt JTextField nicht mehr an. AWT, Swing, JavaFX & SWT 2
P ActionListener Graphics Einbauen AWT, Swing, JavaFX & SWT 0
S actionlistener mit 2 fenster integrieren AWT, Swing, JavaFX & SWT 11
Liondary GUI - ActionListener AWT, Swing, JavaFX & SWT 7
J ActionListener erkennt Variable nicht AWT, Swing, JavaFX & SWT 6
E ActionListener führt falsche Funktion aus AWT, Swing, JavaFX & SWT 6
Sin137 ActionListener in MVC AWT, Swing, JavaFX & SWT 7
M ActionListener und mathematische Methoden AWT, Swing, JavaFX & SWT 13
A Oberfläche mit zwei Klassen und actionlistener verbinden AWT, Swing, JavaFX & SWT 7
Paul15 ActionListener Variablen AWT, Swing, JavaFX & SWT 13
Y ActionListener AWT, Swing, JavaFX & SWT 2
K Ereignisbehandlung, ActionListener, ActionEvent AWT, Swing, JavaFX & SWT 3
C Im ActionListener Buttons disablen, einen Thread starten, dann Buttons enablen AWT, Swing, JavaFX & SWT 2
M JTextArea wird nicht aktualisiert (ActionListener-Problem) AWT, Swing, JavaFX & SWT 1
J Event Handling JOptionPane ActionListener setzen. AWT, Swing, JavaFX & SWT 3
S ActionListener Klasse aufrufen AWT, Swing, JavaFX & SWT 4
R Swing Problem: IOException bei ActionListener AWT, Swing, JavaFX & SWT 1
J ActionListener soll auf paint() Methode zugreifen AWT, Swing, JavaFX & SWT 1
A JButton wird bei ActionListener nicht "angenommen" AWT, Swing, JavaFX & SWT 7
T Einfaches Problem mit ActionListener AWT, Swing, JavaFX & SWT 2
K ActionListener mit KeyListener AWT, Swing, JavaFX & SWT 7
K GUI, Button, ActionListener - ein paar Einsteigerprobleme AWT, Swing, JavaFX & SWT 1
W Verschachtelter ActionListener AWT, Swing, JavaFX & SWT 0
N gewünschte ActionListener bei RadioButton mit isSelected geht nicht AWT, Swing, JavaFX & SWT 2
C Probleme mit Buttons und einem ActionListener AWT, Swing, JavaFX & SWT 2
K Swing JMenu und ActionListener AWT, Swing, JavaFX & SWT 4
A Swing ActionListener AWT, Swing, JavaFX & SWT 8
V ActionListener Abhängigkeitenproblem AWT, Swing, JavaFX & SWT 6
M Event Handling ActionListener übergeben ich checks net AWT, Swing, JavaFX & SWT 4
C Swing ComboBox - ActionListener deaktivieren AWT, Swing, JavaFX & SWT 2
S Button (ActionListener) funktioniert nicht, wenn y-Koordinate verändert wird AWT, Swing, JavaFX & SWT 5
L Swing ActionListener führt seine Aufgabe nur teilweise aus. AWT, Swing, JavaFX & SWT 7
A Swing ActionListener kann nicht hinzugefügt werden AWT, Swing, JavaFX & SWT 4
P Actionlistener - 3 klassen - kompliziert - auf methoden zugreifen AWT, Swing, JavaFX & SWT 3
Q CardLayout, ausgelagerte Panels, ActionListener AWT, Swing, JavaFX & SWT 5
M ProgressBar in ActionListener AWT, Swing, JavaFX & SWT 4
D AWT eigenem Knopf ActionListener zuweisen AWT, Swing, JavaFX & SWT 24
E Wert aus ActionListener geben AWT, Swing, JavaFX & SWT 4
J ActionListener per Innere Klasse oder e.getActionCommand() if-Abfrage? AWT, Swing, JavaFX & SWT 12
L Swing ActionListener zugriff auf bestimmte Elemente AWT, Swing, JavaFX & SWT 3
P Swing Seltsames ActionListener-Verhalten AWT, Swing, JavaFX & SWT 7
Oliver530 ActionListener von eigener ButtonKlasse AWT, Swing, JavaFX & SWT 16
Kenan89 statischer ActionListener keine Wirkung? AWT, Swing, JavaFX & SWT 2
Kenan89 statischer ActionListener keine Wirkung? AWT, Swing, JavaFX & SWT 3
C In der Schleife ActionListener aktivieren AWT, Swing, JavaFX & SWT 3
B Swing Problem beim ActionListener AWT, Swing, JavaFX & SWT 5
P Swing JPanel mit ActionListener mehrfach verwenden AWT, Swing, JavaFX & SWT 8
1 ActionEvent generieren und an ActionListener weiterleiten AWT, Swing, JavaFX & SWT 12
N Swing Klasse erbt von JDialog - Problem mit innerer ActionListener-Klasse AWT, Swing, JavaFX & SWT 6
N JCombobox und Actionlistener Aktion nur ausführen, wenn Useraktion ihn auslöst AWT, Swing, JavaFX & SWT 4
N Componente und Actionlistener AWT, Swing, JavaFX & SWT 5
C ActionListener AWT, Swing, JavaFX & SWT 6
Corben ActionListener Error AWT, Swing, JavaFX & SWT 2
F Wert durch ActionListener an Klasse übergeben AWT, Swing, JavaFX & SWT 3
I Swing Problem mit InputMap bei JButton (ActionListener) AWT, Swing, JavaFX & SWT 3
S Swing JButton mit ActionListener innerhalb einer JTable AWT, Swing, JavaFX & SWT 4
P Variablen in einem ActionListener zurücksetzen AWT, Swing, JavaFX & SWT 6
M AWT Problem mit ActionListener AWT, Swing, JavaFX & SWT 2
A Swing Bug in Swing? Wenn checkbox disabled reagiert ActionListener nicht AWT, Swing, JavaFX & SWT 5
S ActionListener "nach oben weitergeben" AWT, Swing, JavaFX & SWT 10

Ähnliche Java Themen

Neue Themen


Oben