10

I learned about how swing isn't thread-safe. Delving deeper, I discovered that every modification to a swing component must be done on the Event Dispatch Thread in order to prevent various issues associated with multithreading. However, the information seemed to completely stop there. There doesn't seem to be a good tutorial that explains how to do this anywhere accessible on the internet.

Patching together information from code posted in relation to other issues, it seemed that I would have to put an untidy block of code around every single swing modification in my program (like this example from my own code):

try {
        SwingUtilities.invokeAndWait(new Runnable() {

            public void run() {
                setTitle("Frame title");
                setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                setVisible(true);

                setSize(800, 480);
                setLocationRelativeTo(null);
                setIconImage(Toolkit.getDefaultToolkit().createImage(ClassLoader.getSystemResource("Frame icon.png")));
            }
        });
    } catch (Exception e) {
        e.printStackTrace();
    }

Basically, is this right? Do I have to put that code (or the equivalent with invokeLater) around every modification to a Swing component in my code?

Also, why doesn't Swing do this automatically?

yizzlez
  • 8,757
  • 4
  • 29
  • 44
Tharwen
  • 3,057
  • 2
  • 24
  • 36

4 Answers4

8

The trick is that when swing calls you it will ALWAYS be in the EDT, so you don't have to worry about it.

However if you are in a timer or an action triggered by some other external event, your main thread or any other thread you've created then yes, you have to use invokeLater or invokeAndWait.

In other words, yes swing does do "it" automatically. Needing to use invokeXx is so rare that if swing were to do it internally it would waste too much time.

Many java programmers never figure this out and it can cause some pretty nasty hard-to-find problems with drawing your GUI. I do wish swing threw an exception when you called it not using the EDT--Java would have a better reputation when it came to professional GUIs if it did because there would be less crap out there.

Bill K
  • 62,186
  • 18
  • 105
  • 157
  • not as good as what you wish but you can install automated Swing/EDT violation detection code and they do catch quite a lot of mistakes (don't have any link handy but there are quite some of them). – TacticalCoder Oct 25 '11 at 23:44
  • Microsoft in the windows 3.0/3.1 era had "Debug Binaries" that would do this kind of checking so that you wouldn't have to reboot every time you sent bad arguments. It always bugged me that Java didn't have the same--especially since it's smart enough to be able to compile it out on a command-line switch. – Bill K Oct 26 '11 at 20:54
  • 1
    I used to always put it "in" the Java app, replacing the repaint manager(s) with a *CheckThreadViolationRepaintManager*. I remember it worked quite well : ) – TacticalCoder Oct 26 '11 at 22:57
  • Now that I think about it these days it's probably an easy thing to solve with aspects, but on the other hand I'm not so much worried about ME, I'm worried about everyone else going around making people think that there is no such thing as a good java gui. Another good check would be to ensure that the EDT thread never spends more than .01 seconds or so in your code--any longer and it should throw an exception telling you to put it in a worker thread. – Bill K Oct 27 '11 at 00:13
4

note that any code executed from event handlers is already run in the EDT (the Event in the acronym)

this means that for general use (while you don't mess with swingworkers and threadpools and such) you are always inside the EDT

and you can always query if you are in the EDT with SwingUtilities.isEventDispatchThread()

also note that in your code the call to invokeAndWait will fail and throw an error when you are in the EDT already

ratchet freak
  • 47,288
  • 5
  • 68
  • 106
3

Basically, you dont draw or update the GUI from outside of the EDT. You use SwingUtilitis.invokeLater() from another thread to ensure the GUI drawing or updating code is run on the EDT.

Zaki
  • 6,997
  • 6
  • 37
  • 53
  • Just the drawing code? Can I get rid of the untidiness around things like setSize() and setVisible()? – Tharwen Oct 25 '11 at 22:47
  • by drawing code, it implies any updates to the GUI components, so yes, setSize() and setVisible() is part of the drawin code. – Zaki Oct 25 '11 at 22:51
  • You also should create new threads to do expensive tasks outside of the EDT, otherwise you risk freezing up the UI. – Chris Dennett Oct 25 '11 at 23:30
3

Not all your UI code must be part of a runnable in an invokeLater call. That is simply because a large part of your program will be run on the EDT anyway. You need to dispatch messages to the EDT only when you are on a different thread.

Savvas Dalkitsis
  • 11,476
  • 16
  • 65
  • 104