2010-10-14 37 views
8

J'ai lu le tutoriel définitif sur key bindings à quelques reprises, mais mon cache de cerveau ne semble pas assez grand pour contenir les processus complexes.Comment Java envoie-t-il les KeyEvents?

je débogage un problème de liaison clé (avéré que j'utilisais le mauvais état JComponent.WHEN_*), et je suis tombé sur un javadoc concis et hilarant pour le privé javax.swing.KeyboardManager paquet par un (malheureusement) ingénieur Java anonyme.

Ma question est la suivante: sauf pour KeyEventDispatcher qui est vérifié au tout début, est-ce que la description manque et/ou se trompe?

La classe KeyboardManager est utilisé pour aide les actions du clavier d'expédition pour les WHEN_IN_FOCUSED_WINDOW actions de style. Les actions avec d'autres conditions sont traitées directement dans JComponent.

Voici une description des symantics [sic] de la façon dont le clavier dispatching devrait fonctionner atleast [sic] que je comprends . KeyEvents sont expédiés au composant ciblé

Le gestionnaire de focus obtient le premier crack au traitement de cet événement . Si le gestionnaire de focus ne le souhaite pas, le JComponent appelle super.processKeyEvent() ceci permet aux écouteurs de traiter l'événement .

Si aucun des écouteurs ne "consomme" l'événement, les raccourcis clavier obtiennent un tir . C'est là que les choses commencent à devenir intéressantes. Tout d'abord, KeyStokes [sic] défini avec la condition WHEN_FOCUSED avoir une chance. Si aucun de ne souhaite l'événement, le composant se déplace alors que c'est [sic] les parents ont recherché des actions de type WHEN_ANCESTOR_OF_FOCUSED_COMPONENT. Si personne ne l'a encore pris, alors il finit ici. Nous recherchons ensuite les composants enregistrés pour les événements WHEN_IN_FOCUSED_WINDOW et leur envoyons . Notez que si aucun de ces n'est trouvé, alors nous passons l'événement à les menubars et nous leur laissons une fissure . Ils sont gérés différemment.

Enfin, nous vérifions si nous regardons un cadre interne. Si nous sommes et aucun voulu l'événement alors nous montons au créateur de l'InternalFrame et voir si quelqu'un veut l'événement (et ainsi de suite et ainsi de suite).


(UPDATE) Si vous avez déjà demandé cet avertissement gras dans le guide clé bindings:

Parce que l'ordre de recherche des composants est imprévisible, éviter de dupliquer WHEN_IN_FOCUSED_WINDOW fixations!

Il est à cause de ce segment 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; 
     } 
    } 

Ainsi, l'ordre de recherche est en fait prévisible, mais dépend évidemment de cette mise en œuvre particulière, il est donc préférable pas compter sur du tout. Gardez-le imprévisible.

(Javadoc et le code est de jdk1.6.0_b105 sur Windows XP.)

+0

Ceci est une belle analyse sur la gestion de KeyEvent ... mais je ne sais pas si c'est une question qui est responsable. – BoffinbraiN

+0

@BoffinbraiN: J'espérais que quelqu'un avec quelques douzaines de badges de swing dit quelque chose comme "au meilleur de ma connaissance c'est correct" :) –

+1

Oui, cela aurait certainement été préférable! Mais je pense que pour quelque chose d'aussi profond, c'est vraiment lié à la mise en œuvre, et vous avez scruté cette implémentation avec beaucoup plus de soin que la plupart des programmeurs diligents. ;) Bien sûr, ne pas faire dépendre votre code de ce détail spécifique, bien sûr. – BoffinbraiN

Répondre

1

Nous devons commencer le débogage de Component.dispatchEventImpl.
La simple lecture des commentaires source de la méthode devrait vous donner une idée parfaite de la manière dont les événements circulent dans Swing (vous pouvez également démarrer un niveau à partir de EventQueue.pumpEventsForHeirarchy).

Pour plus de clarté me donner un laissez extrait du code:

  1. Set horodatage et modificateurs de l'événement en cours .; Pré-répartiteurs. Effectuez tout reciblage/réorganisation nécessaire avant de notifier AWTEventListeners.
  2. Autoriser le Toolkit à transmettre cet événement à AWTEventListeners.
  3. Si personne n'a consommé un événement clé, autorisez KeyboardFocusManager à le traiter.
  4. Permettre aux méthodes d'entrée pour traiter l'événement
  5. prétraiter des événements spéciaux avant la livraison
  6. Livrer événement pour un traitement normal
  7. Traitement spécial pour 4.061.116. Crochet pour le navigateur pour fermer les boîtes de dialogue modales :)
  8. Autoriser l'homologue à traiter l'événement. Sauf KeyEvents, ils seront traités par les pairs après tous KeyEventPostProcessors (voir DefaultKeyboardFocusManager.dispatchKeyEvent())

vous pouvez maintenant correspondre au flux ci-dessus avec votre description pour déterminer si son droit ou non. Mais le fait est que vous ne devriez vraiment pas dépendre de javadocs de classes privées, la raison étant que les développeurs ne tiennent généralement pas à mettre à jour les commentaires des classes privées quand le code change, ainsi les docs peuvent devenir obsolètes.