22.1 JButton lernt dazu
 
Erben Im Sinne der Modularisierung und der inneren Logik einer objektorientierten Sprache ist die RechnerGUI nicht zufrieden stellend. Warum soll in der GUI abgefragt werden, welches Button ein Ereignis meldet und die Ereignisse dann Button-spezifisch behandelt werden? Nahe liegender wäre es doch, wenn das Button selbst 'sein' Ereignis behandelt, und es müsste doch selbst wissen, wann es gedrückt wurde. Ein JButton-Objekt, wie es von Java angelegt ist, kann das aber nicht. Wir müssen ein 'intelligentes' Button, das das kann, was wir uns wünschen, selbst implementieren, was übrigens viel leichter ist als man zunächst annimmt. Wir nützen nämlich aus, dass Java erlaubt, fertige Klassen zu beerben. In dem Kapitel 10 haben wir schon gelernt wie man von einer Klasse erbt. Dort war es die Klasse MeineTurtle, die von der Klasse Turtle erbte.  Wir werden jetzt einiges mehr über das Vererben lernen.  Gehen wir Schritt für Schritt vor.

Nennen wir unsere neue Button-Klasse JButtonQuadGl um auszudrücken, dass sie alle Eigenschaften hat, die auch die Klasse JButton hat, aber zusätzlich auf das Anklicken eines seiner Instanzen die Werte a, b und c aus den Eingabefenstern  der GUI liest und die Lösung der Quadratischen Gleichung
ax2 + bx + c = 0  im Ausgabefenster der GUI ausgibt.
 

Kopf der neuen Klasse public class JButtonQuadGL extends JButton {
  ...
}

Mit dem reservierten Wort extends gefolgt vom Namen der Klasse JButton, teilen wir dem Kompiler mit, dass JButtonQuadGl JButton beerbt. Alle Attribute und alle Methoden der Klasse JButton sind nun auch Attribute bzw. Methoden der Klasse JButtonQaudGL, so, als wären sie hier implementiert.
Kommen wir zu den zusätzlichen Eigenschaften unseres neuen Buttons. Es soll selbst auf das Ereignis, nämlich 'gedrückt' zu werden, reagieren können. Es soll also in unserer Klasse und nicht mehr in der der GUI  die Methode
actionPerformed(ActionEvent e) implementiert werden. Oder anders ausgedrückt: Unser neuer Button wird selbst zum Aktionsabhorcher. Dazu muss unsere Klasse das Interface ActionListener implementiert. Wie korrigieren also unseren Kopf zu:
 

der neue Kopf public class JButtonQuadGL extends JButton
                           implements ActionListener{
  ...
  public void actionPerformed(ActionEvent e){
    ...
  }
}
 

Schauen wir uns zunächst den gesamten Quelltext an und kommentieren danach einzelne wichtige Stellen.

 

Klasse JButtonQuadGL

Download:
JButtonQuadGl.
java

import javax.swing.*;

import java.awt.event.*;



public class JButtonQuadGl extends JButton 

                           implements ActionListener{



  RechnerGUI rechner;



  public JButtonQuadGl(String beschriftung, RechnerGUI rechner){

   super (beschriftung);

   this.rechner = rechner;

  }

  public void actionPerformed(ActionEvent e){

   double a=Double.parseDouble(rechner.eingabeFeldA.getText());

   double b=Double.parseDouble(rechner.eingabeFeldB.getText());

   double c=Double.parseDouble(rechner.eingabeFeldC.getText());

   rechner.ausgabeFeld.setText(Mathematik.loeseQuadGl(a,b,c));

  }

}
Kommentare Unser JButtonQuadGL-Objekt muss das RechnerGUI-Objekt kennen, damit er dessen Eingabefelder auslesen und in sein Ausgabefeld schreiben kann. Wir deklarieren deshalb einen rechner als RechnerGUI-Objekt.

RechnerGUI rechner;

Damit ist die Verbindung noch nicht geknüpft, das geschieht, wie wir gleich noch sehen werden im Konstruktor:

public JButtonQuadGl(String beschriftung, RechnerGUI rechner){

  super (beschriftung);

  this.rechner = rechner;

} 

Die Parameterliste des Konstruktors enthält zwei Parameter. Zunächst einen, in dem wir die Beschriftung unsers Buttons übergeben und zweitens den GUI-Rechner. Beim letzten wird also die Verknüpfung mit der RechnerGUI geschaffen.
Mit
super(...) rufen wir einen Konstruktor der Klasse auf, von der JButtonQuadGL erbt, also aus der Klasse JButton. Da JButton mehrere Konstruktoren besitzt, entscheidet die Signatur, welcher gemeint ist. In unserem Beispiel ist es JButton(String name), also der, bei dem man den Button zusätzlich beschriften kann. Wir sagen hier 'zusätzlich', weil der Konstruktor außer dem Setzten der Beschriftung noch jede Menge anderer Dinge tut. Schließlich wird mit  this.rechner = rechner; die Referenz des übergebenen GUIRechners, also rechner auf den in unserer neune Klasse bereits deklarierten, gesetzt. Damit steht der übergebene Rechner nicht nur im Konstruktor sondern auch in der ganzen Klasse zur Verfügung. Das ist wichtig, da wir die Methoden des rechners (Auslesen aus den Eingabefeldern und Schreiben in das Ausgabefeld) in der Methode actionPerformed(ActionEvent e) gebraucht werden.

