2009-06-27 61 views
2

我正在寻找一种简单的方法来制作一个Swing组件将所有收到的 事件转发给其父容器(或者甚至所有家长,直至根)。Swing:如何实现从子组件到父容器的所有事件转发?

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

首先,让我介绍一下我现有的解决方案。这是一个解决方法。

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

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

你能推荐一个更好的吗?

+0

我在某些swing事件上遇到了consume()方法,这个方法用于指示您在处理程序中使用了该事件。我认为相反的是你需要的。 – akarnokd 2009-06-27 14:27:04

+0

例如:鼠标点击,鼠标拖动(“激活”视觉图元素),各种热键,... – 2009-06-27 14:30:20

回答

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

}

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

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

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

+0

在旁注:关于Swing与Delphi相反的好事之一,它可以让你轻松在任何地方都可以注入多个事件处理程序,而Delphi的GUI模型基于单一的onSomething方法。 – akarnokd 2009-06-27 15:25:27

1
  • 无论你从组件的事件,在这种情况下,你注册,你需要的听众捕获事件。 Pro是您可以选择捕捉事件的地方,并且您可以选择按来源选择接收它们。 Con是你必须尽可能注册尽可能多的听众...
  • 或者使用玻璃面板,并在它传播到组件前捕获所有信息。在这种情况下,您将它们全部捕获,并且如果要将它们绑定到玻璃窗格下的组件,则必须编写自定义处理代码。 (假设您将玻璃窗格保留为空)以下是一个在事件到达组件之前捕获事件的示例,甚至可以将事件转发给所选组件:http://download.oracle.com/javase/tutorial/uiswing/components/rootpane.html#glasspane
  • 中间层是使用分层窗格创建透明组件任何你需要的东西)。

你也可以消耗()事件......你的主要问题是你要么在捕捉事件之前捕捉事件(从头开始编写自定义处理)它们之间或之后(并且从处理中产生一些干扰你可能需要破解),但是你不能通过继承任何东西来修改处理代码本身(或者你可以吗?从未见过......)。

相关问题