Ausgewählte Zeile wurde aufgrund der JTable-Füllmethode nicht aktualisiertJava

Java-Forum
Anonymous
 Ausgewählte Zeile wurde aufgrund der JTable-Füllmethode nicht aktualisiert

Post by Anonymous »

Hier ist ein Testfall:
Wenn der Benutzer:
  • die zweite Tabellenzeile auswählt.
  • Smith in das Filterfeld eingibt und die Eingabetaste drückt.
dann sollte die Beschriftung der Tabellenstatistik lauten: „Zeilen: 1“
Hier ist ein MRE. Es umfasst sowohl eine gute als auch eine schlechte Implementierung der Tabellenfülllogik.
Wenn Sie die gute Implementierung beibehalten, ist der Testfall bestanden.
Wenn Sie jedoch die schlechte Implementierung beibehalten, ist der Testfall fehlgeschlagen. Was es noch interessanter macht, ist, dass es erfolgreich ist, wenn Sie das Feld leeren, die Eingabetaste drücken und den Testfall wiederholen.

Code: Select all

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;
}
}
Ich habe festgestellt, dass es mit der Methode javax.swing.JTable.SortManager#cacheModelSelection zusammenhängt, die in der guten Implementierung nicht aufgerufen wird. Infolgedessen wird das erste if in der Methode javax.swing.JTable.SortManager#restoreSelection später als „false“ ausgewertet, was schließlich zur Aktualisierung des Beschriftungstextes führt.

Code: Select all

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

Code: Select all

// 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) {
Warum sollte ich die schlechte Implementierung überhaupt brauchen? Sehen Sie, unsere App nutzt den schlechten Ansatz und es ist nicht einfach, ihn in den guten umzuwandeln. Ich befürchte, dass die App auf unerwartete Weise beschädigt werden könnte. Trotzdem würde ich es immer noch vorziehen, wenn der beschriebene Fehler (sicher) behoben würde.
Was sind die Hauptursachen für dieses Verhalten und gibt es irgendwelche Optimierungen an der „schlechten“ Implementierung, die dafür sorgen würden, dass es funktioniert?
Java 8.

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post