Question

I have been designing a Swing-based tabletop RPG program to facilitate text-based roleplay with GUI control elements.

To facilitate this, each running client gets a main desktop ("GM Desktop" on the hosting client and "Player Desktop" on the remote clients) with all of the important JFrames. Additionally, both GM and Players can open "Perspective Desktops" for characters, providing them with a separate JDesktopPane that contains the "Role Play Chat Window" that gives that character's perspective, along with additional JInternalFrames such as the "Character Sheet Window", etc.

The user navigates between desktops using a JTabbedPane.

The issue that I am having is that SOME of the windows I want to be able to move between desktops. For example, if the OOC (Out-of-Character) Chat receives a message while the user is in a Perspective Desktop, I want there to be an option for the OOC Chat Window to automatically relocate to the current desktop so the user sees the message immediately. Similarly I want the player to be able to "call" certain windows into the current desktop using the menu bar.

However, when I attempt to move a JInternalFrame from one JDesktopPane to another, I receive an exception.

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)

All JInternalFrames in my program descend from the same subclass of JInternalFrame ("InternalWindow").

The exception makes it look a little convoluted but it boils down to calling JDesktopPane.remove(JInternalFrame) then JDesktopPane.add(JInternalFrame).

And then I receive that exception as soon as the "add" method is called on GameDesktop line 80.

/**
 * 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();
}

The "UI.invokeEvent(Runnable)" method is a convenience method I wrote for SwingUtilities.invokeAndWait(Runnable). It checks to see if the current thread is the EDT and, if it is, executes the run() method immediately. Otherwise, it uses invokeAndWait(Runnable) to schedule the runnable on the EDT.

Any ideas of how to fix this problem would be appreciated.

Example 1 Example 2

EDIT:

All my research on this error suggests that it has something to do with the Z-axis position of the component. I tried changing the add call to specify the z position

super.add(window, getComponentCount());

but no change. Still getting the same IllegalArgumentException.

Was it helpful?

Solution

See if you get the same error when running this. If not, the problem is not with switching the parent of the internal frame, it's with the synchronization.

public class IFSwitch extends JDesktopPane {

    final JDesktopPane pane1 = this;

    public IFSwitch() {

        JFrame frame1 = new JFrame("Frame1");
        JFrame frame2 = new JFrame("Frame2");
//      JDesktopPane pane1 = new JDesktopPane();
        JDesktopPane pane2 = new JDesktopPane();
        final JInternalFrame if1 = new JInternalFrame();

        frame1.add(pane1);
        frame2.add(pane2);
        pane1.add(if1);

        if1.setBounds(10, 10, 100, 100);
        frame1.setBounds(100, 100, 200, 200);
        frame2.setBounds(500, 500, 200, 200);
        frame1.setVisible(true);
        frame2.setVisible(true);
        if1.setVisible(true);

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        pane2.add(if1);
        pane1.remove(if1); // You don't even need this line.
        pane1.repaint();

    }

    public static void main(String[] args) {

        new IFSwitch();
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top