App.java:import javax.swing.SwingUtilities; public class App { /** * @param args */ public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { new MainFrame("SwingWorker Demo"); } }); } }
MainFrame.java:import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.List; import java.util.concurrent.ExecutionException; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.SwingWorker; public class MainFrame extends JFrame { private JLabel countLabel1 = new JLabel("0"); private JLabel statusLabel = new JLabel("Task not completed."); private JButton startButton = new JButton("Start"); public MainFrame(String title) { super(title); setLayout(new GridBagLayout()); GridBagConstraints gc = new GridBagConstraints(); gc.fill = GridBagConstraints.NONE; gc.gridx = 0; gc.gridy = 0; gc.weightx = 1; gc.weighty = 1; add(countLabel1, gc); gc.gridx = 0; gc.gridy = 1; gc.weightx = 1; gc.weighty = 1; add(statusLabel, gc); gc.gridx = 0; gc.gridy = 2; gc.weightx = 1; gc.weighty = 1; add(startButton, gc); startButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { start(); } }); setSize(200, 400); setDefaultCloseOperation(EXIT_ON_CLOSE); setVisible(true); } private void start() { // Use SwingWorker<void void=""> and return null from doInBackground if // you don't want any final result and you don't want to update the GUI // as the thread goes along. // First argument is the thread result, returned when processing finished. // Second argument is the value to update the GUI with via publish() and process() SwingWorker<boolean integer=""> worker = new SwingWorker<boolean integer="">() { @Override /* * Note: do not update the GUI from within doInBackground. */ protected Boolean doInBackground() throws Exception { // Simulate useful work for(int i=0; i<30; i++) { Thread.sleep(100); System.out.println("Hello: " + i); // optional: use publish to send values to process(), which // you can then use to update the GUI. publish(i); } return false; } @Override // This will be called if you call publish() from doInBackground() // Can safely update the GUI here. protected void process(List<integer> chunks) { Integer value = chunks.get(chunks.size() - 1); countLabel1.setText("Current value: " + value); } @Override // This is called when the thread finishes. // Can safely update GUI here. protected void done() { try { Boolean status = get(); statusLabel.setText("Completed with status: " + status); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ExecutionException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; worker.execute(); } }</integer></boolean></boolean></void>
SwingWorker的第一个template argument:doInBackground方法的返回类型,get方法的返回值类型template argument中只能用Void(void对应的类)。如果用Void,doInBackground方法必须返回null。
template argument中只能用class,不能用primitive type。
SwingWorker的第二个template argument:publish方法的参数类型,process方法参数List的泛型类型。如果要再doInBackground方法执行的同时,update GUI,在doInBackground方法中调用publish方法,然后override process方法。
process方法的参数是一个List<第二个template argument>,因为并不是每一次在doInBackground方法中调用publish的时候process方法都会被调用。这个List保存了每次publish的内容。在process方法中,可以update GUI safely。process方法在EDT中被调度。
每一个SwingWorker对象只能execute一次,如果需要再执行一遍,只能再创建一个对象。
doInBackground方法中update GUI不安全。doInBackground方法可以throw exception。在done方法中可以catch。
done方法在这个thread结束的时候会被执行,done方法中可以update GUI safely。
get方法得到doInBackground方法的返回值,如果doInBackground还没有执行完,get方法wait。