# Eigenen Listener schreiben



## Benji0815 (3. Feb 2010)

Hallo,

ich möchte einen eigenen Listener schreiben. 

1.)Ich möchte Ergebnisse die mein Programm liefert z.B. die aktuelle Zahl, die mir ein Counter beim Bearbeiten von Daten liefert regelmäßig an die GUI übermitteln. 

Die GUI soll dann automatisch sagen, 1 Datei bearbeitet, 2, 3, 4, ... Ich zeige das Ganze dann z.B. in einem Textfeld der GUI an. Ich starte das Programm einmal über einen Button in der GUI und es fängt an Daten zu bearbeiten. Das hochzählen soll jetzt über den Listener geschehen ohne das ich jedesmal einen Button drücken muss.

Wie muss ich den Listener aufbauen? Gibt es ein bestimmtes Event, dass ich hier verwenden kann. Bin für jede Hilfe dankbar! Auch über einen Link oder Tutorial, der das ganze verständlich erklärt.

2.)Der Listener soll eine Methode neuesErgebnis(Ergebnis erg) haben. Zur GUI habe ich von meinem Programm aus eine Schnittstelle. In dieser Schnittstelle gibt es eine addMyListener(MyListener listener)
Methode und auch eine removeMyListener(MyListener listener) Methode. Das habe ich so im Netz gesehen. Kann ich dahinter eine ArrayList stellen in die ich Listener adden und removen kann oder darf immer nur ein Listener geaddet werden.

Verstehe den Sinn des adden und removen nicht ganz. Kann mir jemand helfen?


----------



## MrWhite (3. Feb 2010)

Ist doch nicht weiter schwer.

Deine Klasse, die das Ergebnise berechnet, braucht eine Liste von Listenern.

Wenn ein neues Ergebnis fertig ist, wird einfach die Liste abgeklappert und für jedes Element in der Liste die Methode neuesErgebnis aufgerufen.

Die Methode neuesErgebnis bekommt du über ein Interface in die GUI. Deine Fenster und Panels, die auf dieses Ergebnis reagieren sollen, müssen dieses Interface implementieren.

Das ganze nennt man auch Observer-Pattern.


----------



## Benji0815 (5. Feb 2010)

Hallo,

die Aussage mit dem Observer-Pattern verwirrt mich ein wenig. Das Observer-Pattern ist eine Möglichkeit so etwas zu realisieren, ich möchte aber einen eigenen Listener schreiben. Ist das wirklich das selbe?

Kennt jemand ein gutes Tutorial, wie ich einen eigenen Listener schreiben kann? Ich komme damit leider noch nicht so gut zurecht.

Ich habe ein größeres Javaprojekt und zwei Schnittstellen eine zur GUI und eine zu einer externen Bibliothek, die verschiedene Operationen durchführt. In der externen Bibliothek habe ich einen Counter.
Den jeweils aktuellen Wert des Counters möchte ich über die Schnittstelle zur Bib. an die GUISchnittstelle weiterreichen. Die aktuellen Counterwerte sollen in der GUI regelmäßig aktualisiert werden. In der GUI Schnittstelle habe ich z.B. eine addMyListener(MyListener listener) methode. Diese legt die Listeners in einer Liste ab. Es gibt auch eine remove Methode.

Und ich habe eine Listener Interface. Mit einer Methode "neuesErgebnis(Ergebnis erg)"

Kann vielleicht jemand versuchen, mir die groben Schritte zur Listener Implementierung nochmal kurz zu erklären. Vielleicht anhand der Teile die ich schon habe und was noch benötigt wird.

Vielen Dank!


----------



## Michael... (5. Feb 2010)

Das Observer Pattern ist ja nur ein Muster für Listener. Es beschreibt wie man eine solche Listenerbeziehung aufbauen kann.
Es heisst nicht, dass Du die java Klassen Observer und Observable verwenden must (die sind nur Implementierungen des Patterns), man kann durchaus ein eigenes Listener Interface definieren/benutzen.


----------



## Benji0815 (5. Feb 2010)

Gut dann habe ich das richtig verstanden. Danke!

