这是场景:我有两个 java 应用程序。第一个是使用swing GUI 的可视化应用程序,全部封装在一个JFrame 中,它具有非常复杂的行为(非常旧的代码库),我无法更改这些行为。我只是有一个 JFrame 对象的钩子。
第二个应用程序是我正在编写的,它基本上是第一个应用程序的单元测试器。使用 JFrame 钩子和 JDI,我已经能够完成执行这些测试所需的所有自省,并且进展顺利。事实上,我的测试进展顺利,我想在后台运行它们。但是,由于我的许多测试都涉及将 KeyEvents 和 MouseEvents 分派到 JFrame,一旦窗口失去焦点,这些将停止。从我读过的内容来看,这似乎是由于默认的 KeyboardFocusManager 的要求,它只会将这些事件分派给既显示又聚焦的组件(这也要求包含它们的窗口既显示又聚焦)。这让我想到了我的问题:
如何在没有 KeyboardFocusManager 停止其进程的情况下将事件“强制”调度到某些摆动组件?
重要说明:我希望将这些事件分派到的组件也注册为永久焦点所有者,这有助于消除在窗口未聚焦时哪个组件应该接收事件的歧义(KeyboardFocusManager.getGlobalPermanentFocusOwner())
我如何举办活动:(非常简单的东西)
public void keyPress(int keycode, char c) {
KeyEvent press = new KeyEvent(content, KeyEvent.KEY_PRESSED, System.currentTimeMillis(), 0, keycode, c);
pushEventToQueue(press);
}
public void mousePress(int buttons) {
MouseEvent press = new MouseEvent(content, MouseEvent.MOUSE_PRESSED,
System.currentTimeMillis(), buttons, curX, curY, 1, false);
pushEventToQueue(press);
}
我尝试过的(以及为什么它们不起作用):
通过 Component.dispatchEvent(event) 调度事件。这不起作用,因为它需要组件可见,因为它通过 KeyboardFocusManager 路由(很奇怪)。
出于上述原因,通过 KeyboardFocusManager.dispatchEvent(event) 调度事件。
调用 Component.requestFocus() 或 .requestFocusInWindow() 将允许传递事件,但对我不起作用,因为它们也会强制 Window 容器聚焦,这会将窗口带到前台。
遍历永久焦点所有者的侦听器,并使用我的自定义事件调用事件函数。我不确定为什么这不起作用,但我怀疑这与正常应用程序功能中缺乏通过不同焦点所有者的传播有关。
这是我当前的 pushEventToQueue 函数,其中包含失败的注释部分供您娱乐:
private void pushEventToQueue(AWTEvent evt) {
// Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(evt);
// Component perm = KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner();
// if (perm == null) {
// content.dispatchEvent(evt);
// } else {
// if (evt instanceof KeyEvent) {
// for (KeyListener l:perm.getKeyListeners()) {
// if (evt.getID() == KeyEvent.KEY_PRESSED)
// l.keyPressed((KeyEvent) evt);
// else if (evt.getID() == KeyEvent.KEY_RELEASED)
// l.keyReleased((KeyEvent) evt);
// else if (evt.getID() == KeyEvent.KEY_TYPED)
// l.keyTyped((KeyEvent) evt);
// }
// } else if (evt instanceof MouseEvent) {
// for (MouseListener l:perm.getMouseListeners()) {
// if (evt.getID() == MouseEvent.MOUSE_PRESSED)
// l.mousePressed((MouseEvent) evt);
// else if (evt.getID() == MouseEvent.MOUSE_RELEASED)
// l.mouseReleased((MouseEvent) evt);
// else if (evt.getID() == MouseEvent.MOUSE_CLICKED)
// l.mouseClicked((MouseEvent) evt);
// }
// } else
// perm.dispatchEvent(evt);
// }
content.dispatchEvent(evt);
try {
Thread.sleep(50); //Minimal but necessary
} catch (InterruptedException e) {
e.printStackTrace();
}
}
我现在唯一能想到的(我不知道该怎么做)就是扩展 KeyboardFocusManager 类并添加一些功能,当当前 JVM 中没有窗口时,这些功能会将焦点默认为我选择的未聚焦组件有焦点(也就是所有java窗口都在后台)。理想情况下,这不会干扰现有的程序功能,因为它表现出非默认行为的唯一情况是所有窗口都没有聚焦。
我无法更改 swing 应用程序的代码库。这意味着我不能实现 KeyBindings 而不是 KeyListeners,也不能覆盖摆动组件的 isFocused/isShowing 方法。我能做的是反射或 JDI 提供的任何东西,在这种情况下似乎有点没用。
这个事情谁有经验?任何人都可以提供指导吗?