【问题标题】:Swing: How to achieve forwarding of all events from subcomponents to parent container?Swing:如何实现所有事件从子组件到父容器的转发?
【发布时间】:2010-11-06 09:02:42
【问题描述】:

我正在寻找一种直接的方法来使 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);
    }
  )
);

通过查看代码,您认为这是一个好概念吗?
我当前概念的问题是:它仅转发事件,为此手动指定了侦听器。

你能推荐一个更好的吗?

【问题讨论】:

  • 我在一些摇摆事件上遇到了consume() 方法,该方法用于指示您在处理程序中消费了该事件。我认为你需要的恰恰相反。
  • 例如:鼠标点击、鼠标拖动(“激活”可视化图表元素)、各种热键……

标签: java user-interface swing events


【解决方案1】:

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

您可以使用 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。

【讨论】:

  • 附注:与 Delphi 相比,Swing 的优点之一是它使您可以轻松地在几乎任何您想要的地方注入多个事件处理程序,而 Delphi 的 GUI 模型基于单一的 onSomething 方法我的时间。
【解决方案2】:

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

您可以像这样创建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】:
    • 您可以从组件中获取事件,在这种情况下,您可以在需要捕获事件的地方注册侦听器。优点是您可以选择捕获事件的位置,并且您可以选择按源选择性地接收它们。缺点是您必须注册尽可能多的听众...
    • 或者使用玻璃窗格,在它传播到组件之前捕获所有内容。在这种情况下,您将全部捕获它们,并且如果要将它们绑定到玻璃窗格下的组件,则必须编写自定义处理代码。 (假设您将玻璃窗格保持为空...)这是一个示例,它在事件到达组件之前捕获事件,甚至将其转发给选定的事件:http://download.oracle.com/javase/tutorial/uiswing/components/rootpane.html#glasspane
    • 中间立场是使用分层窗格在您需要的任何内容之上创建透明组件(类似玻璃窗格的东西)。

    你也可以使用()事件......你的主要问题是你要么在摆动手柄之前捕获事件(并从头开始编写自定义处理),要么在它们之后(并且从你可能拥有的处理中受到一些干扰)破解),但你不能通过继承任何东西来修改处理代码本身(或者你可以吗?到目前为止从未见过......)。

    【讨论】:

      猜你喜欢
      • 2013-05-13
      • 1970-01-01
      • 2019-07-18
      • 1970-01-01
      • 1970-01-01
      • 2020-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多