-1

EDIT: Simplified my code.

This is the main class that initialises the GUI and Server threads.

public class Main {
    public static void main(String args[]) throws ClassNotFoundException, InstantiationException, IllegalAccessException, UnsupportedLookAndFeelException, UnknownHostException {
    Runnable tGUI = new TransceiverGUI();
    Runnable server = new Server(tGUI);
    new Thread(tGUI).start();
    new Thread(server).start();
    }
}

Now, in my public class TransceiverGUI extends javax.swing.JFrame implements Runnable class, I have a method with the following:

protected boolean incomingFileRequest(String filename, long filesize, String user) throws InterruptedException, InvocationTargetException {
        /* .... code logic which executes .... */
        /* UPDATE GUI HERE DOES NOT WORK */
        LabelProgress.setForeground(Color.red);
        LabelProgress.setText("Receive Progress");
    }

Whenever incomingFileRequest is called from within the GUI class (from any EventListener) it works perfectly and the GUI is updated.

However, when I call incomingFileRequest from the Server class/thread, the code runs and returns the correct value, but the GUI does not update.

The server thread calls it like this: // POPUP with request boolean answer = gui.incomingFileRequest(message.getMessage(), message.getFileSize(), message.senderIPAddress);

I have placed the code that updates the GUI in a block that creates a new thread like this:

Thread t = new Thread() {
public void run() {
   LabelProgress.setForeground(Color.red);
   LabelProgress.setText("Receive Progress");
   repaint();
}
};
t.start();

I also tried javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { /* update GUI code */ } });.

My question is, how do I call a method (that updates the GUI) within the GUI class from another thread? Keeping in mind that code is executed perfectly, the GUI elements are just not updated.

Any help would be greatly appreciated.

AnonymousAngelo
  • 996
  • 3
  • 15
  • 37
  • 5
    **Swing is single threaded**. You simply cannot use Swing elements from multiple threads. It is **not allowed**. You **must** restrict all access to Swing components to the EDT. – Boris the Spider Aug 16 '15 at 15:11
  • 3
    I second @BoristheSpider's comments above. Also, yours appears to be a somewhat complex issue regarding communication between different classes using different threads, and this may require that you create and post an [mcve] to enable us to fully understand your problem and its possible causes. Please read the link. – Hovercraft Full Of Eels Aug 16 '15 at 15:13
  • 1
    Regarding your edit above, if it is due to my comment above, then I don't think that you understand what I'm asking. Again, please read the link as it is fully explained there. – Hovercraft Full Of Eels Aug 16 '15 at 15:19
  • The project itself is rather complex, so it will be hard for me to provide detailed example, even after simplifying. – AnonymousAngelo Aug 16 '15 at 15:20
  • 1
    Then it may be hard for us to give you a satisfying answer. To solve a problem, the bug must first be identified, and it will be hard for us to do so without an understandable small runnable program that demonstrates the issue for us. – Hovercraft Full Of Eels Aug 16 '15 at 15:21
  • Thank you for your help, I do appreciate it! As @BoristheSpider suggested, my issue is with the multiple thread accesses. It is possible to call methods within the GUI class from another thread, but not to update the GUI elements. Is there another way to somehow call a method within the GUI class which then triggers some other method to update the GUI? I apologise if this is confusing... – AnonymousAngelo Aug 16 '15 at 15:24
  • A guess -- but if you have long-running code such as code uploading or downloading a file, this can tie up your GUI, preventing it from changing text/color, even freezing it, especially if your code does not respect Swing threading appropriately. Please read: [Lesson: Concurrency in Swing](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/) – Hovercraft Full Of Eels Aug 16 '15 at 15:25
  • The GUI never hangs or freezes. The long-running code is executed on a different thread. That specific method (in the GUI) is simply a JOptionPane that pops up asking a user to accept or decline an incoming file (the listener is on a different thread). The GUI executes all the code and returns perfectly, it just ignores the code to update the JFrame. – AnonymousAngelo Aug 16 '15 at 15:28
  • @EfVonZee: Please have a look at [this thread](http://stackoverflow.com/a/13004927/1057230), in which I tried to perform Bubble Sort. Hopefully this can give a fair idea, in your endeavour :-) – nIcE cOw Aug 16 '15 at 15:32
  • 1
    Then consider putting in the time and effort to create your [mcve]. It is a great debugging skill to have and won't be wasted effort, trust me. I have to create these things non-infrequently, and the effort often shows me that it is worth my effort to create classes with low coupling and high cohesion since they are usually independently testable and so much easier to debug. – Hovercraft Full Of Eels Aug 16 '15 at 15:32
  • @HovercraftFullOfEels I completely understand and agree with you, however, I am very pressed for time at the moment. For the future I will definitely study the tutorial in detail. I am rather new as a poster here at StackOverflow. Thank you for your help :) – AnonymousAngelo Aug 16 '15 at 15:37
  • @nIcEcOw I will have a look now, thank you! – AnonymousAngelo Aug 16 '15 at 15:37
  • 1
    Well, I sincerely hope that you will get a solution and soon, but I see none forthcoming based on the information that is currently available, other than suggests based on blind guesses like mine above. Good luck. – Hovercraft Full Of Eels Aug 16 '15 at 15:38
  • Update please: Any resolution so far? – Hovercraft Full Of Eels Aug 16 '15 at 23:41

