Aktionen überwachen

Erinnern wir uns noch an das Beispiel mit den drei Buttons im Kapitel Grundlagen der Objektorientierung? Wir haben nun genug Wissen um das Beispiel von Pseudo-Code in echten Code umzusetzen:

package start;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;

public class DreiButtons extends JFrame {

  public static void main(String[] args) {
    
    DreiButtons fenster = new DreiButtons();
    
    fenster.setBounds( 0, 0, 900, 500 );
    fenster.setAlwaysOnTop( true );
    fenster.setDefaultCloseOperation( EXIT_ON_CLOSE );
    fenster.setLocationRelativeTo( null );
    fenster.setVisible( true );

    
    JButton button1 = new Button("Text1");
    button1.setBounds(0, 0, 100, 30);
    
    JButton button2 = new Button("Text2");
    button2.setBounds(110, 0, 100, 30);
    
    JButton button3 = new Button("Abbruch");
    button3.setBounds(220, 0, 100, 30);
    
    fenster.add(button1);
    fenster.add(button2);
    fenster.add(button3);
    
  }


}

class Button extends JButton implements ActionListener {

  String beschriftung;
  
  Button(String t) {
  this.setText(t);
  this.addActionListener(this);	
  }
  
  @Override
  public void actionPerformed(ActionEvent e) {
    
    if(this.getText() == "Abbruch") {
      System.exit(0);
    } else {
      System.out.println( "Meine Beschriftung lautet:" + this.getText() );		
    }
    
  }
  
}

Die Klasse Button könnten wir natürlich auch in einer extra Datei auslagern. Der Einfachkeit halber lassen wir es hier aber so.

Doch was ist ein ActionListener genau? Ein ActionListener ist ein sogenanntes Inferface. Ein Interface stellt der Klasse weitere Methoden zur Verfügung die jedoch meist angepasst werden müssen. In unserem Fall ist es die Methode actionPerformed die von Eclipse automatisch eingefügt wird. ActionPerformed bekommt automatisch bei einem Klick die Variable e übergeben. e ist ein Objekt vom Typ ActionEvent, das die Quelle des Klicks enthält.

Hier hat praktisch jeder Button seinen eigenen ActionListener da er bereits in der Klasse integriert ist.
Für kleinere Aufgabe mag dies so nützlich sein. Bei größeren Oberflächen ist es jedoch meist günstiger gleich im JFrame den ActionListener zu implementieren. Dadurch benötigt man nur einen einzigen ActionListener in dem man alles behandeln kann.
Auch kann man dann das Objekt selbst mit dem ActionEvent vergleichen was in dem Beispiel nicht möglich ist da noch kein button gebildet wurde und somit keine Referenz zur Verfügung steht. Folgender Code würde also nicht funktionieren:
...
Object o = e.getSource();
if(o == button1)
...

Fügt man den ActionListener erst später hinzu funktioniert es und man hat die Möglichkeit den Button direkt mit dem Ursprung der Aktion zu vergleichen. Besser ist es also so:

package start;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;

public class DreiButtons extends JFrame implements ActionListener {
  
  JButton button1;
  JButton button2;
  JButton button3;
  
  public static void main(String[] args) {
    
    DreiButtons fenster = new DreiButtons();		
  }
  
  DreiButtons() {
    
    setBounds( 0, 0, 900, 500 );
    setAlwaysOnTop( true );
    setDefaultCloseOperation( EXIT_ON_CLOSE );
    setLocationRelativeTo( null );
    setVisible( true );
    
    initialisiereObjekte();
  }

  public void initialisiereObjekte() {
    button1 = new JButton("Text1");
    button1.setBounds(0, 0, 100, 30);
    button1.addActionListener(this);
    
    button2 = new JButton("Text2");
    button2.setBounds(110, 0, 100, 30);
    button2.addActionListener(this);
    
    button3 = new JButton("Abbruch");
    button3.setBounds(220, 0, 100, 30);
    button3.addActionListener(this);
    
    add(button1);
    add(button2);
    add(button3);
  }


  @Override
  public void actionPerformed(ActionEvent e) {
    Object o = e.getSource();
    if(o == button3) {
      System.exit(0);
    } else {
      System.out.print("Ich bin ein " + o.getClass() );
      JButton btn = (JButton) o;
      System.out.print(" mit der Beschriftung " + btn.getText());
      System.out.println();
    }
  }


}


Da der ActionListener nicht aus einem statischen Kontext wie die Main-Methode heraus hinzugefügt werden kann, müssen wir zunächst im Konstruktor den Frame erstellen und dann eine Methode aufrufen die nicht statisch ist.
Anders ausgedrückt: Die Main-Methode gehört nicht wirklich zur Klasse. Sie ist eben nur der Einstieg. Da der ActionListener zur Klasse gehört und am Anfang noch kein Objekt dieser Klasse gebildet wurde, steht der ActionListener logischerweise auch noch nicht zur Verfügung. Also müssen wir zuerst ein Objekt unserer Klasse bilden.
Außerdem müssen die Variablen für die Buttons global angelegt werden, da aus der Methode heraus nur in der eigenen Methode deklarierte Variablen gelesen werden können.  Eine Variable ist global, wenn sie im Kopf der Klasse deklariert wird. Sie steht dann in allen Methoden zur Verfügung. Eine Variable die in einer Methode deklariert wird nennt man lokal.

Als nächstes beschäftigen wir uns etwas mit Mausaktionen.

Zusammenfassung

  • Ein Button braucht einen ActionListener um zu bemerken das auf ihn geklickt wurde und um reagieren zu können.
  • Ein ActionListener ist stellt eine Methode zur Verfügung in der wir programmieren was bei einem Klick passiert.
  • globale Variablen sind überall verfügbar und werden im Kopf der Klasse deklariert.
  • lokal nennt man Variablen die in einer Methode deklariert werden.
  • Die Main-Methode ist nur der Einstieg zum Programm und könnte auch komplett ausgelagert werden. z.B. in eine main.java oder start.java