Reputation: 4283
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 publish
ed 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.
EDIT
I may have found help here.
But, gee, close??
I've highlighted my questions.
Upvotes: 2
Views: 67
Reputation: 4283
The responsiveness problem is solved in ONE LINE OF CODE.
// tca.setDynamicAdjustment(true);
Refer to edit in original question.
Upvotes: 0
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