Java Swing:如何将所有事件从子组件转发到父容器?
我正在寻找一种简单的方法,使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
我在哪里需要这个?我有一个图表编辑器。部件必须向前按键并按下 鼠标单击(在用户单击子元素时将其自身设置为“活动”) (属于该组成部分) 首先,让我介绍一下我现有的解决方案。这是一个解决办法
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方法的。