【发布时间】:2014-10-11 21:17:20
【问题描述】:
我的问题: 为什么是我的 SwingWorker,它似乎只是在它的线程中执行我的工具,然后从 doInBackground() 方法中退出就好了(不使用cancel() SwingWorker 方法),不调用 done() 方法,所以当工具在 doInBackground() 中完成时,我的进度条和标签可能会被清理? p>
我对 SwingWorkers 还很陌生,但我很快就学会了它们,当需要运行线程进程并仍然更新 GUI 时,它们很有意义。当我需要向类似向导的 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() 方法找不到事件调度线程。我找到了这样的答案here,但回答者回答问题的方式对于我更复杂的 GUI 来说真的很简单,并且没有真正解释如何在 main 方法中创建 JFrame 使得 SwingWork 明确成为 Swing 应用程序连接到。在我看来,您不需要做一些特别的事情来将 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);
我的下一个想法是,可能是因为我实际上是从 inside 我的 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() 方法中非常清楚地看到了。
非常感谢任何帮助。如果这是一个明显的答案,我提前道歉,因为我没有看到我需要做些什么来解决我的问题。
【问题讨论】:
标签: java multithreading user-interface swingworker windowbuilder