Java Swing教程 - Java Swing线程

Swing的线程安全规则规定,一旦实现了Swing组件,就必须在事件分派线程上修改或访问该组件的状态。

如果组件已经被涂漆或者准备涂漆,则认为该组件被实现。

Swing中的顶级容器是在我们调用它的pack()时实现的,第一次使用setVisible(true)或show()方法。

当实现顶层容器时,它的所有子代也被实现。

事件分派线程是JVM在检测到它正在使用Swing应用程序时由JVM自动创建的线程。JVM使用此线程来执行Swing组件的事件处理程序。

例如,当我们单击JButton时,actionPerformed()方法中的代码由事件分派线程执行。

以下两个类是Swing应用程序中用于处理其线程模型的辅助类。 类是

SwingUtilities
SwingWorker

要知道代码是否在事件分派线程中执行,使用SwingUtilities类的静态方法isEventDispatchThread()。

如果代码在事件分派线程中执行,则返回true。 否则,它返回false。

System.out.println(SwingUtilities.isEventDispatchThread());

使用Swing操作处理程序代码时,应遵循以下列出的规则。

add all event handlers to a component at the end of the GUI-building code.
run all GUI code on the event dispatch thread
by using the invokeLater(Runnable r) method from the SwingUtilities class.

以下代码显示了启动Swing应用程序的正确方法。

SwingUtilities.invokeLater(() -> {
MySwingApp app = new MySwingApp("A Swing App");
app.pack();
app.setVisible(true);
});

如果事件分派线程尚未启动,SwingUtilities.invokeLater(Runnable r)方法将启动它。

SwingUtilities.invokeLater()方法调用立即返回,并且Runnable参数的run()方法是异步执行的。

在SwingUtilities类中有另一个重要的静态方法invokeAndWait(Runnable r)。

此方法是同步执行的,它不会返回,直到run()方法在事件分派线程上完成执行。 此方法可能会抛出InterruptedException或InvocationTargetException。

不应该从事件调度中调用SwingUtilities.invokeAndWait(Runnable r)方法线程,因为它会阻塞事件分派线程。

我们可以使用SwingUtilities类的invokeAndWait()方法来启动Swing应用程序,而不是invokeLater()方法。

try {
SwingUtilities.invokeAndWait(() -> {
JFrame frame = new JFrame();
frame.pack();
frame.setVisible(true);
});
System.out.println("Swing application is running...");
}catch (Exception e) {
e.printStackTrace();
}

Java Swing教程 - Java Swing线程...

要在Swing应用程序中执行耗时的任务,在除了事件分派线程之外的单独线程中执行长任务。

Swing提供了一个SwingWorker类,这使得在Swing应用程序中很容易使用多个线程。

SwingWorker< T,V> 类被声明为abstract。 类型参数T是结果类型,类型参数V是中间结果类型。

SwingWorker< T,V> 类被声明为abstract。 类型参数T是结果类型,类型参数V是中间结果类型。...

doInBackground(): perform a time-consuming task. It is executed in a separate worker thread.
process(): called as a result of a publish() method call. This method executes on the event dispatch thread, and we can access Swing component in this method.
The publish() method accepts a varargs argument. The process() method passes all arguments to the publish() method packed in a List.
done(): When the doInBackground() method finishes, normally or abnormally, the done() method is called on the event dispatch thread. we can access Swing components in this method.
execute(): call this method to start executing the task in a separate thread.
get(): This method returns the result of the task as returned from the doInBackground() method. It is not suggested to call this method on the event dispatch thread, as it will block all events until it returns.
cancel(boolean mayInterruptIfRunning): This method cancels the task if it is still running.
isCancelled(): returns true if the process has been cancelled. Otherwise, it returns false.
isDone(): It returns true if the task has completed. A task may complete normally or by throwing an exception or by cancellation. Otherwise, it returns false.
import java.awt.BorderLayout;
import java.awt.Container;
import java.util.List;
//fromwww.java2s.com
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
class SwingWorkerProcessor extends SwingWorker {
private final SwingWorkerFrame frame;
private int iteration;
private int intervalInMillis;
public SwingWorkerProcessor(SwingWorkerFrame frame, int iteration,
int intervalInMillis) {
this.frame = frame;
this.iteration = iteration;
if (this.iteration <= 0) {
this.iteration = 10;
}
this.intervalInMillis = intervalInMillis;
if (this.intervalInMillis <= 0) {
this.intervalInMillis = 1000;
}
}
@Override
protected Integer doInBackground() throws Exception {
int sum = 0;
for (int counter = 1; counter <= iteration; counter++) {
sum = sum + counter;
this.publish(counter);
if (Thread.interrupted()) {
throw new InterruptedException();
}
if (this.isCancelled()) {
break;
}
Thread.sleep(intervalInMillis);
}
return sum;
}
@Override
protected void process(List data) {
for (int counter : data) {
frame.updateStatus(counter, iteration);
}
}
@Override
public void done() {
try {
frame.doneProcessing();
} catch (Exception e) {
e.printStackTrace();
}
}
}
class SwingWorkerFrame extends JFrame {
String startMessage = "Please click the start button...";
JLabel statusLabel = new JLabel(startMessage);
JButton startButton = new JButton("Start");
JButton cancelButton = new JButton("Cancel");
SwingWorkerProcessor processor;
public SwingWorkerFrame() {
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
Container contentPane = this.getContentPane();
cancelButton.setEnabled(false);
contentPane.add(statusLabel, BorderLayout.NORTH);
contentPane.add(startButton, BorderLayout.WEST);
contentPane.add(cancelButton, BorderLayout.EAST);
startButton.addActionListener(e -> startProcessing());
cancelButton.addActionListener(e -> cancelProcessing());
}
public void setButtonStatus(boolean canStart) {
if (canStart) {
startButton.setEnabled(true);
cancelButton.setEnabled(false);
} else {
startButton.setEnabled(false);
cancelButton.setEnabled(true);
}
}
public void startProcessing() {
setButtonStatus(false);
processor = new SwingWorkerProcessor(this, 10, 1000);
processor.execute();
}
public void cancelProcessing() {
processor.cancel(true);
setButtonStatus(true);
}
public void updateStatus(int counter, int total) {
String msg = "Processing " + counter + " of " + total;
statusLabel.setText(msg);
}
public void doneProcessing()throws Exception {
if (processor.isCancelled()) {
statusLabel.setText("Process cancelled ...");
} else {
int sum = processor.get();
statusLabel.setText("Sum is " + sum);
setButtonStatus(true);
}
}
}
public class Main{
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
SwingWorkerFrame frame = new SwingWorkerFrame();
frame.pack();
frame.setVisible(true);
});
}
}