Swing的線程安全規(guī)則規(guī)定,一旦實現(xiàn)了Swing組件,就必須在事件分派線程上修改或訪問該組件的狀態(tài)。
如果組件已經(jīng)被涂漆或者準(zhǔn)備涂漆,則認(rèn)為該組件被實現(xiàn)。
Swing中的頂級容器是在我們調(diào)用它的pack()時實現(xiàn)的,第一次使用setVisible(true)或show()方法。
當(dāng)實現(xiàn)頂層容器時,它的所有子代也被實現(xiàn)。
事件分派線程是JVM在檢測到它正在使用Swing應(yīng)用程序時由JVM自動創(chuàng)建的線程。JVM使用此線程來執(zhí)行Swing組件的事件處理程序。
例如,當(dāng)我們單擊JButton時,actionPerformed()方法中的代碼由事件分派線程執(zhí)行。
以下兩個類是Swing應(yīng)用程序中用于處理其線程模型的輔助類。 類是
要知道代碼是否在事件分派線程中執(zhí)行,使用SwingUtilities類的靜態(tài)方法isEventDispatchThread()。
如果代碼在事件分派線程中執(zhí)行,則返回true。 否則,它返回false。
System.out.println(SwingUtilities.isEventDispatchThread());
使用Swing操作處理程序代碼時,應(yīng)遵循以下列出的規(guī)則。
以下代碼顯示了啟動Swing應(yīng)用程序的正確方法。
SwingUtilities.invokeLater(() -> { MySwingApp app = new MySwingApp("A Swing App"); app.pack(); app.setVisible(true); });
如果事件分派線程尚未啟動,SwingUtilities.invokeLater(Runnable r)方法將啟動它。
SwingUtilities.invokeLater()方法調(diào)用立即返回,并且Runnable參數(shù)的run()方法是異步執(zhí)行的。
在SwingUtilities類中有另一個重要的靜態(tài)方法invokeAndWait(Runnable r)。
此方法是同步執(zhí)行的,它不會返回,直到run()方法在事件分派線程上完成執(zhí)行。 此方法可能會拋出InterruptedException或InvocationTargetException。
不應(yīng)該從事件調(diào)度中調(diào)用SwingUtilities.invokeAndWait(Runnable r)方法線程,因為它會阻塞事件分派線程。
我們可以使用SwingUtilities類的invokeAndWait()方法來啟動Swing應(yīng)用程序,而不是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(); }
要在Swing應(yīng)用程序中執(zhí)行耗時的任務(wù),在除了事件分派線程之外的單獨線程中執(zhí)行長任務(wù)。
Swing提供了一個SwingWorker類,這使得在Swing應(yīng)用程序中很容易使用多個線程。
SwingWorker< T,V> 類被聲明為abstract。 類型參數(shù)T是結(jié)果類型,類型參數(shù)V是中間結(jié)果類型。
SwingWorker< T,V> 類被聲明為abstract。 類型參數(shù)T是結(jié)果類型,類型參數(shù)V是中間結(jié)果類型。...
import java.awt.BorderLayout; import java.awt.Container; import java.util.List; //from ww w . ja v a2s .co m import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; class SwingWorkerProcessor extends SwingWorker<Integer, Integer> { 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<Integer> 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); }); } }
更多建議: