【问题标题】:How to Stop a SwingWorker?如何停止 SwingWorker?
【发布时间】:2012-03-22 18:49:24
【问题描述】:

我怎样才能阻止SwingWorker 做他的工作?我知道有 cancel() 方法可以做到这一点,但我能做的最多就是匿名创建一个新的 SwingWorker 来完成这项工作。

下面是代码供参考:

public void mostrarResultado(final ResultSet resultado) {

    new SwingWorker<Void, Object[]>() {

        @Override
        public Void doInBackground() {

            // TODO: Process ResultSet and create Rows.  Call publish() for every N rows created.+
            DefaultTableModel modelo = new DefaultTableModel();
            jTableResultados.removeAll();
            int columnas;
            int res = 0;
            try {
                ResultSetMetaData metadata = resultado.getMetaData();
                columnas = metadata.getColumnCount();
                Object[] etiquetas = new Object[columnas];
                jProgressBar.setIndeterminate(true);
                for (int i = 0; i < columnas; i++) {
                    etiquetas[i] =
                            metadata.getColumnName(i + 1);
                }
                modelo.setColumnIdentifiers(etiquetas);
                jTableResultados.setModel(modelo);

                while (resultado.next() && !this.isCancelled()) {
                    res++;
                    Object fila[] = new Object[columnas];
                    for (int i = 0; i < columnas; i++) {
                        fila[i] = resultado.getObject(i + 1);
                    }
                    modelo.addRow(fila);
                    publish(fila);
                }
                jProgressBar.setIndeterminate(false);
                if (res == 0) {
                    JOptionPane.showMessageDialog(jPanelClientes.getParent(), "No se encontraron resultados con los criterios de búsqueda definidos", "Sin resultados", JOptionPane.INFORMATION_MESSAGE);
                }
            } catch (SQLException ex) {
                LOG.log(Level.SEVERE, "Excepcion: ", ex);
                JOptionPane.showMessageDialog(jPanelClientes.getParent(), "Error en al ejecutar la busqueda seleccionada", "Error", JOptionPane.ERROR_MESSAGE);
            }
            return null;
        }
    }.execute();
}

实际上,这项工作做得很好并且发布时没有任何问题,但鉴于我使用数据库,可能会发生查询有太多结果并且完全发布所花费的时间需要一些时间,因此用户必须能够取消任务并运行新任务。

显然,worker 与取消按钮事件的方法不同,因此我将无法调用 Worker cancel() 方法。

尝试以这种方式使工作者成为该类的属性,但没有运气:

    public class myClass extends javax.swing.JFrame {
      private SwingWorker<Void, Object[]> tarea;

但是当我去的时候:

tarea = new SwingWorker<Void,Object[]>(){...} 

我得到不兼容的类型,发现无效,需要 SwingWorker,我完全没有想法。

有什么建议吗?

谢谢

【问题讨论】:

  • 确实可能重复,可惜搜索没有弹出那个答案:/
  • @Lowb 可能重复,是的,我们不介意读者,没有人知道您的其余代码中发生了什么,因为您的 SwingWorkers 代码不正确,请在此处查看我的答案,以便更好请尽快帮助您编辑您的帖子SSCCE
  • 我的意思是,我没有在搜索中看到那个答案,是的,那些解决了我的问题,这就是为什么我说它是重复的。对不起,如果我不够清楚。

标签: java swing swingworker


【解决方案1】:

1) 从不创建/重新创建

DefaultTableModel modelo = new DefaultTableModel();

2) 请问是什么

jTableResultados.removeAll();

JTable, AbstractTableModel, DefaultTableModel

3) 你的 JProgressBar 不能工作

jProgressBar.setIndeterminate(false);

4) 两个相关问题都让我对取消 SwingWorker's 实例感到满意

【讨论】:

  • 1) 那我应该如何定义tablemodel呢? 2) 删除 jTable 中先前显示的结果,显示 BD 查询的结果 3) 进度条工作得很好。 4) 解决了,是的。
