Взаимодействие с JTable, который быстро обновляется новыми строками - PullRequest
4 голосов
/ 02 марта 2012

Краткое описание проблемы.

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

Ниже приводится первоначальный вопрос, который более подробно объясняет проблему :

Рассмотрим следующую ситуацию:

  1. Существует JTable, который показывает информацию о пользователях о текущих выполняющихся запросах в некоторой системе

  2. Когда в систему поступает новый запрос, в таблицу добавляется новая строка

  3. пользователь может взаимодействовать с таблицей, щелкнув правой кнопкой мыши по строке (в таблице используется модель выбора одной строки) и выбрав опцию в меню (например, отменить, отложить, повторить и т. Д.)

  4. существует отдельный класс, который реализует интерфейс ActionListener (слушает таблицу) и обрабатывает все взаимодействия с пользователем

  5. Когда пользователь выполняет какое-либо действие с таблицей, этот класс проверяет текущую выбранную строку и присваивает некоторые значения для действия пользователя (в основном он берет индекс выбранной строки и затем вызывает tableModel.getValueAt (indexOfSelectedRow, indexVfuuDextColumnIndex))

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

Вопрос в том, как это исправить. Я думаю о двух подходах:

  • использовать что-то вроде invokeAndWait () для инициализации в классе обработки моих действий пользователя (не нравится эта идея, потому что, по моему мнению, это приведет к другим непредсказуемым ошибкам) ​​

  • создание отдельного класса слушателя, который будет прослушивать выбор пользователя в таблице и сохранять данные из выбранной строки, как только он был выбран отдельно от TableModel. Таким образом, класс обработки действий будет получать данные не из изменяемой модели таблицы, а из выбранной строки, которая является постоянной в описанном сценарии. (не уверен, что эта идея будет работать)

Пожалуйста, прокомментируйте мои идеи и предложите свои.

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

Ответы [ 2 ]

4 голосов
/ 02 марта 2012

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

import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;

public class TestJTableInsert {
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                final DefaultTableModel model = new DefaultTableModel(0, 1);
                new Timer(500, new ActionListener() {
                    private final Random random = new Random();
                    private int data = 1;

                    @Override
                    public void actionPerformed(ActionEvent e) {
                        model.insertRow(random.nextInt(model.getRowCount() + 1),
                                new Object[] { data++ });
                    }
                }).start();

                final JTable table = new JTable(model);
                JPopupMenu popup = new JPopupMenu();
                popup.add(new AbstractAction("Which row is this?") {

                    @Override
                    public void actionPerformed(ActionEvent e) {
                        JOptionPane.showMessageDialog(table,
                                "This is row " + table.getValueAt(table.getSelectedRow(), 0));
                    }
                });
                table.setComponentPopupMenu(popup);
                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                frame.getContentPane().add(new JScrollPane(table));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }
}
3 голосов
/ 02 марта 2012

пример модели - это не то, что можно легко сделать здесь.

Вот стартовый пример, демонстрирующий, что выбор остается постоянным (в том смысле, что он всегда указывает на одно и то же«реальный» ряд:

final DefaultTableModel model = new DefaultTableModel(0, 1);
for (int i = 0; i < 50; i++) {
    model.addRow(new Object[] {i});
};

final JXTable table = new JXTable(model);
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
table.setRowSelectionInterval(25, 25);
Action l = new AbstractAction("random insert") {
    Random random = new Random();
    @Override
    public void actionPerformed(ActionEvent e) {
        int row = random.nextInt(model.getRowCount());
        model.insertRow(row, new Object[] {"inserted at: " + row});
        table.scrollRowToVisible(table.getSelectedRow());
    }

};
new Timer(100, l).start();
...