Jetzt bräuchte ich nur noch ein Tutorial wo mal so ein eigener Listener mit allem drum und dran implementiert wird, damit ich mich da mal einlesen kann.

Hab beim Googeln eine Seite gefunden, die mir halbwegs weiterhilft(Java Listeners), würde mich aber freuen, wenn Ihr vielleicht noch weitere Tutorials kennen würdet.


----------



## MrWhite (5. Feb 2010)

Benji, das ist doch super einfach und ein Model, dass du nicht nur für Listener sondern überall brauchen kannst, wo es um Publish-Subscribe Beziehungen geht!

Lass mich mal erklären.

Stell dir das ganze als Abonnement-Model vor.

Die Bravo , der Spiegel, die Zeit etc haben Abonnenten.

Will jemand die Bravo oder den Spiegel oder die Zeit abonnieren, meldet er sich dort an und lässt sich in eine Liste eintragen.

Kommt die neue Zeitschrift raus, bekommt sie jeder Abonennt automatisch zugestellt und kann damit machen was er will.


Soweit so gut. Sowas lässt sich doch einfach in Code übersetzen.

Was haben die Bravo und der Spiegel und die Zeit gemeinsam?
Abonennten können sich bei Ihnen anmelden damit ihnen die neuesten Zeitschriften zugestellt werden. Wie die einzelnen Zeitschriftenverlage die Abonnenten intern managen, bleibt ihnen überlassen. Deswegen erstellen wir ein Interface.


```
public interface Zeitschriftenverlag
{
     void registriereAbonnent(Abonennt a);

     //eigentlich kommen hier noch Methoden wie unregister etc.
}
```

Beispiel wie die Bravo das macht, die haben alle in einer Liste:


```
public class BravoVerlag implements Zeitschriftenverlag
{
    private List<Abonnent> abonnenten = new ArrayList<Abonnent>();    

    public void registriereAbonnent(Abonnent a)
    {
         abonnenten.add(a);
    }

    public void neueZeitschriftAnAbonnentenAusliefern()
    {
          for(Abonnent a : abonnenten) a.zeitschriftBekommen(this.getNeueAusgabe());
    }
}
```


Was haben die Abonennten gemeinsam? Das können Firmen oder Ottonormalverbraucher sein. Die machen eventuell unterschiedliche Dinge mit der Zeitschrift. Eine Firma will vielleicht nur gucken ob ihre Werbetexte richtig gedruckt wurden, den Ottonormalverbraucher interessiert wahrscheinlich eher der Inhalt der Zeitschrift. Auf jedenfall gucken sie alle in die Zeitschrift.


```
pulbic interface Abonnent
{
     void zeitschriftBekommen(Zeitschrift z);
}


public class Ottonormalverbraucher implements Abonnent
{
     public void zeitschriftBekommen(Zeitschrift z)
     {
          if(z instanceof Bravo)
          {
                nutzeAlsKlopapier(z);
          }
     }
}
```




So sieht das dann als main aus:


```
public static void main(String[] args)
{
        BravoVerlag b = new BravoVerlag();
        ZeitVerlag z = new ZeitVerlag();

        Ottonormalverbraucher hans = new Ottonormalverbraucher();
       Ottonormalverbraucher dampf = new Ottonormalverbraucher();
 
       b.registriereAbonnent(hans);
       b.registriereAbonnent(dampf);
       z.registriereAbonnent(hans);
}
```


----------



## Benji0815 (5. Feb 2010)

Super! Danke Dir für das anschauliche Beispiel.


----------



## Benji0815 (5. Feb 2010)

Trotz des sehr ausführlichen und guten Beispiels habe ich damit leider noch Probleme. Ich steh irgendwie total auf dem Schlauch und habe Schwierigkeiten mir das in Verbindung mit dem aktualisieren einer GUI vorzustellen. 

Das Prinzip dachte ich habe ich verstanden, bei der Umsetzung wird mir aber klar, dass ich es wohl doch nicht so gut verstanden habe.

Ich habe bei mir ja ein ListenerInterface "neuesErgebnis(Ergebnis erg)" und ich habe in meiner Schnittstelle zur GUI eine Methode um Listeners zu adden.

