我有一个类似于TableFilterDemo的应用程序,它生成一个带有与此
类似的字段的数据库{new File("/path/with/names/included/here.file"), "foo", "bar", new Integer(5), new Double(0.7)},
路径可能很长,所以我实现了一个单元格渲染器,它只显示文件名,但将完整路径设置为工具提示。
table.getColumnModel().getColumn(0).setCellRenderer(new DefaultTableCellRenderer(){
@Override
protected void setValue(Object value) {
Object result = value;
if ((value != null) && (value instanceof File)) {
File file = (File) value;
result = file.getName();
super.setValue(result);
super.setToolTipText(file.toString());
}
}
});
现在的问题是,对文件列进行排序仍按完整路径排序,而不仅仅是文件名。我猜我需要实现某种比较器,但我不知道从哪里开始。
编辑:要清楚,我已经制作了一个gist来表明我的意思。
我希望能够在单元格中显示文件名(here.file,there.file)而不是完整路径。排序文件列时,还要按文件名而不是完整路径排序。当鼠标指针位于相应的文件单元格上时,完整路径应为工具提示。过滤表格时,我也想在搜索中包含完整路径。
EDIT3:带解决方案的SSCCE
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableRowSorter;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.io.File;
import javax.swing.table.DefaultTableCellRenderer;
public class TableFilterDemo extends JPanel {
private JTable table;
private JTextField filterText;
private TableRowSorter<MyTableModel> sorter;
public TableFilterDemo() {
setLayout(new BorderLayout());
// Comparator for the file column, sorts by name instead of full path
Comparator<File> fileComparator = new Comparator<File>() {
@Override
public int compare(File file1, File file2) {
return file1.getName().compareTo(file2.getName());
}
};
// Create a table with a sorter.
MyTableModel model = new MyTableModel();
sorter = new TableRowSorter<MyTableModel>(model);
sorter.setComparator(0, fileComparator);
table = new JTable(model);
table.setRowSorter(sorter);
table.setPreferredScrollableViewportSize(new Dimension(500, 70));
table.setFillsViewportHeight(true);
// For the purposes of this example, better to have a single
// selection.
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
table.getColumnModel().getColumn(0).setCellRenderer(new DefaultTableCellRenderer() {
@Override
protected void setValue(Object value) {
Object result = value;
if ((value != null) && (value instanceof File)) {
File file = (File) value;
result = file.getName();
super.setValue(result);
super.setToolTipText(file.toString());
}
}
});
// Add the scroll pane to this panel.
add(
new JScrollPane(table), BorderLayout.CENTER);
// Create a separate form for filterText and statusText
filterText = new JTextField();
// Whenever filterText changes, invoke newFilter.
filterText.getDocument().addDocumentListener(new DocumentListener() {
public void changedUpdate(DocumentEvent e) {
newFilter();
}
public void insertUpdate(DocumentEvent e) {
newFilter();
}
public void removeUpdate(DocumentEvent e) {
newFilter();
}
});
add(filterText, BorderLayout.SOUTH);
}
/**
* Update the row filter regular expression from the expression in the text
* box.
*/
private void newFilter() {
RowFilter<MyTableModel, Object> rf = null;
// If current expression doesn't parse, don't update.
try {
rf = RowFilter.regexFilter("(?i)" + filterText.getText());
} catch (java.util.regex.PatternSyntaxException e) {
return;
}
sorter.setRowFilter(rf);
}
class MyTableModel extends AbstractTableModel {
private String[] columnNames = {"File", "a", "b", "c", "d"};
private Object[][] data = {
{new File("/long/path/with/names/included/2012-10-11-001.file"),
"foo", "bar", new Integer(5), new Double(0.7)},
{new File("/path/full/of/text/2012-10-11-002.file"),
"baz", "bah", new Integer(2), new Double(1.7)},
{new File("/a/long/path/full/of/other/text/2012-10-11-003.file"),
"baz", "bah", new Integer(2), new Double(1.7)},};
public int getColumnCount() {
return columnNames.length;
}
public int getRowCount() {
return data.length;
}
public String getColumnName(int col) {
return columnNames[col];
}
public Object getValueAt(int row, int col) {
return data[row][col];
}
public Class getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
/*
* Don't need to implement this method unless your table's data can
* change.
*/
public void setValueAt(Object value, int row, int col) {
data[row][col] = value;
fireTableCellUpdated(row, col);
}
}
/**
* Create the GUI and show it. For thread safety, this method should be
* invoked from the event-dispatching thread.
*/
private static void createAndShowGUI() {
// Create and set up the window.
JFrame frame = new JFrame("TableFilterDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Create and set up the content pane.
TableFilterDemo newContentPane = new TableFilterDemo();
newContentPane.setOpaque(true); // content panes must be opaque
frame.setContentPane(newContentPane);
// Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
// Schedule a job for the event-dispatching thread:
// creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
答案 0 :(得分:1)
TableRowSorter
类提供setComparator(int column, Comparator<?> comparator)
方法。这应该完全符合你的需要。提供按Comparator
订购File
的{{1}}。添加到您已有的内容中,我认为它可以为您提供所需内容。
答案 1 :(得分:1)
下面的示例显示了如何仅将文件名显示为tool tip的完整路径。您可以在过滤器中合并完整路径,如图here
所示附录:@Paul Hicks问道,“你能指出一些新的和重要的东西吗?”
基本的改变是让模型而不是渲染器返回您想要显示的值。然后让视图在模型中查询渲染工具提示所需的详细信息。
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableRowSorter;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.io.File;
/** @see https://stackoverflow.com/a/23450990/230513 */
public class TableFilterDemo extends JPanel {
private JTable table;
private JTextField filterText;
private TableRowSorter<MyTableModel> sorter;
public TableFilterDemo() {
setLayout(new BorderLayout());
// Create a table with a sorter.
MyTableModel model = new MyTableModel();
sorter = new TableRowSorter<MyTableModel>(model);
table = new JTable(model) {
@Override
public String getToolTipText(MouseEvent e) {
Point p = e.getPoint();
int row = convertRowIndexToModel(rowAtPoint(p));
MyTableModel model = (MyTableModel) table.getModel();
return model.getPath(row);
}
};
table.setRowSorter(sorter);
table.setPreferredScrollableViewportSize(new Dimension(500, 200));
table.setFillsViewportHeight(true);
// For the purposes of this example, better to have a single
// selection.
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
// Add the scroll pane to this panel.
add(
new JScrollPane(table), BorderLayout.CENTER);
// Create a separate form for filterText and statusText
filterText = new JTextField();
// Whenever filterText changes, invoke newFilter.
filterText.getDocument().addDocumentListener(new DocumentListener() {
public void changedUpdate(DocumentEvent e) {
newFilter();
}
public void insertUpdate(DocumentEvent e) {
newFilter();
}
public void removeUpdate(DocumentEvent e) {
newFilter();
}
});
add(filterText, BorderLayout.SOUTH);
}
/**
* Update the row filter regular expression from the expression in the text
* box.
*/
private void newFilter() {
RowFilter<MyTableModel, Object> rf = null;
// If current expression doesn't parse, don't update.
try {
rf = RowFilter.regexFilter("(?i)" + filterText.getText());
} catch (java.util.regex.PatternSyntaxException e) {
return;
}
sorter.setRowFilter(rf);
}
class MyTableModel extends AbstractTableModel {
String path = System.getProperty("user.dir");
File[] data = new File(path).listFiles();
private String getPath(int row) {
return data[row].getPath();
}
@Override
public int getColumnCount() {
return 1;
}
@Override
public int getRowCount() {
return data.length;
}
@Override
public String getColumnName(int col) {
return "path";
}
@Override
public Object getValueAt(int row, int col) {
return data[row].getName();
}
@Override
public Class getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
}
/**
* Create the GUI and show it. For thread safety, this method should be
* invoked from the event-dispatching thread.
*/
private static void createAndShowGUI() {
// Create and set up the window.
JFrame frame = new JFrame("TableFilterDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Create and set up the content pane.
TableFilterDemo newContentPane = new TableFilterDemo();
newContentPane.setOpaque(true); // content panes must be opaque
frame.setContentPane(newContentPane);
// Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
// Schedule a job for the event-dispatching thread:
// creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}