在 edt 中更新 swing 组件
Updating swing components within edt
如果我理解正确,那么当我创建 GUI swing 组件时,例如我有这个:
public class frameExample extends JFrame{
public frameExample(){
//Here adding bunch if components
setVisible(true);
}
}
因此,只要我不调用 setVisible 方法,组件就会从创建实例的线程中生成。因此,如果在 class 中我有我的主要方法,请写:
JFrame test=new frameExample();
我系统输出
Thread.currentThread.getName();
在 setVisible 之前的 frameExample 的构造函数中,我应该得到:main.
之后创建和维护 swing 元素的责任被传递给事件调度线程,因为它不是线程安全的,每个组件 add/remove/modify 应该在 EDT 线程中完成。
所以我应该将 setVisible 放在构造函数的最后一行代码中,或者单独调用它。
据我所知,所有事件监听都通过 EDT。因此,如果我在 actionPerformed 方法中创建一个新组件,它应该可以正常工作。
此外,如果我将 运行nable 实例传递给 invokeLater 或 invokeAndWait,那么所有 运行() 方法都将由 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 class 中,我在 EDT 中添加了两个按钮 im,但是在我调整它的大小后组件没有添加到我的框架中(这会强制 edt 更新它的组件?? ? 这是什么原因?).
所以即使在 edt 中我也没有得到我的新组件,但是当我在 edt 之外创建一个随机线程并让它更改一些 gui 元素时 属性(例如 setText)在 edt 之外工作正常。
所以我的第一个问题是:为什么我的组件没有在 edt 中更新以及为什么它们在调整大小后可见
第二个:为什么我可以在 edt 之外更改 swing 组件并且一切正常?这只是随机线程行为吗,例如,没有同步块,事情就可以正常工作,但是当你重新运行你在某个时候编程时,它最终会因为缺乏同步而崩溃。
So as long as I don't call the setVisible method the components are being made from the thread the instance was created
错了。只要您不专门创建新的 Thread
或使用实用方法(例如 SwingUtilities#invoke...
方法),每次调用都会在当前 Thread
上调用,包括 setVisible
打电话。
您似乎认为使 Swing 组件可见会以某种方式使您的代码切换线程。不,Swing 组件的绘制将发生在 EDT 上。正如您正确指出的那样,Swing 不是线程安全的。
这就是为什么您也应该在 EDT 上而不是在另一个线程上创建组件。它可能在大多数时候都没有问题,但最终你会偶然发现奇怪的错误。
As I understand all event listening goes through the EDT. So if I create a new component within for example an actionPerformed method it should do fine.
Also if I pass a runnable instance to invokeLater or invokeAndWait then all the run() method will be done by the EDT.
正确。
So in my anonim class where I add the two buttons im in the EDT, but the components are not added to my frame just after i resize it
向 Container
添加组件需要您重新验证布局(请参阅 Container#add
方法的 javadoc)。打电话
revalidate();
repaint();
添加按钮后,它将按预期工作。手动调整框架的大小与您已经注意到的效果相同。
So i dont get my new components even within edt, however when i create a random thread outside edt and make it change some gui element property (for example setText) in just works fine outside the edt.
如前所述,它可能在大多数时间都有效,但不能保证它会在 100% 的时间有效。添加组件未按预期工作的原因已在上面解释,与线程问题无关。
如果我理解正确,那么当我创建 GUI swing 组件时,例如我有这个:
public class frameExample extends JFrame{
public frameExample(){
//Here adding bunch if components
setVisible(true);
}
}
因此,只要我不调用 setVisible 方法,组件就会从创建实例的线程中生成。因此,如果在 class 中我有我的主要方法,请写:
JFrame test=new frameExample();
我系统输出
Thread.currentThread.getName();
在 setVisible 之前的 frameExample 的构造函数中,我应该得到:main.
之后创建和维护 swing 元素的责任被传递给事件调度线程,因为它不是线程安全的,每个组件 add/remove/modify 应该在 EDT 线程中完成。
所以我应该将 setVisible 放在构造函数的最后一行代码中,或者单独调用它。
据我所知,所有事件监听都通过 EDT。因此,如果我在 actionPerformed 方法中创建一个新组件,它应该可以正常工作。
此外,如果我将 运行nable 实例传递给 invokeLater 或 invokeAndWait,那么所有 运行() 方法都将由 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 class 中,我在 EDT 中添加了两个按钮 im,但是在我调整它的大小后组件没有添加到我的框架中(这会强制 edt 更新它的组件?? ? 这是什么原因?).
所以即使在 edt 中我也没有得到我的新组件,但是当我在 edt 之外创建一个随机线程并让它更改一些 gui 元素时 属性(例如 setText)在 edt 之外工作正常。
所以我的第一个问题是:为什么我的组件没有在 edt 中更新以及为什么它们在调整大小后可见
第二个:为什么我可以在 edt 之外更改 swing 组件并且一切正常?这只是随机线程行为吗,例如,没有同步块,事情就可以正常工作,但是当你重新运行你在某个时候编程时,它最终会因为缺乏同步而崩溃。
So as long as I don't call the setVisible method the components are being made from the thread the instance was created
错了。只要您不专门创建新的 Thread
或使用实用方法(例如 SwingUtilities#invoke...
方法),每次调用都会在当前 Thread
上调用,包括 setVisible
打电话。
您似乎认为使 Swing 组件可见会以某种方式使您的代码切换线程。不,Swing 组件的绘制将发生在 EDT 上。正如您正确指出的那样,Swing 不是线程安全的。 这就是为什么您也应该在 EDT 上而不是在另一个线程上创建组件。它可能在大多数时候都没有问题,但最终你会偶然发现奇怪的错误。
As I understand all event listening goes through the EDT. So if I create a new component within for example an actionPerformed method it should do fine.
Also if I pass a runnable instance to invokeLater or invokeAndWait then all the run() method will be done by the EDT.
正确。
So in my anonim class where I add the two buttons im in the EDT, but the components are not added to my frame just after i resize it
向 Container
添加组件需要您重新验证布局(请参阅 Container#add
方法的 javadoc)。打电话
revalidate();
repaint();
添加按钮后,它将按预期工作。手动调整框架的大小与您已经注意到的效果相同。
So i dont get my new components even within edt, however when i create a random thread outside edt and make it change some gui element property (for example setText) in just works fine outside the edt.
如前所述,它可能在大多数时间都有效,但不能保证它会在 100% 的时间有效。添加组件未按预期工作的原因已在上面解释,与线程问题无关。