Проблемы интервала выбора JTable с отсортированной таблицей

1

У меня есть JTable, который сортируется и фильтруется с помощью RowSorter и обновляется в реальном времени. У меня проблема, когда пользователи пытаются создать интервал выбора с помощью мыши (нажмите + перетащить строки) или с клавиатуры (SHIFT + стрелка вниз несколько раз).

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

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

Я приложил небольшое демо-приложение. Попробуйте выбрать несколько строк с помощью мыши - каждую секунду выбор будет поврежден....

Кажется, это ошибка (или нежелательное поведение) в Java-классах. Я надеюсь, что кто-то сможет предложить креативное решение/работу.

    public class TableTest extends JFrame {
    private static final long serialVersionUID = 1L;

    public TableTest() {
        super("Table Selection Problem");
        setBounds(50, 50, 800, 600);
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        // Create a table model
        final DefaultTableModel tableModel = new DefaultTableModel(40,10);

        // Create table row sorter sorted on column 1
        TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(tableModel);
        sorter.setSortsOnUpdates(true);
        sorter.setSortKeys(Arrays.asList(new RowSorter.SortKey(1,SortOrder.DESCENDING)));

        // Create a table and bind the sorter
        JTable table = new JTable(tableModel);
        table.setRowSorter(sorter);

        // Bind a list selection listener, this doesn't do anything besides showing the selection change(s) on every table model update
        table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
            @Override
            public void valueChanged(ListSelectionEvent e) {
                System.out.println(e); 
            }
        });


        // place the table in the frame
        getContentPane().add(new JScrollPane(table), BorderLayout.CENTER);

        // Simulate some application events that trigger a table update...
        new Thread() {
            public void run() {
                try {
                    final Random r = new Random();
                    for(int x = 0; x < 1000; x++) {
                        // update a table cell (not even an add or delete)
                        SwingUtilities.invokeLater(new Runnable() {
                            public void run() {
                                tableModel.setValueAt(r.nextInt(1000), r.nextInt(40), r.nextInt(10));
                            }
                        });
                        // wait 1 second before next table update
                        Thread.sleep(1000);
                    }
                } catch(Throwable t) {
                    t.printStackTrace();
                }
            }
        }.start();      
    }


    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                (new TableTest()).setVisible(true);                     
            }
        });     
    }
}
  • 0
    Должен сказать, что не вижу проблемы. Что касается перспективы, выбор был между родами, то есть, если я выбрал строку 1-5, а перед ней была вставлена новая строка, этот сдвиг вниз. Если новая строка вставляется где-то между ними, то выбор разделяется, что было бы моим ожиданием, так как выбор основан на данных, а не на строке (с точки зрения высокого уровня)
  • 0
    Вот как работает код, когда нет обновления модели таблицы при увеличении интервала выбора. Если вы запускаете мое тестовое приложение - оно отправляет обновление модели таблицы каждую секунду. Нажмите на строку 2 таблицы и начните перетаскивать мышь вверх / вниз, скажем, чтобы выбрать строки с 2 по 7, затем немного отступите назад, чтобы были выбраны строки с 2 по 4, а затем снова вниз, чтобы выбрать строки с 2 по 10. Обновление модели таблицы происходит в процессе выбора. Выбор якоря (строка 2) удаляется, и теперь выбор начинает расширяться от того места, где находится мышь (когда произошло обновление) - туда, куда она была перемещена.
Показать ещё 3 комментария
Теги:
swing
selection
jtable
rowsorter

1 ответ

2

Когда я запускал ваш код с помощью JDK7 в Windows 7, я обнаружил, что setSortsOnUpdates(...) вызывает проблемы с данными в таблице. То есть, я позволяю коду работать некоторое время, и я заметил, что в столбце 1 не отображается никаких значений. Итак, я увеличил ширину рамки, и внезапно значения появились в отсортированном порядке. Поэтому по какой-то причине таблица не была перекрашена, даже если данные изменились. Когда я прокомментировал setSortsOnUpdates(...) изменения в TableModel появились сразу. Я понятия не имею, в чем проблема.

Поэтому я изменил подход, чтобы вручную вызывать сортировку при изменении данных. Тем не менее, я только сделал вид, когда ListSelectionListener не корректировался. Вот код:

import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import java.util.Arrays;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.event.*;

    public class TableTest5 extends JFrame {
    private static final long serialVersionUID = 1L;

    private boolean isAdjusting = false;
    private boolean isModelChanged = false;
    TableRowSorter<TableModel> sorter;
    final Random r = new Random();

    public TableTest5() {
        super("Table Selection Problem");
        setBounds(50, 50, 800, 600);
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        // Create a table model
        final DefaultTableModel tableModel = new DefaultTableModel(30,3);

        // Create table row sorter sorted on column 1
//        TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(tableModel);
        sorter = new TableRowSorter<TableModel>(tableModel);
        sorter.setSortsOnUpdates(true);
        sorter.setSortKeys(Arrays.asList(new RowSorter.SortKey(1,SortOrder.DESCENDING)));

        // Create a table and bind the sorter
        JTable table = new JTable(tableModel);
        table.setRowSorter(sorter);

        // Bind a list selection listener, this doesn't do anything besides showing the selection change(s) on every table model update
        table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
            @Override
            public void valueChanged(ListSelectionEvent e) {
                isAdjusting = e.getValueIsAdjusting();

                if (!isAdjusting && isModelChanged)
                {
                    isModelChanged = false;
                    sorter.sort();
                }
            }
        });


        // place the table in the frame
        getContentPane().add(new JScrollPane(table), BorderLayout.CENTER);

        // Simulate some application events that trigger a table update...
        new Thread() {
            public void run() {
                try {
                    //final Random r = new Random();
                    for(int x = 0; x < 1000; x++) {
                        // update a table cell (not even an add or delete)
                        SwingUtilities.invokeLater(new Runnable() {
                            public void run() {

                                int value = r.nextInt(1000);
                                int row = r.nextInt(30);
                                int column = r.nextInt(5);
                                System.out.println(value + " : " + row + " : " + column);
                                tableModel.setValueAt(value, row, column);

                                if (!isAdjusting)
                                    sorter.sort();
                                else
                                    isModelChanged = true;
                            }
                        });
                        // wait 1 second before next table update
                        Thread.sleep(1000);
                    }
                } catch(Throwable t) {
                    t.printStackTrace();
                }
            }
        }.start();

    }


    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                (new TableTest5()).setVisible(true);
            }
        });
    }
}

Возможно, вам захочется использовать TableModelListener для прослушивания изменений TableModel для ручного вызова сортировки.

  • 0
    Хотя это, похоже, исправляет проблему в примере - если вы добавите строку (или удалите строку) из модели таблицы, у вас снова возникнет та же проблема. Этот подход не работает для выбора клавиатуры (SHIFT + стрелки вниз).

Ещё вопросы

Сообщество Overcoder
Наверх
Меню