JList does not populates after search button clicked

168 views Asked by At

I've written a recursive search method in java GUI application to find a file in a drive.
UI is responsive,
Search happened successfully but JList does not populate,whereas console prints file names successfully, after 3 clicks on search button files are added in JList but with repeated names of each file

     //nullpointerexception
      java.util.concurrent.ExecutionException:  
    java.lang.NullPointerException
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.util.concurrent.FutureTask.get(FutureTask.java:188)
at javax.swing.SwingWorker.get(SwingWorker.java:602)
at searchapp.searchScreen$4.propertyChange(searchScreen.java:90)
at java.beans.PropertyChangeSupport.fire(PropertyChangeSupport.java:335)
atjava.beans.PropertyChangeSupport.firePropertyChange(PropertyChangeSupport.java:327)
at javax.swing.SwingWorker$SwingWorkerPropertyChangeSupport.firePropertyChange(SwingWorker.java:854)
at javax.swing.SwingWorker$SwingWorkerPropertyChangeSupport$1.run(SwingWorker.java:859)
at javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.run(SwingWorker.java:832)
at sun.swing.AccumulativeRunnable.run(AccumulativeRunnable.java:112)
at javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.actionPerformed(SwingWorker.java:842)
at javax.swing.Timer.fireActionPerformed(Timer.java:312)
at javax.swing.Timer$DoPostEvent.run(Timer.java:244)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:312)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:738)
at java.awt.EventQueue.access$300(EventQueue.java:103)
at java.awt.EventQueue$3.run(EventQueue.java:699)
at java.awt.EventQueue$3.run(EventQueue.java:697)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:708)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)
Caused by: java.lang.NullPointerException
at searchapp.searchWorker.search(searchWorker.java:65)
at searchapp.searchWorker.search(searchWorker.java:66)
at searchapp.searchWorker.search(searchWorker.java:66)
at searchapp.searchWorker.doInBackground(searchWorker.java:51)
at searchapp.searchWorker.doInBackground(searchWorker.java:21)
at javax.swing.SwingWorker$1.call(SwingWorker.java:296)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at javax.swing.SwingWorker.run(SwingWorker.java:335)
at   java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at            java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
java.util.concurrent.ExecutionException: java.lang.NullPointerException
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.util.concurrent.FutureTask.get(FutureTask.java:188)
at javax.swing.SwingWorker.get(SwingWorker.java:602)
at searchapp.searchScreen$4.propertyChange(searchScreen.java:90)
at java.beans.PropertyChangeSupport.fire(PropertyChangeSupport.java:335)
at java.beans.PropertyChangeSupport.firePropertyChange(PropertyChangeSupport.java:327)
at javax.swing.SwingWorker$SwingWorkerPropertyChangeSupport.firePropertyChange(SwingWorker.java:854)
at javax.swing.SwingWorker$SwingWorkerPropertyChangeSupport$1.run(SwingWorker.java:859)
at javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.run(SwingWorker.java:832)
at sun.swing.AccumulativeRunnable.run(AccumulativeRunnable.java:112)
at javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.actionPerformed(SwingWorker.java:842)
at javax.swing.Timer.fireActionPerformed(Timer.java:312)
at javax.swing.Timer$DoPostEvent.run(Timer.java:244)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:312)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:738)
at java.awt.EventQueue.access$300(EventQueue.java:103)
at java.awt.EventQueue$3.run(EventQueue.java:699)
at java.awt.EventQueue$3.run(EventQueue.java:697)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:708)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)
Caused by: java.lang.NullPointerException
at searchapp.searchWorker.search(searchWorker.java:65)
at searchapp.searchWorker.search(searchWorker.java:66)
at searchapp.searchWorker.search(searchWorker.java:66)
at searchapp.searchWorker.doInBackground(searchWorker.java:51)
at searchapp.searchWorker.doInBackground(searchWorker.java:21)
at javax.swing.SwingWorker$1.call(SwingWorker.java:296)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at javax.swing.SwingWorker.run(SwingWorker.java:335)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)


     //New Code