Kurz zum Aufbau meines Programms. Ich habe die Bibliothek, die die eigentliche Arbeit ausführt. Diese kann über eine Schnittstellenklasse (kein Interface) angesprochen werden. Darüber gibt es nochs eine Schnittstellenklasse für die GUI und darüber die GUI. In der GUI konfigurtiert man das Programm und gibt die Konfigdaten über die beiden Schnittstellenklassen an die Bibliothek weiter. Anders herum liefert die Bib. Ergebnisse an die GUI. Die Schnittstelenklasse zur GUI beinhaltet die Methode zum adden eines Listeners. 

Mir ist nicht so richtig klar, wo ich z.B. die Methode zum adden eines Listeners aufrufen soll? Wo (z.B. untere Schnittstellenklasse?) befindet sich die Methode die die Liste der Listener enthält und mit for durchläuft und wie starte ich sie? Mir ist noch nicht klar wann ich mit der add Methode einen neuen Listener erzeuge und wo? Wenn ich z.B. Informationen von verschiedenen Countern habe, einer zählt die Anzahl der HTML Dateien ein anderer die Anzahl der .txt Dokumente. Diese Werte möchte ich jetzt nach oben in die GUI reichen erzeuge ich dann einen Listener und wo rufe ich die add(Listener) Methode auf.


----------



## MrWhite (6. Feb 2010)

Hallo Benji,

bei dir müsste das in etwa so aussehen:

Nehmen wir mal an, deine Bibliothek ist eine Klasse:


```
public class MyLib
{
    public void doConfig()
    {
         //snip
    }

    public int rechnung1()
    {
           // snip;
    }

    public int rechnung2()
    {

         // snip;
    }
}
```

Dann baust du dir eine Wrapper-Klasse dafür, die die Listener entgegennimmt:


```
public class MyLibWrapper extends MyLib
{
         private List<ErgebnisListener> listener = new ArrayList<ErgebnisListener>();
         public void addListener(ErgebnisListener l)
         {
              this.listener.add(l);
         }

         public void removeErgebnisListener(Listener l)
         { 
             this.listener.remove(l);
         }

          public void fireNeuesErgebnisEvent(int ergebnis)
          {
               for (ErgebnisListener l : listeners) l.neuesErgebnis(ergebnis);
          }

           public void rechnung1Durchführen()
           {
                 int erg = this.rechnung1();
                 fireNeuesErgebnisEvent(erg);
           }
}
```

ErgebnisListener ist das Interface für deine Listener:


```
public interface ErgebnisListener
{
      public void neuesErgebnis(int erg);
}
```


Dann hast du ein GUI, das sieht z.B. so aus:


```
public class MyFrame extends JFrame implements ErgebnisListener
{
      private MyLibWrapper wrapper;

      public void doConfig()
      { 
             wrapper = new MyLibWrapper();
             wrapper.doConfig();
             //Hier wird z.B. mal das Hauptfenster als Ergebnislistener registriert
             wrapper.addListener(this);
      }

      public static void main(String[] args)
      {
             MyFrame f = new MyFrame();
            

           //config sachen durchführen
            f.doConfig();

             //snip;

           f.getWrapper().addListener(anderenListenerHinzufügen)
      }
}
```

Am besten du fügst deine Listener zum Wrapper, der die Funktionalität deiner Bibliothek kapselt und die Ergebnisse berechnet hinzu, wenn alle Konfigurationen abgeschlossen sind.


----------



## Benji0815 (6. Feb 2010)

Danke für die ausführliche Erklärung!


----------



## Benji0815 (6. Feb 2010)

Wenn ich jetzt eines der Ergebnisse in einem JTextField anzeigen möchte, das sich regelmäßig aktualisiert, also von der Bib. immer den aktuellen counterwert bekommt, kann ich das dann mit
der neuesErgebnis-Methode wie unten im Code machen. Wo befindet sich rechnung1Durchführen().
Was ist unten mit anderenListenerHinzufügen gemeint?


