0

I've been reading a lot of SO answer and questions but I never asked anything before.

My question is about desing patterns and best practices in Swing application.

Suppose you have a Swing application with a GUI class with a JLabel and another class (not an inner class of the previous) which extends Thread and perform some network operations (basically it periodically fetch resources from a web API to check if a given value appear).

When a certain value is fetched by the second class I need to update the JLabel of the firt class. I'm perfectly aware this should be done in the EDT using invokeLater(), my question is how to handle the access from the background Thread to the JLabel.setText() method.

As far as I know I see three solution:

  • provide a static getter in the GUI class and call it insite a SwingUtilities.invokeLater() in the Thread class
  • provide a static method inside the GUI class which internally calls SwingUtilities.invokeLater() and access that method (say MyGui.updateTheLabel()) from the Thread class
  • passing a reference of the JLabel to the Thread constructor and use that reference to update the label with SwingUtilities.invokeLater()

Which one of this solution is better? Are there particular design patterns meant to solve this issue. I find it ugly to put SwingUtilities.invokeLater() everywhere I want to update the GUI or creating static getters around.

Thank you :)

  • Read this explanation of the different approaches http://stackoverflow.com/questions/19444912/difference-between-swingutilities-invokelater-and-swingworkervoid-object/19444995#19444995 – René Link Feb 19 '14 at 08:50
  • Can you elaborate how you intend to use `static` methods for the first two solutions? – Marco13 Feb 19 '14 at 09:37
  • Let's say Gui.getLabel() so I can call GUI.getLabel().setText() in the first case. Or GUI.updateLabel() in the second. – user3327136 Feb 19 '14 at 17:08

3 Answers3

2

To perform tasks in background and updating UI elements in Swing application you can use SwingWorker class.

Sachin Gorade
  • 1,427
  • 12
  • 32
  • Extending code13's idea: you can have a SwingWorker checking periodically your external API, calling `publish` every time it sees a change, and then implement in your `process` method every GUI update – Jorge_B Feb 19 '14 at 09:08
2

The networking thread should not know about JLabel. Its duty is to load some data from network. Exposing that data on a screen is another task, and should be made with a special UI class. That class should have some method like (update(byte[]), which internally calls invokeLater. An instance of that UI class should be passed to the networking thread at creation time, and that thread should periodically call update method.

Alexei Kaigorodov
  • 13,189
  • 1
  • 21
  • 38
0

I usually define runnables for the tasks I'll be performing on the GUI, and create these when needed. Outsiders need not know how the updates are performed, they just use the GUI's exposed API.

Example:

interface NetworkUpdateListener {
    void updateFetched(String newText);
}

class Gui implements NetworkUpdateListener {
    private JLabel label;
        // ...

    @Override
    public void updateFetched(String newText) {
        SwingUtilities.invokeLater(new LabelUpdater(newText));
    }

    private final class LabelUpdater implements Runnable {
        private final String text;

        LabelUpdater(String s) { text = s; }

        @Override
        public void run() { label.setText(text); }
    }
}

Somewhere else, from another thread:

NetworkUpdateListener listener;
// ...
listener.updateFetched(text);
afsantos
  • 5,178
  • 4
  • 30
  • 54
  • This is actually the same solution, thanks for posting I upvoted it but I'm accepting the one coming from Alexei which posted it first :) – user3327136 Feb 19 '14 at 17:10