public class searchWorker extends SwingWorker<List<File>, File> {

    protected static final FileFilter DIRRECTORY_FILE_FILTER = new FileFilter() {

        @Override
        public boolean accept(File pathname) {
            return pathname.isDirectory();
        }
    };
    private DefaultListModel model;
    private File path;
    private FileFilter filefilter;

    public searchWorker(File path, FileFilter filter, DefaultListModel model) {
        this.model = model;
        this.path = path;
        this.filefilter = filter;
    }

    @Override
    protected void process(List<File> chunks) {
        for (File file : chunks) {
            model.addElement(file);
        }
    }

    @Override
    protected List<File> doInBackground() throws Exception {
        return new ArrayList<>(search(path));
    }

    public List<File> search(File path) {
        List<File> files = new ArrayList<>(25);
        if (path.exists()) {
            File[] list = path.listFiles(filefilter);
            if (list != null && list.length > 0) {
                files.addAll(Arrays.asList(list));
                publish(list);

            }
            File[] dirs = path.listFiles(DIRRECTORY_FILE_FILTER);
            for (File dir : dirs) {
                files.addAll(search(dir));

            }
        }
        return files;
    }

}

private void searchBtnActionPerformed(java.awt.event.ActionEvent evt) {
    searchWorker worker = new searchWorker(new File("c:\\"), new FileFilter() {

        @Override
        public boolean accept(File pathname) {
            return pathname.getName().endsWith(".txt") && pathname.getName().startsWith("abc");
        }
    }, lm);
    worker.execute();
}

 //old code
DefaultListModel lm = new DefaultListModel();