```
public class MyFrame extends JFrame implements ErgebnisListener
{
      private MyLibWrapper wrapper;

      public void doConfig()
      { 
             wrapper = new MyLibWrapper();
             wrapper.doConfig();
             //Hier wird z.B. mal das Hauptfenster als Ergebnislistener registriert
             wrapper.addListener(this);
              //added by Benji//
             //gehört das hier hin???
             wrapper.rechnung1Durchführen();
      }

       //added by Benji//Wird  diese Methode überhaupt ausgeführt? Funktioniert das so?
       // Wie wird neuesErgebnis aufgerufen? Durch rechnung1Durchführen()?
       public void neuesErgebnis(int erg){
            jtextfieldrechnung1.setText(erg);
       }

      //added by Benji//



      public static void main(String[] args)
      {
             MyFrame f = new MyFrame();
            

           //config sachen durchführen
            f.doConfig();

             //snip;

            //added by Benji//
           //Was ist mit anderenListenerHinzufügen gemeint? Sind das auch ErgebnisListener,die ich erstellt habe?
           //Oder ist hier einfach Raum für weitere Listener wie z.B. einen ActionListener?

           f.getWrapper().addListener(anderenListenerHinzufügen)
      }
}
```


----------



## MrWhite (7. Feb 2010)

Benji0815 hat gesagt.:


> Wenn ich jetzt eines der Ergebnisse in einem JTextField anzeigen möchte, das sich regelmäßig aktualisiert, also von der Bib. immer den aktuellen counterwert bekommt, kann ich das dann mit
> der neuesErgebnis-Methode wie unten im Code machen.



Ja, das sollte eigentlich sogar so sein, wenn du mit GUIs hantierst. Nur wenn du sehr viele Dinge mit dem GUI bei so einem Event anstellen wilslt, rentiert es sich, dafür eine eigene Methode zu schreiben.



> Wo befindet sich rechnung1Durchführen().



Du hast ja eine Bibliothek. Aber die kann keine Listener registrieren. Deswegen baust du dir einen sog. "Wrapper", der die Funktionen deiner Bibliothek ausführt und die Listener benachrichtigt. Im Wrapper befindet sich also diese Methode. Sie ruft die Bibliothek auf, zwischenspeichert das Ergebnis und teilt das dann allen Listenern mit.



> Was ist unten mit anderenListenerHinzufügen gemeint?



Du kannst doch beliebig viele Listener hinzufügen! Z.B. könntest du an deinen Wrapper noch einen Netzwerkservice anschliessen, der auf neue Ergebnisse wartet. Oder irgendeine Routine, die bei einem neuen Ergebnis irgendwas in Gang setzt. Allerdings wäre es für mehrere Listener vermutlich suboptimal, den Wrapper im Frame zu halten. Den sollte man dann lieber andersweitig zur Verfügung stellen.


----------



## Benji0815 (7. Feb 2010)

> Du hast ja eine Bibliothek. Aber die kann keine Listener registrieren. Deswegen baust du dir einen sog. "Wrapper", der die Funktionen deiner Bibliothek ausführt und die Listener benachrichtigt. Im Wrapper befindet sich also diese Methode. Sie ruft die Bibliothek auf, zwischenspeichert das Ergebnis und teilt das dann allen Listenern mit.



OK, hab ich soweit verstanden, was ich hier eigentlich wissen wollte, war wo führe ich "rechnung1Durchführen()" aus? In der GUI wie unten beschrieben?

Aber eigenlich sollte das das doch an der Stelle ausgeführt werden, wo mein aktueller Counter berechnet wird? Dazu muss ich dann aber irgendwie eine Instanz meiner GUI Klasse von der ich das Prog. gestartet habe und in der die Ergebnisse angezeigt werden zu dieser Klasse runterreichen


```
public class MyFrame extends JFrame implements ErgebnisListener
{
      private MyLibWrapper wrapper;
 
      public void doConfig()
      { 
             wrapper = new MyLibWrapper();
             wrapper.doConfig();
            
             wrapper.addListener(this);
             
             wrapper.rechnung1Durchführen(); //Hier??????????????????????


//usw....
```


----------



## MrWhite (8. Feb 2010)

Das führst du dort aus, wo die Rechnung durchgeführt werden muss/soll. Kann z.B. auf einen Klick-Event von einem Button durchgeführt werden. Das hängt also ganz davon ab, wann und wo du die rechnung1() deiner Bibliothek durchführen willst.


----------

