Swing:如何实现从子组件到父容器的所有事件的转发?

我正在寻找一种直接的方法来使Swing组件将所有收到的事件转发到其父容器 (甚至是所有父级到root)。

编辑
我在哪里需要这个? 我有一个图表编辑器。 组件必须转发按键和鼠标单击(一旦用户单击该组件的子元素,就将其自身设置为“活动”)。

首先,让我提出我现有的解决方案。 这是一个解决方法。

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); } ) ); 

通过查看代码,你会说这是一个很好的概念吗?
我当前概念的问题是:它只转发事件,为其手动指定了一个监听器。

你能建议一个更好的吗?

如果视图中的每个组件都处理相同的鼠标事件,这看起来会有点棘手。 即,如果用户拖动项目1项目2也将处理这些事件? 如果我理解正确,你希望有thisthis.parentthis.parent.parent处理鼠标操作。 在这种情况下,递归将是向上的,而不是向下的。

你可以像这样创建一个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); 

}

根据您的情况,我对键盘方面有一个建议:

你可以使用swing的KeyStroke工具:

 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(); } }); 

这样,您可以为快捷方式注册“全局”事件处理程序1

1虽然它可能在您的情况下有一些限制。

对于鼠标事件的情况,我将创建一个递归函数,它将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); } } } 

只是为了捕捉这个概念。 对于各种组件,您可能需要不同的或多个接收器。

编辑:对不起,我不小心说WindowAdapter而不是MouseAdapter。

  • 您可以从组件中获取事件,在这种情况下,您可以在需要捕获事件的位置注册侦听器。 Pro是您可以选择捕获事件的位置,您可以选择通过源选择性地接收它们。 Con是你必须尽可能多地注册听众…
  • 或者使用玻璃窗格,并在传播到组件之前捕获所有窗格。 在这种情况下,您可以捕获它们,如果要将它们绑定到玻璃窗格下的组件,则必须编写自定义处理代码。 (假设你把你的玻璃窗保持为空……)这是一个在事件到达组件之前捕获事件的例子,甚至将事件转发到选定的组件: http : //download.oracle.com/javase/tutorial/uiswing/components /rootpane.html#glasspane
  • 中间地带是使用分层窗格创建透明组件(像玻璃窗一样),无论您需要什么。

你也可以使用()事件…你的主要问题是你要么在摆动手柄之前捕获事件(并从头开始编写自定义处理)它们之后或之后的权衡(并且有一些干扰来处理你可能需要黑客攻击) ),但你不能通过子类化任何东西来修改处理代码本身(或者你可以?到目前为止从未见过……)。