Как отобразить части текста в jtable

У меня есть приложение, похожее на 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());
            }
        }

    });

Проблема в том, что сортировка столбца файла по-прежнему сортируется по полному пути, а не только по имени файла. Я предполагаю, что мне нужно реализовать какой-то компаратор, но я не знаю, с чего начать.

РЕДАКТИРОВАТЬ: Чтобы быть ясно, я сделал суть, чтобы показать, что я имею в виду.

Я хочу иметь возможность показывать только имя файла (здесь. Файл, там. Файл) в ячейках, а не полный путь. При сортировке файлового столбца также сортируйте по имени файла вместо полного пути. Полный путь должен быть всплывающей подсказкой, когда указатель мыши находится над соответствующей ячейкой файла. При фильтрации таблицы мне бы хотелось, чтобы в поиск также был включен полный путь.

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 ответа

Решение

TableRowSorter класс обеспечивает setComparator(int column, Comparator<?> comparator) метод. Это должно делать именно то, что вам нужно. Обеспечить Comparator что заказы File с getName(), В дополнение к тому, что у вас уже есть, я думаю, что это дает вам то, что вы ищете.

В приведенном ниже примере показано, как отобразить только имя файла с полным путем в качестве всплывающей подсказки. Вы можете включить полный путь в свой фильтр, как показано здесь

Приложение: @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://stackru.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();
            }
        });
    }
}
Другие вопросы по тегам