问题描述
我已经在Java GUI应用程序中编写了一个递归搜索方法,以在驱动器中查找文件.
用户界面具有响应性,
搜索成功完成,但JList
没有填充,而控制台成功打印了文件名,在JList
中添加了3次单击搜索按钮的文件后,每个文件都重复了名称
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();
}
推荐答案
基本问题是,您实际上并没有修改ListModel
.
The basic problem is, you're not actually modifying the ListModel
in anyway.
Swing是一个单线程环境,您已经使用Thread
来确保执行搜索时不会阻塞UI,这很好,但是Swing也不是线程安全的,这意味着您不应该t从事件调度线程的上下文外部更新UI,因此Thread
是错误的.
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.
尽管您可以"使用Thread
,SwingWorker
可以为该问题提供更好(通常更简单)的解决方案(更不用说可重用的问题了)
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();
有关更多详细信息,请参见 Worker Threads和SwingWorker
See Worker Threads and SwingWorker for more details
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;
}
}
}
这篇关于单击搜索按钮后,JList不会填充的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!