views:

999

answers:

5

Hi, I'm Jason. I'm having a bit of a problem with the Substance look and feel (https://substance.dev.java.net/).

My problem is more general. I've already got my GUI written and it works fine, but when I use a Substance Look-and-feel, it requires all GUI initialization to take place in the EDT thread (Event Dispatching Thread or something).

Right now I'm using com.sun.java.swing.plaf.windows.WindowsLookAndFeel (not sure if I spelled that right) and it doesn't require anything of this sort.

So I put the main initialization into the EDT by calling SwingUtilities.invokeLater(). This made it work. However, the program also spawns several other windows during its execution. Right now I have code like:

SomeNewWindow window = new SomeNewWindow();
// ... some bs emitted
window.doStuff();

This code works fine because by the time window.doStuff() is called, it's already initialized. But Substance requires me to do something like this:

SwingUtilities.invokeLater(new Runnable(){
public void run(){
SomeNewWindow window = new SomeNewWindow();
}});
// ... bs emitted
window.doStuff();

Here it sometimes throws a NullPointerException because window is not initialized by the time window.doStuff() is called. I can't put window.doStuff() into the EDT thread because it usually takes several seconds to return and will hang the GUI.

I've tried putting Thread.sleep(1000) right after I invoke the EDT thread because it's probably initialized by then. But this seems awkward. I simply need a way for the main thread to 'know' when the SomeNewWindow initialization has returned so it can continue on without having to worry about a NullPointerException.

Thanks in advance.

+3  A: 

Duplicate of Is it safe to construct Swing/AWT widgets NOT on the Event Dispatch Thread?

(Hard to find; I only knew about it because I'd read it before)

cletus
A: 

I think the standard approach to this would be to make your EDT the "base thread" from which you start other worker threads to do stuff.

Another way would be to use a volatile flag that the initializer can set when it's done, so the other thread can check it in a loop and act on the new window once the flag is set.

Zach Scrivena
A: 

Egwor suggest using a CountDownLatch instead. Definitely looks like it would simplify the situation.


This is a job for condition variables.

Basically, in run(), Lock the lock, construct some new window and signal the condition (and unlock the lock). "Meanwhile", in the other thread, do your other "bs", lock the lock; if the window is null, wait() on the condition variable; unlock the lock; window.doStuff();

Logan Capaldo
I think a countdown latch might be better, no?
Egwor
Maybe. I don't know what a countdown latch is :)
Logan Capaldo
+4  A: 

You could switch from invokeLater to invokeAndWait, which will wait until the window is created. It's a bit cheesy, but not as bad as putting in a sleep.

Paul Tomblin
That works! Never knew that existed.*facepalm*
A: 

Is there a reason why you can't just move the doStuff() call into the invokeLater callback?

SwingUtilities.invokeLater(new Runnable(){
    public void run(){
         SomeNewWindow window = new SomeNewWindow();
         window.doStuff();
    }
});

If the above is impossible, I'd go with invokeAndWait() instead of invokeLater(), as Paul Tomblin already suggested.

Barend
And no because window.doStuff usually takes several seconds or minutes. I try doing that and the window becomes transparent for that time.
Agreed, bad idea :-)
Barend