SwingWorker done()方法貌似没有被调用?但是,SwingWork未被取消或阻止,不使用发布/处理方法

时间:2014-08-18 21:13:20

标签: java multithreading user-interface swingworker windowbuilder

我的问题:为什么我的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()方法中可以清楚地看到我想要做的所有这些。

非常感谢任何帮助。如果这是一个明显的答案我提前道歉,因为我没有看到我需要做些什么来解决我的问题。

1 个答案:

答案 0 :(得分:1)

isDone()之后调用

doInBackground(),但在isDone()完成后您收到属性更改事件,因为您的侦听器会覆盖您在isDone()中修改的几乎所有UI属性你得出了错误的结论。

PropertyChangeEvent针对不同的属性发送,最明显的是progressstate。调用isDone后收到的最后一个事件告诉您state的{​​{1}}属性从SwingWorker转到STARTED

您可以检查DONE的{​​{3}},以区分PropertyChangeEventprogress的更改。