Java Swing:如何将所有事件从子组件转发到父容器?

Java Swing:如何将所有事件从子组件转发到父容器?,java,user-interface,swing,events,Java,User Interface,Swing,Events,我正在寻找一种简单的方法,使Swing组件向前移动所有接收的内容 将事件添加到其父容器(甚至是根目录下的所有父容器) 编辑: 我在哪里需要这个?我有一个图表编辑器。部件必须向前按键并按下 鼠标单击(在用户单击子元素时将其自身设置为“活动”) (属于该组成部分) 首先,让我介绍一下我现有的解决方案。这是一个解决办法 public interface IUiAction { void perform(Component c); } public static void performRecurs

我正在寻找一种简单的方法,使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);
    }
  )
);
通过查看代码,您认为这是一个好的概念吗?
我当前概念的问题是:它只转发事件,而侦听器是手动指定的


你能推荐一个更好的吗?

根据你的情况,我有一个关于键盘方面的建议:

您可以使用swing的击键功能:

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(); } });
通过这种方式,您可以为shortcuts1注册“全局”事件处理程序

1尽管它在您的情况下可能有一些限制

对于mouse事件,我将创建一个递归函数,它向每个目标组件添加一个
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。

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

您可以创建一个
界面
,如下所示:

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

  • 要么从组件获取事件,在本例中,注册需要捕获事件的侦听器。Pro是指您可以选择捕获事件的位置,并且可以选择按源有选择地接收事件。缺点是你必须注册尽可能多的监听器,尽可能多的源代码
  • 或者使用玻璃窗格,并在其传播到组件之前捕获所有。在本例中,您将捕获它们,如果您想将它们绑定到玻璃窗格下的组件,则必须编写自定义处理代码。(假设您将玻璃窗格保持为空…)下面是一个示例,它在事件到达组件之前捕获事件,甚至将事件转发给选定的组件:
  • 中间点是使用分层窗格在您需要的任何组件之上创建透明组件(类似于玻璃窗格的东西)

您还可以使用()事件。。。您的主要问题是一个折衷方案,即您要么在swing句柄之前捕获事件(并从头编写自定义处理),要么在它们之后捕获事件(并且可能会受到一些处理的干扰,您可能不得不对其进行破解),但您不能通过子类化任何内容来修改处理代码本身(或者您可以?到目前为止从未见过…).

我在一些swing事件上遇到了consume()方法,该方法用于指示您在处理程序中使用了该事件。我认为你需要的恰恰相反。例如:鼠标点击、鼠标拖动(以“激活”可视化图表元素)、各种热键……旁注:与Delphi相反,Swing的一个优点是,它使你可以方便地在任何地方实际插入多个事件处理程序,而Delphi的GUI模型是基于我那个时代的onSomething方法的。