如何在jtable中显示部分文本

时间:2014-05-03 20:18:54

标签: java swing jtable renderer rowfilter

我有一个类似于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();
            }
        });
    }
}

2 个答案:

答案 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();
            }
        });
    }
}