DSlomer64
DSlomer64

Reputation: 4283

SwingWorker with FileVisitor not publishing processed info quickly; GUI hangs

Using SwingWorker with FileVisitor not publishing processed info quickly; GUI hangs. I'd prefer it didn't and would like help with that problem.

Here's a brief outline of how I use SwingWorker with FileVisitor interface to search a Windows directory node for files matching user-specified criteria. :

  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"});

EDIT HAD I ONLY INCLUDED THESE TWO LINES, PROBLEM MAY HAVE BEEN SOLVED IMMEDIATELY

       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 starts a new instance of SwingWorker, whose job is to display (in a JTable) file info found by the instance of TASK that it starts. TASK instantiates FileVisitor, and walkFileTree begins. Every matching file found in the visitFile method is published for SwingWorker to process.

It works great most of the time, but if there is a ton of matching files, the GUI becomes unresponsive for several seconds; meanwhile, plenty of reading and displaying has occurred, and the UI is updated every few thousand file reads.

Despite using SwingWorker to fill the JTable in the background, apparently (I'm guessing) too much matching files info comes too fast to keep up.

Here's why I say that:

Even though visitFile has a counter which signals to TERMINATE, process apparently is far behind in adding records to the JTable. The println inside it shows that, as time passes, the number of chunks passed varies considerably, depending on rate of FileVisitor finding matches:

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

After visitFile terminated, process had to send (10001-2168), or 7833 records to the JTable, and it took a long time, and the GUI was unresponsive much of the time. In fact, if the max. matches is (the ridiculous) 10,000, the program hangs for many MINUTES, but 10,000 records are in the JTable.

I don't know what to do about the unresponsiveness. I'd like to be able to hit the STOP button and have the program stop. Or be able to X (close) the window. No way.

Am I not using SwingWorker correctly? I can't make the tree walk be based on SwingWorker since there's no loop that I have available to me (it's internal).

P.S. While apparently hung, javaw is taking a solid 25% of CPU time and incrementing its memory allocation by about 16K per second, as process plods along, until it finally publishes the last chunk.

enter image description here

EDIT

I may have found help here.

But, gee, close??

I've highlighted my questions.

Upvotes: 2

Views: 67

Answers (2)

DSlomer64
DSlomer64

Reputation: 4283

The responsiveness problem is solved in ONE LINE OF CODE.

// tca.setDynamicAdjustment(true);

Refer to edit in original question.

Upvotes: 0

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285405

I don't know the solution to your problem, but I do know that this should not be done within the SwingWorker or its inner classes:

GUI.txtMaxMatches.getText())

You should get this information on the EDT and pass it into your SwingWorker via its constructor.

Upvotes: 2

Related Questions