public void search(String path) {

    File root = new File(path);
    File[] list = root.listFiles();
    if (list == null) {
        return;
    }
    for (File f : list) {
        if (f.isDirectory()) {
            if (list == null) {
                return;
            }
            search(f.getAbsolutePath());

        } else {
            if (f.getName().endsWith(".txt") && f.getName().startsWith("abc")) {
                lm.addElement(f.getName());

                System.out.println(f.getName());

                found = true;
            }
        }

    }


private void formWindowOpened(java.awt.event.WindowEvent evt) {

    jList1.setModel(lm);
}

private void searchBtnActionPerformed(java.awt.event.ActionEvent evt) {
    //just added this code in my program to resolve unresponsive UI
    Thread t = new Thread(new Runnable() {

        @Override
        public void run() {
            search("c:\\");
        }
    });
    t.start();

}
2

There are 2 answers

13
MadProgrammer On

The basic problem is, you're not actually modifying the ListModel in anyway.

Swing is a single threaded environment, you've used a Thread to ensure that the UI is not blocked while the search is carried out, which is good, but Swing is also not thread safe, meaning that you shouldn't update the UI from outside of the context of the Event Dispatching Thread, so the Thread is bad.

While you "could" use a Thread, a SwingWorker would present a better (and generally simpler) solution to the problem (not to mention a more reusable one)

public static class SearchWorker extends SwingWorker<List<File>, File> {

    protected static final FileFilter DIRECTORY_FILE_FILTER = new FileFilter() {
        @Override
        public boolean accept(File pathname) {
            return pathname.isDirectory();
        }
    };

    private DefaultListModel model;
    private File path;
    private FileFilter fileFilter;

    public SearchWorker(File path, FileFilter filter, DefaultListModel model) {
        this.model = model;
        this.path = path;
        this.fileFilter = filter;
    }

    @Override
    protected void process(List<File> chunks) {
        for (File file : chunks) {
            model.addElement(file);
        }
    }

    @Override
    protected List<File> doInBackground() throws Exception {
        return new ArrayList<>(search(path));
    }

    public List<File> search(File path) {

        List<File> files = new ArrayList<>(25);
        if (path.exists() && path.isDirectory()) {
            File[] list = path.listFiles(fileFilter);
            if (list != null && list.length > 0) {
                files.addAll(Arrays.asList(list));
                publish(list);
            }

            File[] dirs = path.listFiles(DIRECTORY_FILE_FILTER);
            if (dirs != null) {
                for (File dir : dirs) {
                    files.addAll(search(dir));
                }
            }
        }

        return files;
    }

}

Then you would simply start it using something like...

SearchWorker worker = new SearchWorker(new File("c:\\"), new FileFilter() {

    @Override
    public boolean accept(File pathname) {
        return pathname.getName().endsWith(".txt") && pathname.getName().startsWith("abc");
    }
}, lm);
worker.execute();

See Worker Threads and SwingWorker for more details

Runnable example...

Scanning

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            DefaultListModel model = new DefaultListModel();
            JList list = new JList(model);
            setLayout(new BorderLayout());
            add(new JScrollPane(list));

            JLabel label = new JLabel("...");
            add(label, BorderLayout.SOUTH);

            SearchWorker worker = new SearchWorker(new File("c:\\"), new FileFilter() {
                @Override
                public boolean accept(File pathname) {
                    return pathname.getName().endsWith(".png");
                }
            }, model);
            worker.addPropertyChangeListener(new PropertyChangeListener() {
                @Override
                public void propertyChange(PropertyChangeEvent evt) {
                    SearchWorker worker = (SearchWorker) evt.getSource();
                    if ("state".equals(evt.getPropertyName())) {
                        if (worker.isDone()) {
                            label.setText("Finished");
                            try {
                                List<File> files = worker.get();
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    } else if ("path".equals(evt.getPropertyName())) {
                        File path = (File) evt.getNewValue();
                        label.setText(path.toString());
                    }
                }
            });
            worker.execute();
        }

    }

    public static class SearchWorker extends SwingWorker<List<File>, File> {

        protected static final FileFilter DIRECTORY_FILE_FILTER = new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                return pathname.isDirectory();
            }
        };

        private DefaultListModel model;
        private File path;
        private FileFilter fileFilter;

        public SearchWorker(File path, FileFilter filter, DefaultListModel model) {
            this.model = model;
            this.path = path;
            this.fileFilter = filter;
        }

        @Override
        protected void process(List<File> chunks) {
            for (File file : chunks) {
                model.addElement(file);
            }
        }

        @Override
        protected List<File> doInBackground() throws Exception {
            return new ArrayList<>(search(path));
        }

        public List<File> search(File path) {
            firePropertyChange("path", null, path);
            List<File> files = new ArrayList<>(25);
            if (path.exists() && path.isDirectory()) {
                File[] list = path.listFiles(fileFilter);
                if (list != null && list.length > 0) {
                    files.addAll(Arrays.asList(list));
                    publish(list);
                }

                File[] dirs = path.listFiles(DIRECTORY_FILE_FILTER);
                if (dirs != null) {
                    for (File dir : dirs) {
                        files.addAll(search(dir));
                    }
                }
            }

            return files;
        }

    }

}
0
Madhan On

Check the following changes.

  public void search(String path) {
        //DefaultListModel lm = new DefaultListModel();
        //If you are not using the model for other purposes you can declare it here itself

        //to clear the previous values if any [this is why repetitive values]
        lm.clear();
        File root = new File(path);
        File[] list = root.listFiles();
        if (list == null) {
            return;
        }
        for (File f : list) {
            if (f.isDirectory()) {
//                Unnecessary test for null
//                if (list == null) {
//                    return;
//                }
                search(f.getAbsolutePath());

            } else {
                if (f.getName().endsWith(".txt") && f.getName().startsWith("abc")) {
                    lm.addElement(f.getName());

                    System.out.println(f.getName());

                     found = true;
                }
            }
        }
        jList1.setModel(lm);
    }