我正在尝试使用JTables
编写自定义文件导航器来导航文件系统。我遇到的问题是,只要您按住按钮,鼠标事件就一直持续下去,因此,如果有人尝试通过连续双击“上一级”字段来上多个级别(因为它不t移动),除非它们停止长时间单击,否则它只会返回到一个目录。因此,我意识到导致此问题的原因是MouseEvent
仍处于活动状态。
我很确定我可以通过执行if(e.getClickCount() % 2 == 0)
来完成我想做的事情,但这感觉像是不正确的解决方法。是否有更好/更正确的方法来执行此操作,例如在初始双击后重置MouseEvent
?甚至可以手动重置MouseEvent
吗?如果是这样,怎么办?
编辑:恢复为多合一代码,以便更轻松地复制/粘贴:
package main;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.filechooser.FileSystemView;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumnModel;
public class Main {
public static void main(String[] args) {
new CreateFrame();
}
}
class CreateFrame extends JFrame {
public CreateFrame() {
setPreferredSize(new Dimension(800, 600));
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
setContentPane(new LocalNavigator());
pack();
setVisible(true);
}
class LocalTable extends JTable {
private DefaultTableModel dtm;
private File path;
private FileSystemView fsv = FileSystemView.getFileSystemView();
public LocalTable() {
String[] header = new String[] { "Icon", "File/Folder Name", "File Type" };
dtm = new DefaultTableModel() {
@Override
public boolean isCellEditable(int row, int column) {
return false;
}
@Override
public Class<?> getColumnClass(int column) {
if (getRowCount() > 0) {
return getValueAt(0, column).getClass();
}
return super.getColumnClass(column);
}
};
dtm.setColumnIdentifiers(header);
setAutoCreateRowSorter(true);
setRowHeight(25);
setModel(dtm);
addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
JTable table = (JTable) e.getSource();
Point p = e.getPoint();
int row = table.rowAtPoint(p);
String type = getValueAt(row, 2).toString().toLowerCase();
if (type.contains("root") || type.contains("folder")) {
File file = new File((path != null ? path + "/" + getValueAt(row, 1) : getValueAt(row, 1).toString()));
if (file != null)
repopulateFileFolderList(file);
} else if (getValueAt(row, 1).toString().toLowerCase().contains("up one")
&& getValueAt(row, 2).toString().equals("")) {
File file = path.getParentFile();
if (file != null)
repopulateFileFolderList(file);
else
getTableRoot();
} else {
System.out.println("Not a directory!");
}
}
}
});
}
public void getTableRoot() {
path = null;
while (dtm.getRowCount() > 0) {
dtm.removeRow(0);
}
File[] roots = File.listRoots();
for (File root : roots) {
dtm.addRow(new Object[] { fsv.getSystemIcon(root), root.getAbsoluteFile(), "Root Directory" });
}
}
private void repopulateFileFolderList(File folder) {
path = folder;
while (dtm.getRowCount() > 0) {
dtm.removeRow(0);
}
dtm.addRow(new Object[] { fsv.getSystemIcon(folder), "Up One Level", "" });
File[] files = folder.listFiles();
for (File file : files) {
dtm.addRow(new Object[] { fsv.getSystemIcon(file), file.getName(),
(file.isDirectory() ? "Folder" : file.isFile() ? "File" : "Unknown") });
}
}
}
class LocalNavigator extends JPanel {
private LocalTable localTable;
public LocalNavigator() {
setLayout(new BorderLayout());
localTable = new LocalTable();
localTable.getTableRoot();
JScrollPane lTree = new JScrollPane(localTable);
add(lTree, "Center");
TableColumnModel columns = localTable.getColumnModel();
for (int c = 0;c < columns.getColumnCount();c++) {
if (c == 0)
columns.getColumn(c).setMaxWidth(25);
else
columns.getColumn(c).setPreferredWidth(50);
}
}
}
}
最佳答案
在您的要求中,您解释说要允许快速延迟双击。
但是您使用的e.getClickCount()==2
并不是解决方案,因为它受操作系统配置的限制。
您可以通过查看Toolkit.getDefaultToolkit().getDesktopProperty("awt.multiClickInterval")
的结果来获得它
绕过此问题的简单有效方法是,您可以自己处理鼠标侦听器中两次单击之间的延迟。
您可以使用计时器,在该计时器中,您可以选择两次点击之间的最大间隔,并自行处理计数。
解决方案非常简单。因此,由于您的代码是可测试的,因此我直接对其进行了修改并进行了测试。这个对我有用。
总结一下我的修改,我添加了一个布尔实例来计算当前点击次数
并在两个地方分开了双击检测(技术)和双击处理(逻辑)。更具可读性。
我选择了0.5秒作为两次单击之间授权的最大延迟。
您可以选择另一个值,但是如果该值太重要(例如一秒钟或更长时间),则可能会导致意外的双击。
class CreateFrame extends JFrame {
...
private boolean isAlreadyOneClick;
...
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (isAlreadyOneClick) {
handleDoubleClick(e);
isAlreadyOneClick = false;
}
else {
isAlreadyOneClick = true;
Timer t = new Timer("doubleclickTimer", false);
t.schedule(new TimerTask() {
@Override
public void run() {
isAlreadyOneClick = false;
}
}, 500);
}
}
private void handleDoubleClick(MouseEvent e) {
JTable table = (JTable) e.getSource();
Point p = e.getPoint();
int row = table.rowAtPoint(p);
String type = getValueAt(row, 2).toString().toLowerCase();
if (type.contains("root") || type.contains("folder")) {
File file = new File((path != null ? path + "/" + getValueAt(row, 1) : getValueAt(row, 1).toString()));
if (file != null)
repopulateFileFolderList(file);
}
else if (getValueAt(row, 1).toString().toLowerCase().contains("up one")
&& getValueAt(row, 2).toString().equals("")) {
File file = path.getParentFile();
if (file != null)
repopulateFileFolderList(file);
else getTableRoot();
}
else {
System.out.println("Not a directory!");
}
}
}