9

キーバインディングに関する明確なチュートリアルを数回読んだことがありますが、私の脳のキャッシュは複雑なプロセスを保持するのに十分な大きさではないようです。

私はキーバインディングの問題をデバッグしていました(間違った条件を使用していたことが判明しました)、そして(残念ながら)匿名のJavaエンジニアによってJComponent.WHEN_*プライベートなパッケージの簡潔で陽気なjavadocに出くわしました。javax.swing.KeyboardManager

KeyEventDispatcher私の質問はこれです:最初にチェックされているものを除いて、説明は何かを見逃したり、間違えたりしますか?

KeyboardManagerクラスは、WHEN_IN_FOCUSED_WINDOWスタイルのアクションのキーボードアクションをディスパッチするために使用されます。他の条件のアクションは、JComponentで直接処理されます。

これは、私が理解しているように、キーボードディスパッチが少なくとも[原文のまま]どのように機能するかについてのシマンティクス[原文のまま]の説明です。

KeyEventsは、フォーカスされたコンポーネントにディスパッチされます。フォーカスマネージャーは、このイベントの処理で最初のクラックを取得します。フォーカスマネージャーがそれを望まない場合、JComponentはsuper.processKeyEvent()を呼び出します。これにより、リスナーはイベントを処理する機会が与えられます。

リスナーの誰もがイベントを「消費」しない場合、キーバインディングはショットを取得します。これは物事が面白くなり始めるところです。まず、WHEN_FOCUSED条件で定義されたKeyStokes[原文のまま]がチャンスを得ます。これらのいずれもイベントを必要としない場合、コンポーネントは、親がタイプ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からのものです。)

4

1 に答える 1

2

Component.dispatchEventImplからデバッグを開始する必要があります。
メソッドのソースコメントを読むだけで、Swingでイベントがどのように流れるかを完全に理解できるはずです(EventQueue.pumpEventsForHeirarchyから1レベル上から開始することもできます)。

わかりやすくするために、コードからの抜粋を示します。

  1. 現在のイベントのタイムスタンプと修飾子を設定します。; 事前ディスパッチャ。AWTEventListenersに通知する前に、ここで必要なリターゲティング/並べ替えを行ってください。
  2. ToolkitがこのイベントをAWTEventListenersに渡すことを許可します。
  3. キーイベントを消費した人がいない場合は、KeyboardFocusManagerがそれを処理できるようにします。
  4. 入力メソッドがイベントを処理できるようにする
  5. 配信前に特別なイベントを前処理します
  6. 通常の処理のためにイベントを配信します
  7. 4061116の特別な処理:ブラウザのフックでモーダルダイアログを閉じます。:)
  8. ピアがイベントを処理できるようにします。KeyEventsを除いて、すべてのKeyEventPostProcessorsの後にピアによって処理されます(DefaultKeyboardFocusManager.dispatchKeyEvent()を参照)

これで、上記のフローを説明と照合して、その権利があるかどうかを判断できます。ただし、重要なのは、プライベートクラスのjavadocsに実際に依存するべきではないということです。その理由は、開発者は通常、コードが変更されたときにプライベートクラスのコメントを更新する必要がないため、ドキュメントが廃止される可能性があるためです。

于 2011-06-18T05:56:57.300 に答える