【解决方案2】:

这不是问题的答案(这是如何取消,我认为已经解决),而是如何将后台处理与视图/模型更新分开。伪代码大纲:

public static class MyDBWorker extends SwingWorker<Void, Object[]> {

    private JTable table;
    private DefaultTableModel model;
    private ResultSet resultado;

    public MyDBWorker(JTable table, ResultSet resultado) {
        this.table = table;
        this.resultado = resultado;
    }

    @Override
    protected Void doInBackground() throws Exception {
        ResultSetMetaData metadata = resultado.getMetaData();
        int columnas = metadata.getColumnCount();
        Object[] etiquetas = new Object[columnas];
        for (int i = 0; i < columnas; i++) {
            etiquetas[i] = metadata.getColumnName(i + 1);
        }
        publish(etiquetas);
        while (resultado.next() && !this.isCancelled()) {
            Object fila[] = new Object[columnas];
            for (int i = 0; i < columnas; i++) {
                fila[i] = resultado.getObject(i + 1);
            }
            publish(fila);
        }
        return null;
    }


    @Override
    protected void process(List<Object[]> chunks) {
        int startIndex = 0;
        // first chunk, set up a new model
        if (model == null) {
            model = new DefaultTableModel();
            model.setColumnIdentifiers(chunks.get(0));
            table.setModel(model);
            startIndex = 1;
        }
        for (int i = startIndex; i < chunks.size(); i++) {
            model.addRow(chunks.get(i));
        }
    }

    @Override
    protected void done() {
        // nothing to do, we were cancelled
        if (isCancelled()) return;
        // check for errors thrown in doInBackground
        try {
            get();
            // all was well in the background thread
            // check if there are any results
            if (table.getModel().getRowCount() == 0) {
                // show message
            }
        } catch (ExecutionException e) {
            // we get here if f.i. an SQLException is thrown
            // handle it as appropriate, f.i. inform user/logging system
        } catch (InterruptedException e) {
            // 
        }
    }

}

// use it
SwingWorker worker = new MyDBWorker(table, resultado);
PropertyChangeListener stateListener = new PropertyChangeListener() {

    @Override
    public void propertyChange(PropertyChangeEvent e) {
        if (e.getNewValue() == SwingWorker.StateValue.STARTED) {
            progressBar.setIndeterminate(true);
        }
        if (e.getNewValue() == SwingWorker.StateValue.DONE) {
            progressBar.setIndeterminate(false);
        }

    }

};
worker.addPropertyChangeListener(doneListener);
worker.execute();

编辑

修复了一个过程中的错误:向模型添加行必须始终从批处理的第一个索引开始,处理标头时除外。

【讨论】:

  • 感谢@kleopatra 的提示。我想我应该为要发布的每一行调用 process(fila) 而不是 publish(fila)?
  • @Lowb no - 真正让人深思的一件事是线程的明确分离:一些方法被设计为在后台线程(fi doInBackground,publish)上调用,而其他方法则保证在 EDT 上执行(fi 进程,完成)。切勿将一组方法与另一组方法混用
  • 嗯我不明白@kleopatra,那么什么时候调用 process()?块的内容是什么?我如何决定何时在 UI 中显示行?问题太多,抱歉:(
  • @Lowb 只要您想更新 ui,只需在 doInBackground 中调用 publish。实际更新发生在进程中,无论发布之间发生什么 -> 进程完全在工作人员内部,不受您的控制(而且您不想知道它:-)
  • 好的,我现在明白了,当我调用 publish() 时,程序会做一些事情并调用 process(),这就是为什么对吧?谢谢顺便说一句!!!
猜你喜欢
  • 1970-01-01
  • 2011-12-26
  • 1970-01-01
  • 2013-01-31
  • 1970-01-01
  • 1970-01-01
  • 2012-03-24
  • 2016-02-07
  • 2014-10-10
相关资源
最近更新 更多