2 Answers2

2

From your post

Whenever incomingFileRequest is called from within the GUI class (from any EventListener) it works perfectly and the GUI is updated.

However, when I call incomingFileRequest from the Server class/thread, the code runs and returns the correct value, but the GUI does not update.

That is exactly what some ppl tried to explain to you in the comments. All GUI updates must be performed in GUI thread - EDT.

The Event Dispatch Thread is the one that is handling your "listener" that is why GUI gets updated. To update your gui from the different thread you have to simply "schedule" your changes to be performed in the EDT. To do that, simply wrap your GUI modification code into Runnable class and pass it to the EDT via SwingUtilities.invokeLalater(Runnable) method. This way your GUI will be updated ASAP

You have also mentioned that

I also tried javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { /* update GUI code */ } });.

And what was the result? Because this is exactly how it should be done. If this is not working for you, there is some other porblem with your code either your method body waits for some external updates, or it is scheduled in different moment than you think it is.

Antoniossss
  • 31,590
  • 6
  • 57
  • 99
  • That is the exact reason why I am so confused. I've tried calling `SwingUtilities.invokeLalater(Runnable)` from within the method in the GUI class which gets called by the thread. I've also tried calling it wrapped in `SwingUtilities.invokeLalater(Runnable)` from the thread. Neither works. – AnonymousAngelo Aug 16 '15 at 15:55
  • Than the problem lies somewhere else that thi MUST work – Antoniossss Aug 16 '15 at 16:02
0

Initially I had

public class Main {

    public static void main(String args[]) throws ClassNotFoundException, InstantiationException, IllegalAccessException, UnsupportedLookAndFeelException, UnknownHostException {

    Runnable tGUI = new TransceiverGUI();
    Runnable server = new Server(tGUI);

    System.out.println("Starting GUI...");
    new Thread(tGUI).start();
    System.out.println("Starting Server...");
    new Thread(server).start();
    }
}

After many hours of searching for solutions I simply swapped around the way I reversed the way I passed the parameter to the threads. As you can see in the following (working) code, I first create the server thread and then pass it as a parameter to the GUI thread. I also changed the corresponding constructors to accept the parameters accordingly.

After the change everything worked perfectly. I actually have no reason why this change solved my issue.

public class Main {

        public static void main(String args[]) throws ClassNotFoundException, InstantiationException, IllegalAccessException, UnsupportedLookAndFeelException, UnknownHostException {

        Runnable server = new Server();
        Runnable tGUI = new TransceiverGUI(server);

        System.out.println("Starting Server...");
        new Thread(server).start();
        System.out.println("Starting GUI...");
        new Thread(tGUI).start();
        }
    }
AnonymousAngelo
  • 996
  • 3
  • 15
  • 37