如果我理解正确,那么当我创建GUI swing组件时,例如我有:
public class frameExample extends JFrame{
public frameExample(){
//Here adding bunch if components
setVisible(true);
}
}
因此,只要我不调用setVisible方法,就会从创建实例的线程中创建组件。因此,如果在我的主要方法的类中写:
JFrame test=new frameExample();
和我sysout
Thread.currentThread.getName();
在setExample的构造函数中的就在setVisible之前我应该得到:main。
之后,创建和维护swing元素的责任被传递给event-dispatch-thread,因为它不是线程安全的,所以每个组件的添加/删除/修改都应该在EDT线程中完成。
所以我应该将setVisible作为构造函数中的最后一行代码,或者单独调用它。
据我所知,所有事件都是通过EDT进行的。因此,如果我在例如actionPerformed方法中创建一个新组件,它应该可以。
此外,如果我将runnable实例传递给invokeLater或invokeAndWait,那么所有run()方法都将由EDT完成。
所以这就是为什么我感到困惑。
我制作了这段代码:
public class GUI extends JFrame {
JButton btn = new JButton("Change");
JMenuBar m = new JMenuBar();
public GUI() {
super("Test");
setSize(400, 400);
setDefaultCloseOperation(EXIT_ON_CLOSE);
m.add(new JMenu("menu"));
add(m, BorderLayout.NORTH);
add(btn, BorderLayout.SOUTH);
System.out.println("Current thread: before setVisible "+Thread.currentThread().getName());
setVisible(true);
System.out.println("Current thread: after setVisible "+Thread.currentThread().getName());
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
add(new JButton("testbtn1"), BorderLayout.EAST);
add(new JButton("testbtn2"));
System.out.println("Current thread: "+Thread.currentThread().getName());
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 1E8; i++) {
Math.sin(5.0);
}
System.out.println("Current thread: "+Thread.currentThread().getName());
}
}).start();
}
});
}
}
所以在我的anonim类中我在EDT中添加了两个按钮,但是在我调整它之后组件没有添加到我的框架中(这迫使edt更新其组件???这是什么原因此?)。
所以即使在edt中我也不会得到我的新组件,但是当我在edt之外创建一个随机线程并使其更改一些gui元素属性(例如setText)时,在edt之外工作正常。
所以我的第一个问题是:为什么我的组件没有在edt中更新,以及为什么它们在调整大小后可见
第二个问题:为什么我可以对edt外部的摆动组件进行更改,一切正常?这只是一个随机的线程行为,例如在没有同步块的情况下工作正常但是当你重新运行程序时,它会因为缺乏同步而最终崩溃。
答案 0 :(得分:4)
因此,只要我不调用setVisible方法,就会从创建实例的线程中创建组件
错误。只要您没有专门创建新的Thread
或使用实用程序方法(例如SwingUtilities#invoke...
方法),就会在当前Thread
上调用每个调用,包括{{ 1}}来电。
看起来您认为以某种方式使Swing组件可见会使您的代码切换线程。不,Swing组件的绘画将在EDT上进行。正如您所说,Swing不是线程安全的。 这就是为什么你应该在EDT上创建组件,而不是在另一个线程上。在大多数情况下它可能没有问题,但最终你会偶然发现奇怪的错误。
据我所知,所有事件都是通过EDT进行的。因此,如果我在例如actionPerformed方法中创建一个新组件,它应该可以。
此外,如果我将runnable实例传递给invokeLater或invokeAndWait,那么所有run()方法都将由EDT完成。
正确。
所以在我的anonim类中,我在EDT中添加了两个按钮,但是在调整大小之后组件没有添加到我的框架中
向setVisible
添加组件需要您重新验证布局(请参阅Container
方法的javadoc)。只需致电
Container#add
添加按钮后,它将按预期工作。手动调整框架大小与您已经注意到的效果相同。
所以即使在edt中我也不会得到我的新组件,但是当我在edt之外创建一个随机线程并使其更改一些gui元素属性(例如setText)时,在edt之外工作正常。
如前所述,它可能在大多数时间都有效,但不能保证它会100%的时间都能正常工作。上面解释了添加组件无法按预期工作的原因,并且与线程问题无关。