【发布时间】:2012-07-20 04:04:14
【问题描述】:
我在使用 netbeans Swing GUI 时遇到了线程问题。这是我第一次真正尝试使用 Java 的文件系统通知程序为备份程序开发 GUI。我有两个文件SyncUI.java 和Sync.java。
几乎我想要发生的事情是您在jTextField1 文本字段中输入一个目录路径,该路径创建一个同步线程,该线程创建一个新的同步对象,然后在该对象上调用processEvents。当该目录中的文件发生更改时,我想将有关更改的文本添加到列表中。
在其当前状态下,UI 不再响应,但是 processEvents 没有在我的列表中添加任何内容。知道问题是什么吗?此外,由于我刚刚开始使用 java,因此欢迎任何建设性的批评。
SyncUI.java:
package sync;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.DefaultListModel;
import javax.swing.JList;
import javax.swing.SwingUtilities;
public class SyncUI extends javax.swing.JFrame {
public SyncUI() {
initComponents();
}
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jButton1 = new javax.swing.JButton();
jTextField1 = new javax.swing.JTextField();
list1 = new java.awt.List();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jButton1.setText("Start");
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton1ActionPerformed(evt);
}
});
jTextField1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jTextField1ActionPerformed(evt);
}
});
list1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
list1ActionPerformed(evt);
}
});
org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(layout.createSequentialGroup()
.addContainerGap()
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(list1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.add(layout.createSequentialGroup()
.add(jTextField1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 329, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(jButton1)
.add(0, 0, Short.MAX_VALUE)))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(layout.createSequentialGroup()
.addContainerGap()
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
.add(jButton1)
.add(jTextField1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(list1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 229, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addContainerGap(25, Short.MAX_VALUE))
);
pack();
}// </editor-fold>
private void jTextField1ActionPerformed(java.awt.event.ActionEvent evt) {
jButton1.doClick();
}
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
//I tried to use invokeLater, this solved the problem of the UI nonresponse issue
SwingUtilities.invokeLater(new Runnable() {
public void run()
{
//Creates a path dir that my Sync constructor needs to start file notification watcher on that directory
Path dir = Paths.get(jTextField1.getText());
try
{
//Creates a new sync object passing it the directory and the list in my GUI
Sync sync = new Sync(dir, list1);
try
{
sync.processEvents();
}
catch (InterruptedException ex)
{
Logger.getLogger(SyncUI.class.getName()).log(Level.SEVERE, null, ex);
}
}
catch (IOException ex)
{
Logger.getLogger(SyncUI.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
private void list1ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
}
public static void main(String args[]) throws IOException
{
java.awt.EventQueue.invokeLater(new Runnable()
{
public void run()
{
SyncUI s = new SyncUI();
s.setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JButton jButton1;
private javax.swing.JTextField jTextField1;
private java.awt.List list1;
// End of variables declaration
}
Sync.java:
package sync;
import static java.nio.file.StandardWatchEventKinds.*;
import java.nio.file.attribute.*;
import java.io.*;
import java.nio.file.*;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.SwingUtilities;
public class Sync
{
private final WatchService ws;
private final Map<WatchKey,Path> keys;
public java.awt.List list;
public Sync(Path dir, java.awt.List list) throws IOException, InterruptedException
{
this.ws = FileSystems.getDefault().newWatchService();
this.keys = new HashMap<WatchKey,Path>();
this.list = list;
recSet(dir);
//this.processEvents();
}
private void register(Path dir) throws IOException
{
WatchKey key = dir.register(ws, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
keys.put(key, dir);
}
private void recSet(Path start) throws IOException
{
Files.walkFileTree(start, new SimpleFileVisitor<Path>()
{
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException
{
if(!Files.isHidden(dir))
{
register(dir);
System.out.println(dir);
}
return FileVisitResult.CONTINUE;
}
});
}
void processEvents() throws IOException, InterruptedException
{
System.out.println("Entered processEvents");
SwingUtilities.invokeLater(new Runnable() {
public void run()
{
System.out.println("Entered run");
list.add("test2");
list.repaint();
while(true)
{
WatchKey key;
try
{
key = ws.take();
}
catch (InterruptedException x)
{
return;
}
Path dir = keys.get(key);
if (dir == null)
{
System.err.println("WatchKey not recognized");
continue;
}
for (WatchEvent<?> event: key.pollEvents())
{
WatchEvent.Kind<?> kind = event.kind();
WatchEvent<Path> ev = (WatchEvent<Path>)event;
Path filename = ev.context();
String name = dir.resolve(filename).toString();
if (kind == OVERFLOW)
continue;
if(kind == ENTRY_CREATE)
{
System.out.print("Entry Created: ");
File f = new File(name);
if(f.isDirectory())
try {
register(dir.resolve(filename));
} catch (IOException ex) {
Logger.getLogger(Sync.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println(name);
list.add(name);
}
else if(kind == ENTRY_DELETE)
{
System.out.print("Entry Deleted: ");
System.out.println(name);
}
else if(kind == ENTRY_MODIFY)
{
File f = new File(name);
if(!f.isDirectory())
{
System.out.print("Entry Modify: ");
System.out.println(name);
}
}
boolean valid = key.reset();
if (!valid)
break;
}
}
}
});
}
}
【问题讨论】:
-
您可以在按钮按下时动态添加列表项吗?如果不是,这与 NIO 无关,您应该发布它。为了尽快获得更好的帮助,请发帖SSCCE。
-
是的,我能够做到 list.add("stuff");在我的 Button Press Action Listener 中,它确实将我的条目附加到列表中。此外,如果我在 processEvents 中的 while(true) 循环之前返回,它将附加到列表中。
-
请注意,代码审查更适合进行建设性的批评,但请注意有关 `jTextField1 = new javax.swing.JTextField();` 1) 给它起一个合理的名称,例如
dirPath或dirPathTextField2) 提供JFileChooser以选择目录。 -
哦,对了。错过了
while(true)位。好的.. 不要阻塞 EDT(事件调度线程)——当这种情况发生时,GUI 将“冻结”。使用SwingWorker处理长时间运行的任务。有关详细信息,请参阅Concurrency in Swing。 -
是的,我知道我需要进行这些更改。 gui 不像它只是我拼凑起来的一个基本示例,试图让核心功能正常工作。
标签: java multithreading swing awt jlist