Wir kommen jetzt zur Methode actionPerformed(ActionEvent e). Sie sieht der schon von der alten rechnerGUI-Klasse bekannten ziemlich ähnlich. Der Wert für a wird aus dem Textfeld eingabeFeldA des übergeben Objektes rechner gelesen: Statt eingabeFeldA.getText(); schreiben wir jetzt: rechner.eingabeFeldA.getText();. Die bei diesem Aufruf gelieferte Zeichenkette wird der Double-Klassenmethode parseDouble(String name) übergeben, die, falls die Eingabe sinnvoll war, einen double-Wert liefert, der schließlich in a abgelegt wird.
 

Die neue rechnerGUI
(mit nur einem Button)
import java.awt.*;

import java.awt.event.*;

import javax.swing.*;



public class RechnerGUI extends JFrame {        //1

  // Anfang Variablen

  private JPanel northPanel, centerPanel;

  private JLabel labelA, labelB, labelC;

  public JTextField eingabeFeldA, eingabeFeldB, //2 

         eingabeFeldC, ausgabeFeld;

  private JButtonQuadGl qglButton;              //3

  // Ende Variablen



  public RechnerGUI(String title) {

    // Frame-Initialisierung

    super(title);

    setDefaultCloseOperation(EXIT_ON_CLOSE);

    final int frameWidth = 500;

    final int frameHeight = 150;

    setSize(frameWidth, frameHeight);

    Container cp = getContentPane();

    cp.setLayout(new BorderLayout());



    // Anfang Komponenten

    northPanel = new JPanel(new GridLayout());

    cp.add(northPanel, BorderLayout.NORTH);

    

    centerPanel = new JPanel();

    cp.add(centerPanel, BorderLayout.CENTER);

    

    labelA = new JLabel("a:    ");

    labelA.setHorizontalAlignment(SwingConstants.RIGHT);

    northPanel.add(labelA);

    

    eingabeFeldA = new JTextField("0");

    eingabeFeldA.setHorizontalAlignment(SwingConstants.RIGHT);

    northPanel.add (eingabeFeldA);

    

    labelB = new JLabel("b:    ");

    labelB.setHorizontalAlignment(SwingConstants.RIGHT);

    northPanel.add(labelB);



    eingabeFeldB = new JTextField("0");

    eingabeFeldB.setHorizontalAlignment(SwingConstants.RIGHT);

    northPanel.add (eingabeFeldB);

    

    labelC = new JLabel("c:    ");

    labelC.setHorizontalAlignment(/*labelC*/SwingConstants.RIGHT);

    northPanel.add(labelC);



    eingabeFeldC = new JTextField("0");

    eingabeFeldC.setHorizontalAlignment(SwingConstants.RIGHT);

    northPanel.add (eingabeFeldC);

    

    qglButton = new JButtonQuadGl("Löse ax² + bx + c = 0",this);

    centerPanel.add(qglButton);                                 

    qglButton.addActionListener(qglButton);                     

    

    ausgabeFeld = new JTextField("");

    ausgabeFeld.setHorizontalAlignment(SwingConstants.RIGHT);

    cp.add (ausgabeFeld, BorderLayout.SOUTH);



    // Ende Komponenten



    setVisible(true);

  }



        



  public static void main(String[] args) {

    new RechnerGUI("RechnerGUI");

  }

}
Merkmal 1 Die Klasse rechnerGUI implementiert nicht mehr das Interface ActionListener; das macht jetzt der neue Button. Somit entfällt auch die Implementierung der Methode actionPerformed(ActionEvent e).
 
Merkmal 2 Die Textfelder, auf die unser neuer Button zugreift soll, müssen zugänglich gemacht werden, sind also jetzt public.
 
Merkmal 3 Der neue Button wird deklariert
 
Merkmal 4 Beim Aufruf des Konstruktor

JButtonQuaGL(String name, rechnerGUI rechner)


für die Erzeugung des
JButtonQuadGL-Objekts wird, wie schon oben erwähnt, zuerst die Beschriftung für den Button und an zweiter Stelle das rechnerGUI-Objekt, das die Eingabe- und Ausgabefelder hat, übergeben. Diese Object ist aber das aufrufende Objekt, weshalb wir this übergeben.

In

qglButton.addActionListener(qglButton);

wird der qglButton bei  einem ActionListener registirert und als Paramter das AktionListener-Objekt übergeben, das Objekt also, das die Ereignisbehandlung abwickelt, in unserem Fall also das Objekt qglButton.

 

zu 22.2 Klassenhierarchie des neuen Rechners
zur Startseite www.pohlig.de  (C) MPohlig 2004