2009-06-27 3 views
2

スウィングコンポーネントをすべて受信した イベントをその親コン​​テナ(またはルートまでのすべての親)に転送する簡単な方法を探しています。スイング:サブコンポーネントから親コンテナへのすべてのイベントの転送を達成する方法

編集
どこが必要ですか?私はダイアグラムエディタを持っています。コンポーネントは、キーを押して マウスクリックを転送する必要があります(ユーザーがそのコンポーネントのサブエレメント をクリックすると、アクティブに設定されます)。

まず、私の既存の解決策を提示しましょう。これは少しの回避策です。

public interface IUiAction { 
void perform(Component c); 
} 

public static void performRecursiveUiAction(Container parent, IUiAction action) { 
if (parent == null) { 
    return; 
} 

for (Component c : parent.getComponents()) { 
    if (c != null) { 
    action.perform(c); 
    } 
} 

for (Component c : parent.getComponents()) { 
    if (c instanceof Container) { 
    performRecursiveUiAction((Container) c, action); 
    } 
} 
} 

/** 
* 1) Add listener to container and all existing components (recursively). 
* 2) By adding a ContainerListener to container, ensure that all further added 
* components will also get the desired listener. 
* 
* Useful example: Ensure that every component in the whole component 
* tree will react on mouse click. 
*/ 
public static void addPermanentListenerRecursively(Container container, 
    final IUiAction adder) { 

final ContainerListener addingListener = new ContainerAdapter() { 
    @Override 
    public void componentAdded(ContainerEvent e) { 
    adder.perform(e.getChild()); 
    } 
}; 

// step 1) 
performRecursiveUiAction(container, adder); 

// step 2) 
performRecursiveUiAction(container, new IUiAction() { 
    @Override 
    public void perform(Component c) { 
    if (c instanceof Container) { 
    ((Container) c).addContainerListener(addingListener); 
    } 
    } 
}); 
} 

使用法:

addPermanentListenerRecursively(someContainer, 
    new IUiAction(
    @Override 
    public void perform(Component c){ 
     c.addMouseListener(somePermanentMouseListener); 
    } 
) 
); 

コードを見ていることで、あなたはそれが良いコンセプトだと思いますか?
私の現在のコンセプトの問題は、リスナーが手動で指定されたイベントのみを転送することです。

あなたはより良いものを提案できますか?

あなたはそのためにスイングのKeyStrokeの機能を使用することができます:私は物事のキーボード側のための提案を持って、あなたのシナリオに基づいて

+0

あなたのハンドラでイベントを消費したことを示すために使用されるいくつかのスイングイベントで、consume()メソッドが発生しました。私はあなたが必要としているのはその反対ですと思います。 – akarnokd

+0

例:マウスクリック、マウスドラッグ(ビジュアル図要素を「アクティブにする」)、あらゆる種類のホットキー、... –

答えて

2

これは、ビュー内のすべてのコンポーネントが同じマウスイベントを処理すると、少し面倒に思えるようです。つまり、ユーザーがアイテム1をドラッグした場合、アイテム2も同様のイベントを処理しますか?私が正しく理解していれば、thisthis.parentthis.parent.parentのマウス操作を処理することをthisにしようとしています。その場合、再帰は上向きであり、下向きではありません。

あなたは、このようなInterfaceを作成することができます。

public interface MyInterface() { 
    public void performSpecialAction(Event event); 
} 

あなたは、あなたのコンテナがこのインターフェイスを実装しています。あなたのコンポーネントは、その適切なイベント処理に、このコールを組み込む必要があるでしょう:

public static void performRecursiveUiAction(Component comp, Event event) { 
    if (comp.getParent() == null) { 
    return; 
    } 
    if (comp.getParent() instanceof MyInteface) { 
    ((MyInterface)comp.getParent()).performSpecialAction(event); 
    } 
    ThisUtility.performRecursiveUiAction(comp.getParent(), event); 

}

+0

はい、上向きの再帰です。 –

3

あなたは「グローバル」イベントを登録することができます

JRootPane rp = getRootPane(); 

KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0, false); 
rp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(ks, "F2"); 
rp.getActionMap().put("F2", new AbstractAction() { 
public void actionPerformed(ActionEvent e) { onF2Action(); } }); 

この方法ショートカットのハンドラ。

あなたのケースではいくつかの制限があります。

マウスイベントの場合、すべての対象コンポーネントにMouseAdapterインスタンスを追加する再帰関数を作成します。たとえば、

void addToAll(Container c, MouseAdapter a) { 
    for (Component p : c.getComponents()) { 
     if (p instanceof InterrestingComponent) { 
      p.addMouseListener(a); 
      p.addMouseMotionListener(a); 
      p.addMouseWheelListener(a); 
     } else 
     if (p instanceof Container) { 
      addToAll((Container)p, a); 
     } 
    } 
} 

コンセプトをキャプチャするだけです。さまざまなコンポーネントに異なるレシーバーまたは複数のレシーバーが必要な場合があります。

編集:申し訳ありません、私は誤ってMouseAdapterの代わりにWindowAdapterを使用しました。

+0

脇役に:Delphiとは逆にスイングについての良いことの1つは、 DelphiのGUIモデルは、私の時間に単一のonSomethingアプローチに基づいていましたが、実際にはどこでも複数のイベントハンドラを注入することができました。 – akarnokd

1
  • どちらかあなたがコンポーネントからイベントを取得し、この場合にはあなたが必要なリスナーに登録イベントをキャプチャします。 Proでは、イベントをキャプチャする場所を選択でき、ソースによってイベントを選択的に受信することができます。あなたが持っているソースの数だけ多くのリスナーを登録しなければならないということです。
  • また、ガラスパネルを使用して、コンポーネントに伝播する前にすべてをキャプチャします。この場合、それらをすべてキャプチャし、ガラスペインの下にあるコンポーネントに結び付けたい場合は、カスタム処理コードを記述する必要があります。 (あなたがあなたのガラスペインを空にしていたと仮定...)ここでは、コンポーネントに到達する前にイベントをキャプチャし、選択したものにイベントを取り込む例を示します。http://download.oracle.com/javase/tutorial/uiswing/components/rootpane.html#glasspane
  • 中層は、透明なコンポーネントを作成するためにあなたが必要とするものの上にあるもののようなもの)。

また、あなたもイベントを消費することができます...あなたの主な問題は、スイングハンドルの前にイベントをキャプチャして(そして最初からカスタムハンドリングを書く)か、あなたはハックする必要があるかもしれませんが)、何かをサブクラス化することによって(または今まで見たことがないように)、処理コード自体を変更することはできません。