我正在阅读Thinking in Java,作者强调主要方法不应该调用swing方法。作为这种做法的一个例子,他提出了以下代码(可在他的网页上找到):
//: gui/SubmitSwingProgram.java
import javax.swing.*;
import java.util.concurrent.*;
public class SubmitSwingProgram extends JFrame {
JLabel label;
public SubmitSwingProgram() {
super("Hello Swing");
label = new JLabel("A Label");
add(label);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(300, 100);
setVisible(true);
}
static SubmitSwingProgram ssp;
public static void main(String[] args) throws Exception {
SwingUtilities.invokeLater(new Runnable() {
public void run() { ssp = new SubmitSwingProgram(); }
});
TimeUnit.SECONDS.sleep(1);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
ssp.label.setText("Hey! This is Different!");
}
});
}
} ///:~
然后通过invokeLater方法创建并初始化gui对象,使其成为线程安全的。但是几页之后,作者提出了以下代码:
//: gui/Button2.java
// Responding to button presses.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import static net.mindview.util.SwingConsole.*;
public class Button2 extends JFrame {
private JButton
b1 = new JButton("Button 1"),
b2 = new JButton("Button 2");
private JTextField txt = new JTextField(10);
class ButtonListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
String name = ((JButton)e.getSource()).getText();
txt.setText(name);
}
}
private ButtonListener bl = new ButtonListener();
public Button2() {
b1.addActionListener(bl);
b2.addActionListener(bl);
setLayout(new FlowLayout());
add(b1);
add(b2);
add(txt);
}
public static void main(String[] args) {
run(new Button2(), 200, 150);
}
} ///:~
其中SwingConsole是:
//: net/mindview/util/SwingConsole.java
// Tool for running Swing demos from the
// console, both applets and JFrames.
package net.mindview.util;
import javax.swing.*;
public class SwingConsole {
public static void
run(final JFrame f, final int width, final int height) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
f.setTitle(f.getClass().getSimpleName());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(width, height);
f.setVisible(true);
}
});
}
} ///:~
因此,与前面的示例相反,在主方法/主线程中创建并初始化实现JFrame的对象。
我的问题是: (1)第二个例子是错误的还是第一个被夸大了? (2)仅在setVisible调用之后通过invokeLater调用swing方法并且在该语句之前调用主线程中的swing方法是否安全是否足够?
答案 0 :(得分:5)
第二个例子是错误的。必须从事件派发线程创建和使用Swing组件。请参阅https://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html。
引自the javadoc:
不会在事件派发线程上调用对应用程序的主要方法或Applet中的方法的调用。因此,在构建和显示应用程序或小程序时,必须注意将控制权转移到事件派发线程。
(强调我的)
答案 1 :(得分:-1)
使用main()方法的示例可能有点误导。规则AFAIK是只允许主线程执行Swing更新/重绘等,每个definitionem 的main()方法是主线程。所有其他线程都需要通过SwingUtilities.invokeLater(...)来安排内容。即使对于主线程,它也可能会改善延迟,因为您可能会在主线程中花费大量时间,并且只要主线程不太忙,就会调度GUI刷新敌人。
编辑:证明错误