Сортировка JTable только программно

У меня есть JTable, который можно сортировать (сделал его сортируемым, вызвав setAutoCreateRowSorter(true) при инициализации). Я сортирую эту таблицу программно и хочу отключить обработку событий по умолчанию в заголовке таблицы, чтобы таблицу можно было сортировать программно только. Как этого достичь?

Рабочий фрагмент кода будет таким:

public class SortTable extends JDialog {

    private JTable table;

    DefaultRowSorter<TableModel, String> sorter;

    public SortTable() {
        JScrollPane scrollPane = new JScrollPane();
        setBounds(0, 0, 300, 200);
        getContentPane().setLayout(new BorderLayout());
        getContentPane().add(scrollPane, BorderLayout.CENTER);

        //-------most important stuff-------------------
        table = new JTable();
        table.setAutoCreateRowSorter(true); //enabling sorting
        table.setModel(createModel());
        sorter = (DefaultRowSorter<TableModel, String>)table.getRowSorter(); //store sorter to sort programatically later on
        //-----------------------------------------------

        scrollPane.setViewportView(table);
        JPanel buttonPane = new JPanel();
        buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
        getContentPane().add(buttonPane, BorderLayout.SOUTH);
        buttonPane.add(new JButton(getSortAction()));
    }

    private AbstractAction getSortAction() {
        return new AbstractAction("Sort") {

            @Override
            public void actionPerformed(ActionEvent e) {
                sorter.setSortKeys(Arrays.asList(new SortKey(0,SortOrder.ASCENDING)));
                sorter.sort(); //sorting programatically

            }
        };
    }

    private DefaultTableModel createModel() {
        return new DefaultTableModel(
            new Object[][] {
                {"1", "3"},
                {"5", "2"},
                {"4", null},
            },
            new String[] {
                "A", "B"
            }
        );
    }
}

Этот пример представляет собой JDialog, содержащий JTable с кнопкой Sort. Нажатие этой кнопки приведет к сортировке столбца A по возрастанию. Однако кнопка — не единственный способ сортировки таблицы — мы можем просто щелкнуть заголовок таблицы, чтобы изменить сортировку. Мой вопрос в том, как сделать кнопку единственным способом сортировки таблицы. Также было бы неплохо узнать, как избавиться от стрелки, которая появляется при изменении сортировки.


person macias    schedule 14.11.2013    source источник
comment
похожие вопросы задавались в этом и прошлом месяце несколько раз, ищите bz нажмите на тег rowsorter или tablerowsorter   -  person mKorbel    schedule 14.11.2013
comment
@mKorbel черт возьми, я должен время от времени читать документацию по API ;-)   -  person kleopatra    schedule 14.11.2013


Ответы (1)


Читая сообщения на похожие вопросы (например, предложенные @mKorbel) и экспериментируя, мне удалось найти решение. Ответ на главный вопрос будет таким: используйте метод setSortable(int index, boolean sortable) DefaultRowSorter. Кажется очевидным, но интересно то, что этот метод отключает сортировку столбца при использовании toggleSortOrder(int index) в RowSorter, но игнорируется при использовании метода sort() в DefaultRowSorter. Это какое-то несоответствие? Во всяком случае, это оставляет дверь открытой для трюка. Теперь я могу сделать:

        for (int i=0 ; i<table.getColumnCount() ; i++) {
            sorter.setSortable(i, false);
        }

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

        UIManager.put("Table.ascendingSortIcon", new EmptyIcon());
        UIManager.put("Table.descendingSortIcon", new EmptyIcon());

Лучше всего украсить средство визуализации по умолчанию для TableHeader:

        final TableCellRenderer defaultRenderer = table.getTableHeader().getDefaultRenderer();
        table.getTableHeader().setDefaultRenderer(new TableCellRenderer() {

            @Override
            public Component getTableCellRendererComponent(JTable table,
                    Object value, boolean isSelected, boolean hasFocus,
                    int row, int column) {
                JLabel label = (JLabel)defaultRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
                label.setIcon(null);
                return label;
            }

        });
person macias    schedule 15.11.2013
comment
Это своего рода несоответствие нет, он разработан (и задокументирован) для точного решения вашего требования :-) - person kleopatra; 15.11.2013
comment
Да, вы правы, я пропустил это. С другой стороны, класс JTableHeader имеет этот метод setReorderingAllowed, который может отключить переупорядочивание столбцов. Честно говоря, я думаю, что было бы более интуитивно понятно иметь setRowSortingAllowed или что-то в этом роде. Это более естественно означало бы, что заголовок прослушивает события мыши или нет. Фактический механизм сортировки (RowSorter) вообще не будет задействован. - person macias; 15.11.2013
comment
полностью согласен, хороший аргумент :-) На самом деле, я забыл точное значение свойства sortable и предложил хак (удалено). Вероятно, даже допустил ошибку в sortController SwingX, который имеет дополнительный API для программной сортировки (setSortOrder), который ничего не делает, если столбец не поддается сортировке. - person kleopatra; 15.11.2013