我的问题:为什么我的SwingWorker似乎只是在它的线程中执行我的工具,并从 doInBackground()方法中退出(不使用 cancel() SwingWorker方法),不调用done()方法,这样当工具在 doInBackground()中完成时,我的进度条和标签可能会被清除?
我对SwingWorkers很陌生,但是我很快就接受了它们,并且在需要运行线程进程并仍然更新GUI时它们很有意义。当我需要向类似Wizard的GUI添加进度条时,我最终找到了SwingWork类。 GUI从用户收集一些数据,然后运行我已经测试过的工具并根据该数据处理文件。
我有我的基本SwingWorker调用我的工具(从它自己的线程调用):
private class DeIDTask extends SwingWorker<Void, Void> {
private DeIdentifier deidentifier;
boolean processing = true;
DeIDTask(DeIdentifier deid) {
this.deidentifier = deid;
}
/*
* Main task. Executed in background thread.
*/
@Override
protected Void doInBackground() throws Exception {
// Initialize Progress
setProgress(0);
//Sleep for at least one second to simulate "startup".
try {
Thread.sleep(1000 + new Random().nextInt(2000));
} catch (InterruptedException ignore) {}
// Do Processing
Thread procThread = new Thread(new DeIdentifierProcessThread(deidentifier));
procThread.start();
while(procThread.isAlive()) {
try {
// try to join every half a second
procThread.join(500);
setProgress(deidentifier.getProcessProgress());
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
processing = false;
// Do Output Flushing
Thread outputThread = new Thread(new DeIdentifierOutputThread(deidentifier));
outputThread.start();
while(outputThread.isAlive()) {
try {
// try to join every quarter second
procThread.join(250);
setProgress(deidentifier.getOutputProgress());
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
return null;
}
/*
* Executed in event dispatching thread
*/
@Override
protected void done() {
lblProgress_deid.setText("Done.");
progressBar_deid.setStringPainted(false);
progressBar_deid.setIndeterminate(false);
button_65.setEnabled(true);
}
}
请注意,此SwingWorker类仅实现 doInBackground()和 done()方法。我没有以任何方式调用 cancel(),我知道它可以在 doInBackground() done()方法>方法已经完成。
我的想法是,我的SwingWork可能没有正确执行,因此我的 done()方法无法找到Event Dispatch Thread。我找到了这样的答案here,但回答者回答问题的方式对于我更复杂的GUI来说真的很简单,并没有真正解释如何在main方法中创建一个JFrame使Swing应用程序成为SwingWork显式连接到。在我看来,你不需要做一些特殊的事情来将SwingWorker连接到Swing组件。
我创建了一个正常运行的GUI,我的GUI调用SwingWorker的地方来自JButton:
btnStartDeidentification = new JButton("Start De-Identification");
btnStartDeidentification.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// Disable clicking of the button
progressBar_deid.setIndeterminate(true);
btnStartDeidentification.setEnabled(false);
task_deid = new DeIDTask(deidentifier);
task_deid.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
int progress = task_deid.getProgress();
System.out.println("Progress is: " + progress);
progressBar_deid.setIndeterminate(false);
progressBar_deid.setString(null);
progressBar_deid.setValue(progress);
progressBar_deid.setStringPainted(true);
lblProgress_deid.setText("Processing Records (Current/Total): " + deidentifier.getCurrentLineNumber() + "/" + deidentifier.getNumberOfLinesInFile());
}
});
task_deid.execute();
}
});
btnStartDeidentification.setBounds(107, 195, 200, 29);
panel_runDeIDTool_23.add(btnStartDeidentification);
我的下一个想法可能是因为我实际上是从内部我的 actionPerformed()方法初始化并执行SwingWork task_deid done()方法由于某种原因没有找到EDT。但是这个问题here on SO,与我自己的问题非常相似,有一个从 changeListener()内部调用SwingWorker的例子。并且回答者声明 changeListener()是EDT的一部分。我还没有在GUI中使用changeListener,但我认为这意味着我可以在actionPerformed方法中创建和调用 task_deid 。
现在,这些代码片段依赖于我使用Eclipse Window Builder工具创建的名为GUI的整个类。该课程的要点是:
public class GUI {
private JFrame frmToolWizard;
private JPanel panel_Steps;
...
private JPanel panel_runDeIDTool_23;
...
private JButton btnStartDeidentification;
private JProgressBar progressBar_deid;
private JLabel lblProgress_deid;
...
private DeIDTask task_deid;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
GUI window = new GUI();
window.frmToolWizard.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public GUI() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frmToolWizard = new JFrame();
...
panel_Steps = new JPanel();
frmToolWizard.getContentPane().add(panel_Steps);
...
panel_runDeIDTool_23 = new JPanel();
panel_Steps.add(panel_runDeIDTool_23, "name_1406678727369229000");
...
// Lot of other components here
...
btnStartDeidentification = new JButton("Start De-Identification");
...
}
private class DeIDTask extends SwingWorker<Void, Void> {
...
}
}
调用 done()方法的重点是,我想最终确定进度条,将其设为空白,并将进度条下的标签设置为“完成”。所以最终用户知道他们可以继续前进。在DeIDTask done()方法中可以清楚地看到我想要做的所有这些。
非常感谢任何帮助。如果这是一个明显的答案我提前道歉,因为我没有看到我需要做些什么来解决我的问题。
答案 0 :(得分:1)
isDone()
之后调用 doInBackground()
,但在isDone()
完成后您收到属性更改事件,因为您的侦听器会覆盖您在isDone()
中修改的几乎所有UI属性你得出了错误的结论。
PropertyChangeEvent
针对不同的属性发送,最明显的是progress
和state
。调用isDone
后收到的最后一个事件告诉您state
的{{1}}属性从SwingWorker
转到STARTED
。
您可以检查DONE
的{{3}},以区分PropertyChangeEvent
和progress
的更改。