SWT Events global abhören

Bullitt

Mitglied
Hallo!

Ich möchte von einer SWT Applikation die Events global mithören. Das Display ist ja anscheinend die untersteEbene einer SWT-App. und man kann dieser ja auch einen Listener hinzufügen. Hab auch schon etwas in eine App. eingebaut:

Display display = new Display();
display.addListener(SWT.MouseDown, new Listener() {
public void handleEvent(Event event) {
System.out.println("Ereignis: " + event);
}
});
Shell shell = new Shell(display);
...
Dann wird die Oberfläche initialisiert usw...(funktioniert alles)

Nun sollte doch bei jedem Mausklick, bzw jedesmal, wenn der MouseButton gedrückt wird, das Event auf die Konsole ausgegeben werden. Tuts aber nicht!
Mach ich da was falsch, oder bin ich an der komplett falschen Stelle? Gibt anscheinend nicht viele Infos über solche Sachen...
 
Mach es anders, setze für jede Komponente einen Listener
der zusätzlich eine Methode in einem Singleton Object aufruft


sprich
Code:
public class GlobalListener {
  private GlobalListener instance = null;
  private GlobalListener() {}

  public static GlobalListener getInstance() {
      if(instance==null)
                 instance = new GlobalListener();
      return instance;
   }

   public void buttonClick() {
      // Hier implementieren
   }
}

Damit hast du ein Singleton und kannst diesen überall als Listener verwenden

