Java: ActionListener-Konzept ist komisch...

H

Hugoderwolf

Aktives Mitglied
Thread Starter
Dabei seit
07.03.2003
Beiträge
349
Reaktionspunkte
0
Ich steige jetzt gerade a bissl in Java ein. Ich komme mehr oder weniger von C und hab noch nicht die meiste Erfahrung in OOP. However, die Vorlesung "Grundlagen der Informatik I" geht auf Java steil.

Gerade hab ich mir ein Programm zusammengebastelt, das bei jedem clicken eines Buttons ein neues Label mit 'nem Text drin erzeugt. Nur das Konzept des ActionListeners geht mir noch nicht ganz auf. Ich halte es, grob gesagt, für einen Alptraum. Aber ich habe es hoffentlich nur nicht verstanden.

Das Buch zur Vorlesung hat mein Prof selbst geschrieben und er ist furchtbar von sich selbst überzeugt, weshalb er die historische erste "verpasste" Vorlesung von Hugoderwolf auf seinem Konto verbuchen kann. "Lehrbuch Grundlagen der Informatik" von Prof. Dr.-Ing. Helmut Balzert heißt das Werk und löst die Listener-Problematik in einem Beispielprogramm mit zwei Buttons so:

Code:
/*Programmname: Kundenverwaltung5
* Abhoerer-Klasse: AktionsAbhoerer
* Abhoerer-Klasse ist eigenst‰ndige Klasse!
*/
import java.awt.event.*;

public class AktionsAbhoerer
implements ActionListener //wird von Java zur Verf¸gung gestellt
{
    KundeGUI einGUI; //Referenz-Attribut: Referenz auf Erzeuger

    //Konstruktor, durch Parameter wird Referenz auf aufrufendes Objekt ¸bergeben
    AktionsAbhoerer(KundeGUI einKundeGUI)
    {
       einGUI = einKundeGUI;
    }
    public void actionPerformed(ActionEvent event)
    {
        //Ereignisquelle feststellen mit getSource
        Object quelle = event.getSource();
        if (quelle == einGUI.speichernDruckknopf)
            einGUI.speichereKunde();//Reaktion auf Speichern
        else if (quelle == einGUI.anzeigenDruckknopf)
            einGUI.anzeigenKunden();//Reaktion auf Anzeigen
     }
}

Da dreht sich mir bei einigen Sachen der Magen um.

1. Warum soll ich nur zum behandeln von dämlichen Buttonclicks eine extra Klasse und damit eine extra Datei schreiben?
2. Ich muss an diese Klasse noch umständlich die Hauptklasse übergeben, damit ich auf Funktionen darin zugreifen kann.
3. Ich muss in einer Funktion erstmal manuell Unterscheiden, von welchem Button nun das Event kommt und dann die entsprechende Funktion aufrufen (mal abgesehen davon, dass sowas eigentlich in ein switch(){...} gehört...)

Das ist doch völlig dämlich. Normalerweise sollte man dem Button als Eventhandler einfach eine Methode in der Klasse, die die GUI erstellt, zuweisen können. So ist das für mich eine überflüssige Datei und unmengen überflüssiger Code!

Jetzt sagt mir also mal, dass das, was da auf der Buch-CD ist, völliger Schrott ist und dass es viel eleganter geht. Am liebsten in etwa so, wie gerade beschrieben.
 
Hallo,

du kannst auch in der Hauptklasse einen ActionListener und die Methode actionPerformed implementieren. Und dann für den Button als ActionListener einfach "this" registrieren.
Die manuelle Feststellung der Quelle lässt sich meines Wissens nicht umgehen.

Gruß
twjb
 
Das ganze läuft wohl auf das Model/View/Controller Prinzip raus. Und da gehören die Steuerbefehle halt in eine extra Klasse :D

Allerdings musst du nicht extra ne Klasse "AktionsAbhoerer" machen. Implementiere einfach den ActionListener in die Klasse wo die Events auftauchen und gib den ActionListener dann mit "this." an. So musst nicht jedesmal die Klasse mit nennen.

Ausserdem ist:
Code:
Object quelle = event.getSource();
        if (quelle == einGUI.speichernDruckknopf)

nicht sehr "schön" machs mit:

Code:
 if (quelle.equals(event).getSource()
 
yep, typischer denkstil eines c-programmierers ;)

