2010-10-14 6 views
8

Ich habe das definitive Tutorial auf key bindings ein paar Mal gelesen, aber mein Gehirn Cache scheint nicht groß genug, um die komplizierten Prozesse zu halten.Wie versendet Java KeyEvents?

Ich war eine Schlüsselbindungsproblem Debugging (stellte sich heraus ich die falsche JComponent.WHEN_* Zustand wurde mit), und ich stolperte über eine prägnante und urkomisch javadoc für das Paket privaten javax.swing.KeyboardManager durch eine (leider) anonym Java Ingenieur.

Meine Frage ist dies: außer KeyEventDispatcher, die am Anfang überprüft wird, fehlt die Beschreibung und/oder etwas falsch?

Die KeyboardManager Klasse wird für die zu Hilfe Versandtastaturaktionen verwendet WHEN_IN_FOCUSED_WINDOW Stil Aktionen. Aktionen mit anderen Bedingungen werden direkt in JComponent behandelt.

Hier ist eine Beschreibung der symantics [sic], wie Tastatur Dispatching funktionieren sollte atleast [sic], wie ich es verstehe .

KeyEvents werden an die fokussierte Komponente gesendet. Der Focus Manager bekommt den ersten Fehler bei der Verarbeitung dieses Ereignisses. Wenn der Fokus-Manager es nicht will, dann ruft die JComponent super.processKeyEvent() das ermöglicht Listener eine Chance, das Ereignis zu verarbeiten.

Wenn keiner der Listener das Ereignis " " konsumiert, erhalten die Tastatureingaben eine Aufnahme. Dies ist, wo Dinge zu beginnen interessant werden. Zuerst erhalten KeyStokes [sic], die mit dem WHEN_FOCUSED Zustand definiert werden, eine Chance. Wenn keiner von diese das Ereignis wünschen, dann geht die Komponente durch, es ist [sic] Eltern suchte nach Aktionen des Typs WHEN_ANCESTOR_OF_FOCUSED_COMPONENT.

Wenn noch niemand es genommen hat, dann geht es hier oben . Wir suchen dann nach Komponenten, die für WHEN_IN_FOCUSED_WINDOW Ereignisse registriert sind und feuern zu ihnen. Beachten Sie, dass wenn keine gefunden wird, übergeben wir das Ereignis an die Menüleisten und lassen Sie einen Riss bei ihm haben. Sie werden anders behandelt.

Schließlich überprüfen wir, ob wir einen internen Rahmen betrachten. Wenn wir sind und keine man wollte das Ereignis, dann bewegen wir uns auf den Ersteller des InternalFrame und sehen , wenn jemand das Ereignis will (und so weiter und so weiter).


(UPDATE) Wenn Sie jemals über diese mutige Warnung in der Tastenbelegungen Führung gefragt haben:

Da die Reihenfolge der Suche der Komponenten ist unberechenbar, Vermeiden Sie doppelte WHEN_IN_FOCUSED_WINDOW Bindungen!

Es ist wegen dieses Segments in KeyboardManager#fireKeyboardAction:

 Object tmp = keyMap.get(ks); 
    if (tmp == null) { 
     // don't do anything 
    } else if (tmp instanceof JComponent) { 
      ... 
    } else if (tmp instanceof Vector) { //more than one comp registered for this 
     Vector v = (Vector)tmp; 
      // There is no well defined order for WHEN_IN_FOCUSED_WINDOW 
      // bindings, but we give precedence to those bindings just 
      // added. This is done so that JMenus WHEN_IN_FOCUSED_WINDOW 
      // bindings are accessed before those of the JRootPane (they 
      // both have a WHEN_IN_FOCUSED_WINDOW binding for enter). 
      for (int counter = v.size() - 1; counter >= 0; counter--) { 
     JComponent c = (JComponent)v.elementAt(counter); 
     //System.out.println("Trying collision: " + c + " vector = "+ v.size()); 
     if (c.isShowing() && c.isEnabled()) { // don't want to give these out 
      fireBinding(c, ks, e, pressed); 
     if (e.isConsumed()) 
      return true; 
     } 
    } 

So ist die Reihenfolge der Suche ist tatsächlich vorhersehbar, aber natürlich abhängig von dieser speziellen Implementierung, so dass es besser ist, nicht vertrauen es überhaupt. Halte es unberechenbar.

(Javadoc und Code ist aus jdk1.6.0_b105 auf WinXP.)

+0

Dies ist eine gute Analyse zum KeyEvent-Handling ... aber ich weiß nicht, ob es tatsächlich eine Frage ist, die beantwortbar ist. – BoffinbraiN

+0

@BoffinbraiN: Ich hatte gehofft, dass jemand mit ein paar Dutzend Swing-Abzeichen so etwas wie "nach meinem besten Wissen ist es korrekt" sagt :) –

+1

Ja, das wäre definitiv besser gewesen! Aber ich denke, für so etwas tiefgründiges ist es wirklich implementierungsspezifisch, und Sie haben diese Implementierung viel sorgfältiger untersucht als die meisten fleißigen Programmierer jemals. ;) Am besten machen Sie Ihren Code natürlich nicht von diesem speziellen Detail abhängig. – BoffinbraiN

Antwort

1

Wir Debuggen von Component.dispatchEventImpl starten müssen.
Wenn Sie nur die Quellkommentare der Methode durchlesen, erhalten Sie die perfekte Vorstellung davon, wie Ereignisse in Swing fließen (Sie können auch eine Stufe von EventQueue.pumpEventsForHeirarchy aus starten).

Aus Gründen der Klarheit lassen Sie mich nur einen Auszug aus dem Code geben:

  1. Set Zeitstempeln und Modifikatoren des aktuellen Ereignisses .; Vorversender. Führen Sie hier eventuell notwendige Retargeting/Neuanordnungen durch, bevor wir AWTEventListeners benachrichtigen.
  2. Lassen Sie das Toolkit dieses Ereignis an AWTEventListeners übergeben.
  3. Wenn kein Schlüsselereignis verbraucht wurde, lassen Sie ihn vom KeyboardFocusManager verarbeiten.
  4. zulassen Eingabemethoden der Veranstaltung
  5. Pre-Prozess besondere Ereignisse vor der Auslieferung
  6. Deliver Ereignis für die normale Verarbeitung
  7. Sonderbehandlung für 4.061.116 zu verarbeiten. Haken für Browser schließen modale Dialoge :)
  8. Erlaube dem Peer, das Ereignis zu verarbeiten. Außer KeyEvents, werden sie von Peer nach allen KeyEventPostProcessors verarbeitet werden (siehe DefaultKeyboardFocusManager.dispatchKeyEvent())

Nun können Sie den obigen Ablauf mit Ihrer Beschreibung entsprechen, ob ihr Recht zu bestimmen, oder nicht. Aber der Punkt ist, Sie sollten wirklich nicht auf Javadocs von privaten Klassen abhängen, der Grund ist, dass die Entwickler normalerweise nicht kümmern, um die Kommentare von privaten Klassen zu aktualisieren, wenn Code ändert, so dass die Dokumente möglicherweise veraltet werden.