我一直在设计一个基于 Swing 的桌面 RPG 程序,以促进带有 GUI 控制元素的基于文本的角色扮演。
为了促进这一点,每个正在运行的客户端都会获得一个包含所有重要 JFrame 的主桌面(托管客户端上的“GM 桌面”和远程客户端上的“播放器桌面”)。此外,GM 和玩家都可以为角色打开“Perspective Desktops”,为他们提供一个单独的 JDesktopPane,其中包含提供角色视角的“Role Play Chat Window”,以及额外的 JInternalFrames,例如“Character Sheet Window”等.
用户使用 JTabbedPane 在桌面之间导航。
我遇到的问题是我希望能够在桌面之间移动的一些窗口。例如,如果 OOC(字符外)聊天在用户处于透视桌面时收到一条消息,我希望 OOC 聊天窗口有一个选项可以自动重新定位到当前桌面,以便用户看到立即留言。同样,我希望播放器能够使用菜单栏将某些窗口“调用”到当前桌面。
但是,当我尝试将 JInternalFrame 从一个 JDesktopPane 移动到另一个时,我收到一个异常。
com.finnickslab.textroleplayonline.exceptions.CommandEventHandlingException
An exception was thrown during command handling. CommandEvent type: UI_OOC_CHAT (26).
Cause Exception: java.lang.IllegalArgumentException
illegal component position
java.awt.Container.addImpl(Unknown Source)
javax.swing.JLayeredPane.addImpl(Unknown Source)
javax.swing.JDesktopPane.addImpl(Unknown Source)
java.awt.Container.add(Unknown Source)
com.finnickslab.textroleplayonline.ui.GameDesktop.receiveTransfer(GameDesktop.java:80)
com.finnickslab.textroleplayonline.ui.GameDesktop.access$0(GameDesktop.java:74)
com.finnickslab.textroleplayonline.ui.GameDesktop$2.run(GameDesktop.java:69)
com.finnickslab.textroleplayonline.ui.UI.invokeEvent(UI.java:818)
com.finnickslab.textroleplayonline.ui.GameDesktop.transfer(GameDesktop.java:62)
com.finnickslab.textroleplayonline.ui.UI$HostCommandHandler.handle(UI.java:605)
com.finnickslab.textroleplayonline.comm.Server$3.run(Server.java:324)
我程序中的所有 JInternalFrames 都来自 JInternalFrame 的同一个子类(“InternalWindow”)。
该异常使它看起来有点复杂,但归结为调用 JDesktopPane.remove(JInternalFrame) 然后调用 JDesktopPane.add(JInternalFrame)。
然后,只要在 GameDesktop 第 80 行调用“add”方法,我就会收到该异常。
/**
* Transfers the specified InternalWindow from this GameDesktop to
* the specified GameDesktop. Use this method to prevent
* automatic removal of listeners performed with the
* {@link GameDesktop.remove(InternalWindow)} method.
*/
public synchronized void transfer(
final InternalWindow window,
final GameDesktop gd) {
final GameDesktop desktop = this;
contents.remove(window);
UI.invokeEvent(new Runnable() {
@Override
public void run() {
desktop.remove((JInternalFrame) window);
desktop.validate();
desktop.repaint();
gd.receiveTransfer(window);
}
});
}
private synchronized void receiveTransfer(InternalWindow window) {
contents.add(window);
window.changeDesktop(this);
window.center();
this.add((JInternalFrame) window); // LINE 80
this.validate();
this.repaint();
window.resetPosition();
}
“UI.invokeEvent(Runnable)”方法是我为 SwingUtilities.invokeAndWait(Runnable) 编写的一种便捷方法。它检查当前线程是否是 EDT,如果是,则立即执行 run() 方法。否则,它使用 invokeAndWait(Runnable) 在 EDT 上调度 runnable。
任何有关如何解决此问题的想法将不胜感激。
编辑:
我对这个错误的所有研究表明它与组件的 Z 轴位置有关。我尝试更改 add 调用以指定 z 位置
super.add(window, getComponentCount());
但没有变化。仍然得到相同的 IllegalArgumentException。