einfach.

Code:
public class KundeGUI implements ActionListener
{
   ....
   public ...()
   {
       JButton myButton = new JButton();
       myButton.addActionListener(this);
       ...
   }

   public void actionPerformed(ActionEvent e)
   {
       .....
   }
}

hth.jay
 
OK, das kommt schon weitaus besser. In dem Beispiel ist das wohl etwas blöd geregelt (und nicht besonders Konsequent). Mich stört nur trotzdem noch, dass ich die Quelle der Action so blöd aufschlüsseln muss. Aber das muss wohl sein. Schade. :(

Noch 'ne Frage: Geht auch sowas?

class deineMuddha extends Applet implements ActionListener
 
Hugoderwolf schrieb:
OK, das kommt schon weitaus besser. In dem Beispiel ist das wohl etwas blöd geregelt (und nicht besonders Konsequent). Mich stört nur trotzdem noch, dass ich die Quelle der Action so blöd aufschlüsseln muss. Aber das muss wohl sein. Schade. :(

Noch 'ne Frage: Geht auch sowas?

class deineMuddha extends Applet implements ActionListener
Nein, geht nicht.

Du kannst Action Listener nur manuell einzelnen Elementen zuweisen. Früher hatte Sun mal die Möglichkeit eingebaut, einem kompletten Frame einen ActionListener dranzukleben und theoretisch kann man das heute auch noch machen, nur funktionieren wird es nicht.
 
Wieso geht das nicht? Was meinst du mit "manuell einzelnen Elementen zuweisen"?
Ich kann doch von einer Klasse erben und zusätzlich ein Interface implementieren. Meiner Meinung nach müsste das schon gehen.

Gruß
twjb
 
Hallo Leute,

hier meine 2 Cent:
1. "class deineMuddha extends Applet implements ActionListener" kann man natürlich machen, du musst in der Klasse dann halt die Methode actionPerformed(ActionEvent e) implementieren und den ActionListener wie gehabt dem Button über button.addActionListener(this) zuweisen.

2. switch kann nicht verwendet werden, weil es nur mit Primitivdatentypen in Java funktioniert. Noch etwas: Du kannst auch nicht zwei Objektinstanzen über == vergleichen (dabei wird nur true zurückgeliefert, wenn die Referezen wirklich gleich ist) sondern musst die Methode equals() nehmen (besonders wichtig bei Strings, bei denen oft übersehen wird, dass sie keine Primitvdatentypen sind).

3. Du kannst den ActionListener auch als anonyme innere Klasse oder innere Klasse implementieren, dann umgehst du die Aussortierung des Sourceobjects. Das geht so:
Anonyme innere Klasse:
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
tueEtwas();
}
});

Innere Klassen:
...
button1.add(new MeinErsterActionListener());
button2.add(new MeinZweiterActionListener());
...
class MeinErsterActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
blabla...
}
}
class MeinZweiterActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
blabla...
}
}

Hoffe das bringt dich weiter...

Gruß

41isnr1
 
41isnr1 schrieb:
und den ActionListener wie gehabt dem Button über button.addActionListener(this) zuweisen.


Ja, so gesehen funktioniert das, ich dachte er meint, wenn er von dem Action Listener erbt, braucht er keine Listener mehr zuzuweisen.
 
Wie Du siehst, gibt es drei Möglichkeiten, einen ActionListener zu implementieren:

1. In einer getrennten Klasse
2. Durch Implementieren des Interfaces
3. Durch eine innere Klasse

Auch wenn das am Anfang etwas verwirrend ist, hat das seinen Grund:

Java unterstützt das Action-Prinzip. So lassen sich Aktionen auch getrennt implementieren, durch Action-Klassen. Damit kannst Du die Logik von der GUI trennen und diese Logic wiederverwenden.

Zum Beispiel ist es ja oft so, das Du eine Aktion nicht nur hinter einem Button hinterlegst, sondern das es auch einen entsprechenden Menüeintrag gibt. In diesem Fall registriert man die entsprechende Aktion sowohl an Button und Menüeintrag und braucht nur einen Action-Listener.

Im Javabuch.de (ehemals Go To Java) ist das sehr gut erklärt.
 
Ah, das hat mein Tutor uns auch empfohlen. Werde ich mir mal reinziehen.
 
Zurück
Oben Unten