好的,所以我一直在玩SwingWorker并获得了一些更新gui的简化代码,但是我很难弄清楚如何让线程在完成时正确终止。目前,它只通过停止选项终止。如何设置它以在完成其进程时正确终止线程?目前,return null;
进入包装行并挂起。
我的代码如下:
package concurrency;
import java.util.List;
import java.util.Random;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.Insets;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
public class PBTest extends JFrame implements ActionListener {
private final GridBagConstraints constraints;
private final JProgressBar pb, pbF;
private final JButton theButton;
private PBTask pbTask;
private JProgressBar makePB() {
JProgressBar p = new JProgressBar(0,100);
p.setValue(0);
p.setStringPainted(true);
getContentPane().add(p, constraints);
return p;
}
public PBTest() {
super("PBTest");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Make text boxes
getContentPane().setLayout(new GridBagLayout());
constraints = new GridBagConstraints();
constraints.insets = new Insets(3, 10, 3, 10);
pb = makePB();
pbF = makePB();
//Make buttons
theButton = new JButton("Start");
theButton.setActionCommand("Start");
theButton.addActionListener(this);
getContentPane().add(theButton, constraints);
//Display the window.
pack();
setVisible(true);
}
private static class UpdatePB {
private final int pb1, pb2;
UpdatePB(int pb1s, int pb2s) {
this.pb1 = pb1s;
this.pb2 = pb2s;
}
}
private class PBTask extends SwingWorker<Void, UpdatePB> {
@Override
protected Void doInBackground() {
int prog1 = 0;
int prog2 = 0;
Random random = new Random();
while (prog2 < 100) {
if(prog1 >= 100) {
prog1 = 0;
}
//Sleep for up to one second.
try {
Thread.sleep(random.nextInt(1000));
} catch (InterruptedException ignore) {}
//Make random progress.
prog1 += random.nextInt(10);
prog2 += random.nextInt(5);
publish(new UpdatePB(prog1, prog2));
}
return null;
}
@Override
protected void process(List<UpdatePB> pairs) {
UpdatePB pair = pairs.get(pairs.size() - 1);
pb.setValue(pair.pb1);
pbF.setValue(pair.pb2);
}
}
public void actionPerformed(ActionEvent e) {
if ("Start" == e.getActionCommand() && pbTask == null) {
theButton.setText("Stop");
theButton.setActionCommand("Stop");
(pbTask = new PBTask()).execute();
} else if ("Stop" == e.getActionCommand()) {
theButton.setText("Start");
theButton.setActionCommand("Start");
pbTask.cancel(true);
pbTask = null;
} else {
alertMsg("Thread still running.");
}
}
static void alertMsg(String theAlert) {
JOptionPane.showMessageDialog(null, theAlert);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new PBTest();
}
});
}
}
注意:这基本上是对Java教程“鳍状肢”示例的改动......我不是一个程序员,而是一个代码黑客(/悲伤的面孔/,哈哈),此刻,所以我关于下一步该去哪儿,我感到很茫然。
无论如何,代码按预期工作直到完成。我尝试添加done()
方法,但它从不尝试运行它,它总是只到包行(当单步执行调试器时)并挂起。我应该返回null以外的值吗?
提前感谢您的帮助!
答案 0 :(得分:4)
例如
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
public class SwingWorkerExample extends JFrame implements ActionListener {
private static final long serialVersionUID = 1L;
private final JButton startButton, stopButton;
private JScrollPane scrollPane = new JScrollPane();
private JList listBox = null;
private DefaultListModel listModel = new DefaultListModel();
private final JProgressBar progressBar;
private mySwingWorker swingWorker;
public SwingWorkerExample() {
super("SwingWorkerExample");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().setLayout(new GridLayout(2, 2));
startButton = makeButton("Start");
stopButton = makeButton("Stop");
stopButton.setEnabled(false);
progressBar = makeProgressBar(0, 99);
listBox = new JList(listModel);
scrollPane.setViewportView(listBox);
getContentPane().add(scrollPane);
//Display the window.
pack();
setVisible(true);
}
//Class SwingWorker<T,V> T - the result type returned by this SwingWorker's doInBackground
//and get methods V - the type used for carrying out intermediate results by this SwingWorker's
//publish and process methods
private class mySwingWorker extends javax.swing.SwingWorker<ArrayList<Integer>, Integer> {
//The first template argument, in this case, ArrayList<Integer>, is what s returned by doInBackground(),
//and by get(). The second template argument, in this case, Integer, is what is published with the
//publish method. It is also the data type which is stored by the java.util.List that is the parameter
//for the process method, which recieves the information published by the publish method.
@Override
protected ArrayList<Integer> doInBackground() {
//Returns items of the type given as the first template argument to the SwingWorker class.
if (javax.swing.SwingUtilities.isEventDispatchThread()) {
System.out.println("javax.swing.SwingUtilities.isEventDispatchThread() returned true.");
}
Integer tmpValue = new Integer(1);
ArrayList<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < 100; i++) {
for (int j = 0; j < 100; j++) { //find every 100th prime, just to make it slower
tmpValue = FindNextPrime(tmpValue.intValue());
//isCancelled() returns true if the cancel() method is invoked on this class. That is the proper way
//to stop this thread. See the actionPerformed method.
if (isCancelled()) {
System.out.println("SwingWorker - isCancelled");
return list;
}
}
//Successive calls to publish are coalesced into a java.util.List, which is what is received by process,
//which in this case, isused to update the JProgressBar. Thus, the values passed to publish range from
//1 to 100.
publish(new Integer(i));
list.add(tmpValue);
}
return list;
}//Note, always use java.util.List here, or it will use the wrong list.
@Override
protected void process(java.util.List<Integer> progressList) {
//This method is processing a java.util.List of items given as successive arguments to the publish method.
//Note that these calls are coalesced into a java.util.List. This list holds items of the type given as the
//second template parameter type to SwingWorker. Note that the get method below has nothing to do with the
//SwingWorker get method; it is the List's get method. This would be a good place to update a progress bar.
if (!javax.swing.SwingUtilities.isEventDispatchThread()) {
System.out.println("javax.swing.SwingUtilities.isEventDispatchThread() + returned false.");
}
Integer percentComplete = progressList.get(progressList.size() - 1);
progressBar.setValue(percentComplete.intValue());
}
@Override
protected void done() {
System.out.println("doInBackground is complete");
if (!javax.swing.SwingUtilities.isEventDispatchThread()) {
System.out.println("javax.swing.SwingUtilities.isEventDispatchThread() + returned false.");
}
try {
//Here, the SwingWorker's get method returns an item of the same type as specified as the first type parameter
//given to the SwingWorker class.
ArrayList<Integer> results = get();
for (Integer i : results) {
listModel.addElement(i.toString());
}
} catch (Exception e) {
System.out.println("Caught an exception: " + e);
}
startButton();
}
boolean IsPrime(int num) { //Checks whether a number is prime
int i;
for (i = 2; i <= num / 2; i++) {
if (num % i == 0) {
return false;
}
}
return true;
}
protected Integer FindNextPrime(int num) { //Returns next prime number from passed arg.
do {
if (num % 2 == 0) {
num++;
} else {
num += 2;
}
} while (!IsPrime(num));
return new Integer(num);
}
}
private JButton makeButton(String caption) {
JButton b = new JButton(caption);
b.setActionCommand(caption);
b.addActionListener(this);
getContentPane().add(b);
return b;
}
private JProgressBar makeProgressBar(int min, int max) {
JProgressBar progressBar1 = new JProgressBar();
progressBar1.setMinimum(min);
progressBar1.setMaximum(max);
progressBar1.setStringPainted(true);
progressBar1.setBorderPainted(true);
getContentPane().add(progressBar1);
return progressBar1;
}
private void startButton() {
startButton.setEnabled(true);
stopButton.setEnabled(false);
System.out.println("SwingWorker - Done");
}
@Override
public void actionPerformed(ActionEvent e) {
if ("Start" == null ? e.getActionCommand() == null : "Start".equals(e.getActionCommand())) {
startButton.setEnabled(false);
stopButton.setEnabled(true);
// Note that it creates a new instance of the SwingWorker-derived class. Never reuse an old one.
(swingWorker = new mySwingWorker()).execute(); // new instance
} else if ("Stop" == null ? e.getActionCommand() == null : "Stop".equals(e.getActionCommand())) {
startButton.setEnabled(true);
stopButton.setEnabled(false);
swingWorker.cancel(true); // causes isCancelled to return true in doInBackground
swingWorker = null;
}
}
public static void main(String[] args) {
// Notice that it kicks it off on the event-dispatching thread, not the main thread.
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
SwingWorkerExample swingWorkerExample = new SwingWorkerExample();
}
});
}
}
答案 1 :(得分:3)
我不确定你想要实现的目标。 你的例子工作正常。工作线程一直运行到最后。 如果你想等到它结束做某事,你必须在代码中的某个地方调用方法pbTask.get()。否则,它将在不影响任何UI组件的情况下安静地完成。
请考虑对您的方法进行以下更改,以了解它现在的行为方式。请注意,UI会因为您等待线程完成而冻结,但只有在WorkerThread完成时才会在您的日志中显示输出“DONE”。
public void actionPerformed(ActionEvent e) {
if ("Start" == e.getActionCommand() && pbTask == null) {
theButton.setText("Stop");
theButton.setActionCommand("Stop");
(pbTask = new PBTask()).execute();
} else if ("Stop" == e.getActionCommand()) {
theButton.setText("Start");
theButton.setActionCommand("Start");
pbTask.cancel(true);
pbTask = null;
} else {
alertMsg("Thread still running.");
}
try {
pbTask.get();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (ExecutionException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.out.println("DONE");
}
这种变化只是为了说明差异。为了编写实际代码,我们需要更多地了解您要实现的目标。
如果我的超感官技巧没问题,那么你可能想要将按钮翻回“开始”。为此,您需要在Worker:
中覆盖done()方法private class PBTask extends SwingWorker<Void, UpdatePB> {
@Override
protected Void doInBackground() {
int prog1 = 0;
int prog2 = 0;
Random random = new Random();
while (prog2 < 100) {
if(prog1 >= 100) {
prog1 = 0;
}
//Sleep for up to one second.
try {
Thread.sleep(random.nextInt(100));
} catch (InterruptedException ignore) {}
//Make random progress.
prog1 += random.nextInt(10);
prog2 += random.nextInt(5);
publish(new UpdatePB(prog1, prog2));
}
return null;
}
@Override
protected void process(List<UpdatePB> pairs) {
UpdatePB pair = pairs.get(pairs.size() - 1);
pb.setValue(pair.pb1);
pbF.setValue(pair.pb2);
}
@Override
protected void done() {
super.done();
theButton.setText("Start");
theButton.setActionCommand("Start");
}
}