Code:
button1.addMouseListener(new MouseAdapter() {
  public void mouseButtonDown(MouseEvent e) {
     GlobalListener.getInstance().buttonClick();
  }
}


Wenn du das ganze unbedingt in der Haupeinstiegsklasse nutzen willst, dann
instanzier dein Singleton dann mit einer Referenz auf diese Klasse . Dazu muss
getInstance() angepasst werden.

Code:
public static getInstance(MyMainClass mainClass) {
 . ....
// aufruf in dieser Main Klasse
GlobalListener globalListener = GlobalListener.getInstance(this);

Damit wird dann jeder Button-Klick an die von dir angegebene Methode, der von
dir angegeben Klasse delegiert.
 
hmmm...

Hallo und erstmal danke für das Interesse!

Das klingt gut, was du schreibst. Ich möchte in der Tat die Mainklasse als Einstieg benutzen, weil ich den Ursprungscode nicht verändern möchte.
Allerding verstehe ich nicht so ganz, was ich mit der mainClass-Referenz anfangen soll, bzw, wie ich die weiterverarbeiten soll.
Vielleicht hab ich da ein kleines Brett vorm Kopf, aber es wäre nett, wenn du mir da nen Tipp geben könntest.
Danke im Voraus...
 
Code:
public class MainClass {

 public MainClass() {
      createWindow(); 
  }

  public void createWindow() {
    Display display = new Display();
    Shell shell ... usw 
    ...
 }

  public static void main(String[] args) {
  }

  public void buttonClicked() {
         System.out.println("Ein button wurde geklickt");
  }

}


public class GlobalListener {
  private GlobalListener instance = null;
  private MainClass mainClass = null;
  private GlobalListener(MainClass mainClass) {
         this.mainClass = mainClass;
  }

  public static GlobalListener getInstance(MainClass mainClass) {
      if(instance==null)
                 instance = new GlobalListener();
      return instance;
   }

   public void buttonClick() {
        mainClass.buttonClicked();
   }
}

/// irgendwo im Code ein Button

button1.addMouseListener(new MouseAdapter() {
   public void mouseButtonDown(MouseEvent e) {
      GlobalListener globalListener = GlobalListener.getInstance(null);
      //die Instanz exitiert ja schon, deshalb brauchst du hier auch keine MainKlasse 
      // zu kennen.
      globalListener.buttonClick(); // leitet dann diesen Aufruf an die MainKlasse weiter
   }
}

Der ganze Trick besteht darin das du das sogenannte Singleton Pattern einsetzt.
Sprich du instanzierst in der Methode: getInstance(MainClass mainClass);
einen GlobalListener der eine Referenz auf die MainClass besitzt:
siehe:
this.mainClass = mainClass;
sprich die Referenz auf die MainKlasse ist als Member von GlobalListener gespeichert.
Und dieser GlobalListener gibt durch die statische Methode getInstance() immer ein
und und das Selbe Object von sich (GlobalListener) zurück, also erhälst du immer das
Object das eine Referenz auf mainClass besitzt, überall in deinem Code hast du somit
zugriff über GlobalListener, der als eine Art Delegate fungiert, auf die MainClass, du brauchst also nur die Methode buttonClick() an diesem einen GlobaListener object aufrufen, und dieser ruft daraufhin die Methode buttonClicked() bei MainClass auf.

Ist etwas kompliziert zu verstehen, darum bastel ein bischen damit, versuch dir das
im Debugger anzuschauen.
 
Naja...

Hallo!
Aha, ich verstehe, was du meinst. Aber dann muß ich ja praktisch bei jedem Button im Quellcode meinen Listener hinzufügen. Also bei Swing kann ich in der Main-Methode, und NUR in der Main-Methode einfach den AWTEventListener ans Toolkit der Applikation hängen und dieser horcht dann alle Events mit, die die Oberfläche auslöst. Und das, ohne überall den Listener hinzufügen zu müssen.
Das gibts bei SWT wohl nicht, oder? Ansonsten müßte ich ja überall in der Applikation, die ja sehr groß sein könnte, den Quellcode bearbeiten.
Viele Grüße...
 
Re: Naja...

Original geschrieben von Bullitt
Hallo!
Aha, ich verstehe, was du meinst. Aber dann muß ich ja praktisch bei jedem Button im Quellcode meinen Listener hinzufügen. Also bei Swing kann ich in der Main-Methode, und NUR in der Main-Methode einfach den AWTEventListener ans Toolkit der Applikation hängen und dieser horcht dann alle Events mit, die die Oberfläche auslöst. Und das, ohne überall den Listener hinzufügen zu müssen.
Das gibts bei SWT wohl nicht, oder? Ansonsten müßte ich ja überall in der Applikation, die ja sehr groß sein könnte, den Quellcode bearbeiten.
Viele Grüße...

Dank an Refactoring - Assistenten aller Eclipse, oder per Emacs dürfte diese Sache ein kleines Makro sein :)

Es kann sein das es auf den weg geht, den du beschrieben hast, ich sah noch keinen Anlass alle Events an einer Stelle abzufangen.

Aber wenn irgendwo abzufangen währe, dann würde es wohl an der stelle:

display.readAndDispatch();

abrufbar sien.
 
geschafft!

Hallo!
Nur zur Info und falls es interessiert ;)
Ich habs jetzt geschafft, einen Zentralen Listener ans Display zu hängen, der mir Applikationsweit alle Events mithört. Ging allerding nur mit Reflection (ein wenig schmutzig), da die addFilter-Methode aus dem Display privat ist, aber so gings:
Die Methode heißt "addFilter(int eventType, Listener listener) "
Code:
                // Klasse holen
                Class c = display.getClass();
                // Zu holende Methode hat zwei Parameter
                Class formparas[] = new Class[2];
                formparas[0] = int.class;
                formparas[1] = Listener.class;
		// Private Methode holen
                Method method = c.getDeclaredMethod("addFilter", formparas);
                // Private Methode zugänglich machen
                method.setAccessible(true);
		// Parameter der Methode erstellen
                Object param[] = new Object[2];
                param[0] = new Integer(SWT.MouseUp);
                param[1] = new Listener() {
                    public void handleEvent(Event event) {
                        System.out.println("Ereignis: " + event);
                    }
                };
		// Methode ausführen
                Object retVal = method.invoke(display, param);
Das ist genau so, wie ich es haben wollte. einen Listener an einer Stelle, ohne Eingriff in den Gesamt-Code.
Viele Grüße,
Bullitt
 
Zuletzt bearbeitet:
ist bisl her das Thema, aber ist doch aktuell, denke ich. Und einfacher ist es allemal
Code:
display.addFilter(SWT.KeyDown, new Listener() {
      public void handleEvent(Event event) {
             System.out.println("Ereignis: " + event.keyCode);
      }
});
man kann damit auf ESC reagieren, Cancel reslisieren(Button).
für die Maus ist dann SWT.MouseDown

Und ein Dank an Bullitt

Heinrich
 
Zurück