views:

578

answers:

6

Hello,

I have been asking a lot of questions about a project I have been working on recently. Here is the scenario I am in and any help or point in the right direction would help a lot...

This is a network program built with a server and multiple clients. Each client has a GUI which must act according to commands sent from the server. Each client is wrapped within a class called Player. This Player has a GUI (extends JFrame) and a main method, and the Server has a main method only (no GUI). At first, this class was created in the main thread like this:

EventQueue.invokeLater(new Runnable()
{
    public void run()
    {
        new Player().setVisible(true);
    }
 });

This was working fine, until I realized that the entire Player class was now executing in the EDT. So, when I wait for commands from the server the entire GUI locks up until that command is sent and proper actions are executed. As you can imagine, this is a horrible design and proved to be a real pain of a coding environment when everytime you want to check for something you must find some crazy work around so that the GUI still remains in tact.

Obviously, I must check for the commands from the Server in a separate thread and run the GUI components in the EDT. My second implementation had two classes - one for the GUI and one for the Player. The idea was that the Player had a variable that held the GUI so that I could access the GUI from the Player class, something like this:

class Player
{
    public GUI gui;

    ...

    // And then start this gui inside of the EDT.
    EventQueue.invokeLater(new Runnable()
    {
         public void run()
         {
              this.gui = new GUI().setVisible(true);
         }
    }

This doesn't work either, because "this" inside of the new Runnable object refers to the Runnable object, not the Player.

So, I don't know how to communicate between the Player class in one thread and the corresponding GUI class in the EDT thread.

Any help?

A: 

Instead of using an anonymous inner class, why not just declare a class the implements Runnable and have a constructor that takes a GUI instance as argument?

Also, if your GUI class is not thread safe, consider using a message queue to communicate between the EDT & main thread.

oykuo
+2  A: 

To handle your problem with the this pointer, you should write:

class Player
{
    public GUI gui;

    ...

    // And then start this gui inside of the EDT.
    EventQueue.invokeLater(new Runnable()
    {
         public void run()
         {
              Playser.this.gui = new GUI().setVisible(true);
         }
    }
}
Laurent K
+1  A: 

You may try this:

class Player { public GUI gui;

...

// And then start this gui inside of the EDT.
EventQueue.invokeLater(new Runnable()
{
     public void run()
     {
          Player.this.gui = new GUI().setVisible(true);
     }
}
Boris Pavlović
+2  A: 

Boris Pavlović gets the syntax right (actually you could just remove the this.), but still the code doesn't make sense. The gui field is initialised sometime after the Runnable event is queued, so it is unsafe for the player thread to use it.

You could construct Player on the EDT (but do the network operations off EDT). Or register the GUI as a listener (observer) of the Player. invokeAndWait would work, but is dangerous as it often leads to the occasional difficult-to-debug deadlock.

Tom Hawtin - tackline
+1  A: 

"until I realized that the entire Player class was now executing in the EDT"

The constructor occurs on the EDT but methods called on this class might not be.

You should construct the player GUI as you originally intended.

 EventQueue.invokeLater(new Runnable() 
 {
    public void run()
    {
        new Player().setVisible(true);
    }
 });

But Player can launch a separate thread in the constructor (personally I'd share a connection between the Players).

Of course, the callback methods from the server should use invokeLater() when modifying visible components.

Pool