带有 FileVisitor 的 SwingWorker 不能快速发布处理过的信息; GUI 挂起

SwingWorker with FileVisitor not publishing processed info quickly; GUI hangs

使用 SwingWorkerFileVisitor 不能快速发布处理过的信息; GUI挂起。我宁愿它没有,想帮助解决这个问题

这里简要介绍了我如何使用 SwingWorkerFileVisitor 界面来搜索 Windows 目录节点以查找符合用户指定条件的文件。 :

  public class Main 
  {
    public static void main(String args[]) 
    {
      EventQueue.invokeLater( new Runnable() {
          @Override public void run() {
            gui = new GUI();
          }});
    }
  }
  //==============================================================
  public class GUI extends JFrame
  {
    public     GUI()
    {
      init();
      createAndShowGUI();
    }

     private void init()
     {
       dftTableModel = new DefaultTableModel(0 , 4);
         tblOutput     = new JTable(dftTableModel);
         tblOutput.setAutoResizeMode(AUTO_RESIZE_OFF);
         scrTblOutput     = new JScrollPane(tblOutput);
       dftTableModel.setColumnIdentifiers(new Object[]{"Date", "Size", "Filename", "Path"});

编辑如果我只包含这两行,问题可能会立即得到解决

       tca = new tablecolumnadjuster.TableColumnAdjuster(tblOutput);
       tca.setDynamicAdjustment(true);

     }

      private static void btnSearchActionPerformed(ActionEvent evt) 
      {
        TASK task = new TASK();
        task.execute();      
      }
    }
  }
  //==============================================================

  public class TASK extends SwingWorker<Void,String>
  {

    private class rowRec{
      String date;
      int size;
      String filename;
      String pathname;

      private rowRec(String d, int s, String f, String p) 
      {
        date = d; 
        size = s; 
        filename = f; 
        pathname = p;
      }
    }

    FV fv;

    TASK() {        fv = new FV();        }

    //-------------- inner class   

      class FV implements FileVisitor<Path>
      {
        // When walk begins, internal FileVisitor code makes this routine
        // loop until no more files are found OR disposition = TERMINATE.

        public FileVisitResult visitFile(Path f, BasicFileAttributes a) throws IOException 
        {
          if(f.getFileName().toString().toLowerCase().matches(fPatt.toLowerCase().trim()))
          {

             publish(s); 

             if(++k > parseInt(GUI.txtMaxMatches.getText()))

                disposition = TERMINATE;
                publish("Stopped at max. records specified");
          }
          return disposition;
        }
      }
    //----------------

    private  void report(String s)
    {
      rowData = new rowRec(date, isize, filename, path);
      dftTableModel.addRow(new Object[]{rowData.date, rowData.size, rowData.filename, rowData.pathname});
    }

    @Override
    protected void process(List<String> chunks)
    {
      chunks.stream().
        forEach
        (
           (chunk) -> 
           {
             report(chunk);
           }
      );
      kc += chunks.size();
      System.out.println(kc); // *********************************
    }

    @Override
    public Void doInBackground() throws Exception 
    {
        disposition = FileVisitResult.CONTINUE;
        Files.walkFileTree(GUI.p ,fv);
    }
  }

GUI 启动一个新的 SwingWorker 实例,其工作是显示(在 JTable 中)它启动的 TASK 实例找到的文件信息. TASK 实例化 FileVisitorwalkFileTree 开始。在 visitFile 方法中找到的每个匹配文件都被 published 为 SwingWorkerprocess.

大部分时间都很好用,但如果有大量匹配文件,GUI 会在几秒钟内没有反应;同时,发生了大量读取和显示,UI 每读取几千个文件就会更新一次。

尽管在后台使用 SwingWorker 填充 JTable,显然(我猜)太多匹配文件信息来得太快无法跟上。

这就是我这么说的原因:

尽管 visitFile 有一个向 TERMINATE 发出信号的计数器,但 process 显然远远落后于向 JTable 添加记录。它里面的 println 表明,随着时间的推移,通过的 chunks 的数量变化很大,这取决于 FileVisitor 找到匹配项的比率:

41
81
138
250
604
1146
...
1417
1497
1590
1670
1672
1676
1680
1682
1692
1730
1788
1794
1797
1801
1807
1820
1826
1829
1847
1933
2168
10001

visitFile终止后,process不得不向JTable发送(10001-2168)条记录,即7833条记录,耗时较长,GUI 大部分时间都没有反应。事实上,如果最大。匹配项是(荒谬的)10,000,程序挂起很多分钟,但是 JTable.

中有 10,000 条记录

我不知道如何处理无响应。我希望能够点击“停止”按钮让程序停止。或者能够X(关闭)window。没办法。

我没有正确使用 SwingWorker 吗? 我不能让树行走基于 SwingWorker 因为没有可用的循环对我来说(它是内部的)。

P.S。虽然显然挂起,但 javaw 占用了 CPU 的 25% 的时间,并以每秒约 16K 的速度增加其内存分配,因为 process 缓慢进行,直到它最终发布最后一个块。

编辑

我可能找到了帮助 here

但是,哎呀,关闭??

我已经突出显示了我的问题。

我不知道你的问题的解决方案,但我知道这不应该在 SwingWorker 或其内部完成 类:

GUI.txtMaxMatches.getText())

您应该在 EDT 上获取此信息并通过其构造函数将其传递到您的 SwingWorker。

一行代码解决了响应问题。

// tca.setDynamicAdjustment(true);

参考原始问题中的编辑。