2010-10-14 66 views
8

我已經幾次閱讀key bindings上的明確教程,但我的大腦緩存似乎不足以容納複雜的過程。 (不幸的是)匿名的Java工程師偶然發現了一個簡潔而熱鬧的javadoc,供私人包javax.swing.KeyboardManager使用。Java如何派發KeyEvent?

我的問題是這樣的:除了最初檢查的KeyEventDispatcher描述是否遺漏和/或錯誤?

的KeyboardManager類用於爲 WHEN_IN_FOCUSED_WINDOW風格動作 幫助調度鍵盤操作。 其他條件下的操作是直接在JComponent中處理的 。

這裏的symantics 如何鍵盤調度 應該ATLEAST [原文]工作,我 理解[原文]的描述。

KeyEvents被分派到 的焦點組件。焦點經理 在處理此事件時首先得到解決。如果焦點管理者不想要 ,那麼JComponent調用 super.processKeyEvent()這允許 聽衆有機會處理 事件。

如果沒有一個聽衆「消耗」 事件,則鍵綁定獲得 鏡頭。這是開始 變得有趣的地方。首先,用WHEN_FOCUSED 條件定義的KeyStokes [sic]得到一個機會。如果沒有 這些想要的事件,然後 組件行走,雖然它的[sic]父母 尋找類型 WHEN_ANCESTOR_OF_FOCUSED_COMPONENT的行動。

如果還沒有人接受它,那麼它 在這裏結束。然後,我們尋找 組件註冊爲 WHEN_IN_FOCUSED_WINDOW事件並激發 給他們。請注意,如果找不到這些 ,那麼我們會將該事件傳遞給菜單欄的 ,並讓它們在其上打開 。他們的處理方式不同。

最後,我們檢查我們是否在尋找內部框架的 。如果我們不是 需要事件,那麼我們將 移動到InternalFrame的創建者,如果有人想要事件( 等等),請參閱 。


(更新)如果你曾經想知道的鍵綁定引導這個大膽的警告:

因爲搜索組件的順序是不可預知的,避免重複WHEN_IN_FOCUSED_WINDOW綁定!

這是因爲該段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; 
     } 
    } 

所以搜索的順序其實是預見,但顯然依賴於這種特定的實現,所以最好依靠它根本就沒有。保持不可預測性。

(Javadoc和代碼是在WinXP jdk1.6.0_b105。)

+0

這是對KeyEvent處理的一個很好的分析......但我不知道它是否真的是一個可以回答的問題。 – BoffinbraiN 2011-05-08 10:09:55

+0

@BoffinbraiN:我希望有幾十個擺動徽章的人會說「就我所知,這是正確的」,這是最好的:) :) – 2011-05-09 13:47:23

+1

是的,那肯定會更好!但是我認爲對於這個深度的東西,它確實是針對特定實現的,而且你比大多數勤奮的程序員都仔細地仔細審查了這個實現。 ;)當然,最好不要讓你的代碼依賴於這個特定的細節。 – BoffinbraiN 2011-05-09 16:41:42

回答

1

我們需要從Component.dispatchEventImpl開始調試。
只需閱讀方法的源代碼註釋,就可以瞭解事件如何在Swing中流動的完美想法(您也可以從EventQueue.pumpEventsForHeirarchy開始一個級別)。

爲清楚起見只是讓我給從代碼的摘錄:

  1. 設置時間戳和當前事件的改性劑;預調度員。在通知AWTEventListeners之前,在這裏做任何必要的重定向/重新排序。
  2. 允許工具包將此事件傳遞給AWTEventListeners。
  3. 如果沒有人使用關鍵事件,則允許KeyboardFocusManager處理它。
  4. 允許輸入的方法來處理事件
  5. 程序前交付
  6. 之前的任何特殊事件的正常處理交付事件
  7. 爲4061116特殊處理:掛鉤瀏覽器關閉模式對話框:)
  8. 允許對等方處理事件。除此之外的KeyEvents,他們將所有的KeyEventPostProcessors後對被處理(見DefaultKeyboardFocusManager.dispatchKeyEvent())

現在你可以配合你的描述上述流程,以確定其是否正確與否。但關鍵是你不應該依賴私有類的javadoc,原因是開發人員通常不會在代碼改變時更新私有類的註釋,所以文檔可能會過時。