Java:GUI必须在EDT线程中初始化?


2

我是杰森。我在物质的外观和感觉上有点问题(https://substance.dev.java.net/)。

我的问题更一般。我已经编写了我的GUI并且工作正常,但是当我使用物质外观时,它需要在EDT线程(Event Dispatching Thread或其他)中执行所有GUI初始化。

现在我正在使用com.sun.java.swing.plaf.windows.WindowsLookAndFeel(不知道我是否拼写正确),并且它不需要任何此类的东西。

因此,我通过调用SwingUtilities.invokeLater()将主要初始化放入EDT。这使它工作。但是,该程序在执行期间还会生成其他几个窗口。现在,我有这样的代码:

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

此代码工作正常,因为时间window.doStuff()被调用时,它已经初始化。但物质要求我做这样的事情:

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

这有时会抛出一个NullPointerException,因为不被时间window.doStuff()被调用初始化窗口。我无法将window.doStuff()放入EDT线程,因为它通常需要几秒钟才能返回并挂起GUI。

我已经尝试把Thread.sleep(1000)调用EDT线程后,因为它可能是初始化。但这看起来很尴尬。我只需要一种方法让主线程在SomeNewWindow初始化返回时“知道”,以便它可以继续,而不必担心NullPointerException。

在此先感谢。

5

您可以从invokeLater切换到invokeAndWait,它将等待创建窗口。这有点俗气,但不如睡觉。

  0

这是行得通!从来不知道存在。 * facepalm * 21 2月. 092009-02-21 23:14:51


0

我认为标准的做法是让你的EDT成为你开始其他工作线程做“东西”的“基本线程”。

另一种方法是使用volatile标志,初始化程序可以在完成时设置标志,以便另一个线程可以在循环中检查它,并在设置标志后在新窗口上进行操作。


0

Egwor建议使用CountDownLatch代替。绝对看起来它会简化情况。


这是condition variables工作。

基本上,在run()中,锁定锁,构造一些新窗口并发出信号(并解锁锁)。 “同时”,在另一个线程中,做你的其他“bs”,锁定锁;如果窗口为空,则等待条件变量();解锁; window.doStuff();

  0

我认为倒计时闩锁可能会更好,不是吗? 21 2月. 092009-02-21 22:42:40

  0

也许吧。我不知道什么倒计时闩是:) 21 2月. 092009-02-21 22:44:16


0

是否有理由不能将doStuff()调用移入invokeLater回调?

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

如果以上是不可能的,我会用invokeAndWait(),而不是invokeLater()走了,正如保罗汤布林已经建议。

  0

而不是,因为window.doStuff通常需要几秒或几分钟。我尝试这样做,那时窗口变得透明。 22 2月. 092009-02-22 22:10:05

  0

同意,坏主意:-) 24 2月. 092009-02-24 21:55:53