Выбранная строка не обновляется из-за метода заполнения JTable.JAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 Выбранная строка не обновляется из-за метода заполнения JTable.

Сообщение Anonymous »

Вот тестовый пример:
Если пользователь:
  • Выбирает вторую строку таблицы.
  • Вводит «Смит» в поле фильтра, нажимает Enter.
то метка статистики таблицы должна читать: «Строки: 1»
Вот MRE. Он включает в себя как хорошую, так и плохую реализацию логики заполнения таблицы.
Если вы сохраните хорошую реализацию, тестовый пример будет пройден.
Однако, если вы сохраните плохую реализацию, тестовый пример не будет пройден. Что делает его более интересным, так это то, что если вы очистите поле, нажмите Enter и повторите тестовый пример, он пройдет.

Код: Выделить всё

package demos.table;

import javax.swing.DefaultRowSorter;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.RowFilter;
import javax.swing.WindowConstants;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.util.regex.Pattern;

public class SimpleTableDemo {

static JTable table;
private static JLabel tableLabel;

public static void main(String[] args) {
Container mainPanel = createMainPanel();
JFrame frame = new JFrame("Simple Table Demo");
frame.setContentPane(mainPanel);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
}

private static Container createMainPanel() {
JPanel mainPanel = new JPanel(new BorderLayout());
mainPanel.add(createFilterField(), BorderLayout.NORTH);
mainPanel.add(createScroller());
mainPanel.add(createTableLabel(), BorderLayout.SOUTH);
return mainPanel;
}

private static Component createTableLabel() {
tableLabel = new JLabel(createTableLabelText());
return tableLabel;
}

private static Component createFilterField() {
JTextField field = new JTextField();
field.addActionListener(e -> onFilter(field));
return field;
}

private static void onFilter(JTextField field) {
DefaultRowSorter rowSorter = (DefaultRowSorter) table.getRowSorter();
String regex = String.format("(?i)%s", Pattern.quote(field.getText()));
rowSorter.setRowFilter(RowFilter.regexFilter(regex, 1, 2));
}

private static Component createScroller() {
JScrollPane scroller = new JScrollPane();
scroller.setViewportView(createTable());
return scroller;
}

private static Component createTable() {
table = new JTable();
table.setAutoCreateRowSorter(true);
fillTableGood();
//        fillTableBad();
table.getSelectionModel().addListSelectionListener(e -> updateTableLabel());
return table;
}

/**
* Good implementation.
*/
private static void fillTableGood() {
DefaultTableModel model = new DefaultTableModel(createRows(), createColumns());
table.setModel(model);
}

private static String[][] createRows() {
return new String[][]{{"21", "Peter", "Smith"},
{"25", "Helen", "Brown"},
{"30", "Josh", "Brown"},
};
}

private static String[] createColumns() {
return new String[]{"Age", "First Name", "Last Name"};
}

/**
* Bad implementation.
*/
private static void fillTableBad() {
DefaultTableModel model = new DefaultTableModel();
table.setModel(model);

String[] columns = createColumns();
model.setColumnCount(columns.length);
model.setColumnIdentifiers(columns);

String[][] rows = createRows();
for (int rowIndex = 0; rowIndex < rows.length; rowIndex++) {
String[] row = rows[rowIndex];
model.setRowCount(model.getRowCount() + 1);
for (int columnIndex = 0; columnIndex < row.length;  columnIndex++) {
String cellData = row[columnIndex];
model.setValueAt(cellData, rowIndex, columnIndex);
}
}
}

private static void updateTableLabel() {
String text = createTableLabelText();
if (tableLabel != null) tableLabel.setText(text);
}

private static String createTableLabelText() {
int rowCount = table.getRowCount();
String text = String.format("Rows: %d", rowCount);
int selectedRow = table.getSelectedRow();
if (selectedRow != -1) text = String.format("Row %d from %d", selectedRow + 1, rowCount);
return text;
}
}
Я обнаружил, что это связано с методом javax.swing.JTable.SortManager#cacheModelSelection, который не вызывается в хорошей реализации. В результате первый if в методе javax.swing.JTable.SortManager#restoreSelection позже оценивается как false, что в конечном итоге приводит к обновлению текста метки.

Код: Выделить всё

// initializes lastModelSelection — bad!
private void cacheModelSelection(RowSorterEvent sortEvent) {
lastModelSelection = convertSelectionToModel(sortEvent);
modelLeadIndex = convertRowIndexToModel(sortEvent,
selectionModel.getLeadSelectionIndex());
}

Код: Выделить всё

// the second if branch is a good one, the execution should go there
private void restoreSelection(ModelChange change) {
syncingSelection = true;
if (lastModelSelection != null) {
restoreSortingSelection(lastModelSelection,
modelLeadIndex, change);
lastModelSelection = null;
} else if (modelSelection != null) {
Зачем мне вообще нужна плохая реализация? Видите ли, наше приложение использует плохой подход, и его непросто реорганизовать в хороший. Я обеспокоен тем, что это может привести к неожиданной поломке приложения. Тем не менее, я бы все же предпочел, чтобы описанная ошибка была устранена (безопасно).
Каковы основные причины такого поведения и есть ли какие-либо изменения в «плохой» реализации, которые заставили бы ее работать?
Java 8.

Подробнее здесь: https://stackoverflow.com/questions/798 ... ing-method
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»