2008-10-31 10 views
14

Wir sehen JTable Auswahl wird gelöscht, wenn wir eine fireTableDataChanged() oder fireTableRowsUpdated() aus der TableModel tun.Preserve JTable Auswahl über TableModel Änderung

Wird dies erwartet, oder machen wir etwas falsch? Ich habe keine Eigenschaft in der JTable (oder anderen verwandten Klassen) zum Löschen/Beibehalten der Auswahl bei Modellupdates gesehen.

Wenn dies Standardverhalten ist, gibt es eine gute Möglichkeit, dies zu verhindern? Vielleicht eine Möglichkeit, die Auswahl vor dem Update zu "sperren" und danach freizuschalten?

Der Entwickler hat damit experimentiert, die Auswahl vor dem Update zu speichern und erneut anzuwenden. Es ist ein bisschen langsam.

Dies ist Java 1.4.2 unter Windows XP, wenn das wichtig ist. Wir sind auf diese Version basierend auf dem von uns verwendeten Herstellercode beschränkt.

Antwort

4

getan haben, müssen Sie die Auswahl bewahren und dann erneut bewerben.

Zunächst müssen Sie eine Liste aller ausgewählten Zellen erhalten.

Wenn Sie die JTable dann erneut mit den neuen Daten laden, müssen Sie die gleichen Auswahlen programmgesteuert erneut anwenden.

Der andere Punkt, den ich machen möchte, ist, wenn die Anzahl oder Zeilen oder Spalten in Ihrer Tabelle nach jedem Reload des Tabellenmodells zunehmen oder abnehmen, dann behalte bitte nicht die Auswahl.

Der Benutzer könnte Zeile 2 Spalte 1 mit einem Wert sagen "Duck" vor der Modellaktualisierung ausgewählt haben. Aber nach der Modellaktualisierung können dieselben Daten jetzt in Zeile 4 Spalte 1 auftreten, und Ihre ursprüngliche Zelle Zeile 2 Spalte 1 könnte neue Daten wie "Schwein" haben. Wenn Sie die Auswahl zwangsweise auf den Wert vor der Modellaktualisierung setzen, ist dies möglicherweise nicht das, was der Benutzer wollte.

So programmgesteuert Zellen auswählen könnte ein zweischneidiges Schwert sein. Tun Sie es nicht, wenn Sie nicht sicher sind.

0

Wenn ich mich richtig erinnere, Speichern Auswahl und Wieder Anwendung ist es, was wir zu ...

1

Dies ist das Standardverhalten. Wenn Sie fireTableDataChanged() aufrufen, wird die gesamte Tabelle von Grund auf neu erstellt, da Sie ein völlig neues Modell festlegen. In diesem Fall ist die Auswahl natürlich verloren. Wenn Sie fireTableRowsUpdated() aufrufen, wird die Auswahl in allgemeinen Fällen ebenfalls gelöscht. Die einzige Möglichkeit besteht darin, sich an die Auswahl zu erinnern und diese dann festzulegen. Leider gibt es keine Garantie, dass die Auswahl noch gültig ist. Seien Sie vorsichtig, wenn Sie die Auswahl wiederherstellen.

0

Ich hatte das gleiche Problem in einer Anwendung. In meinem Fall war das Modell in der Tabelle eine Liste von Objekten, in denen die Objekteigenschaften den Spalten zugeordnet wurden. In diesem Fall, wenn die Liste geändert wurde, habe ich den ausgewählten Index abgerufen und das Objekt gespeichert, das vor dem Aktualisieren der Liste ausgewählt wurde. Nachdem die Liste geändert wurde und bevor die Tabelle aktualisiert wird, berechne ich die Position des ausgewählten Objekts. Wenn es nach der Änderung noch vorhanden wäre, würde ich die Auswahl auf den neuen Index setzen.

Das Festlegen des ausgewählten Index in der Tabelle nach der Änderung funktioniert nicht, da das Objekt die Position in der Liste ändern kann.

Als Nebenbemerkung habe ich festgestellt, dass die Arbeit mit GlazedLists das Leben im Umgang mit Tabellen viel einfacher macht.

4

Sie können die Auswahl einer Tabelle automatisch beibehalten, wenn sich die STRUKTUR dieser Tabelle nicht geändert hat (d. H. Wenn Sie keine Spalten/Zeilen hinzugefügt oder entfernt haben).

Wenn Sie eine eigene Implementierung von Tablemodel geschrieben haben, können Sie einfach überschreiben die fireTableDataChanged() -Methode:

 @Override 
     public void fireTableDataChanged() { 
      fireTableChanged(new TableModelEvent(this, //tableModel 
               0, //firstRow 
               getRowCount() - 1, //lastRow 
               TableModelEvent.ALL_COLUMNS, //column 
               TableModelEvent.UPDATE)); //changeType 
     } 

und dies sollte sicherstellen, dass Ihre Auswahl der Daten, die nur unter der Voraussetzung aufrechterhalten wird, und nicht die Struktur der Tisch hat sich geändert. Der einzige Unterschied zwischen diesem und dem, was aufgerufen würde, wenn diese Methode nicht überschrieben würde, ist, dass getRowCount() - 1 für das Argument lastRow anstelle von Integer.MAX_VALUE übergeben wird, wobei letzteres ein Signifikator ist, der nicht nur alle enthält Daten in der Tabelle geändert, aber die Anzahl der Zeilen möglicherweise auch.

+0

Vorsicht: nach hinten losgehen, so könnte tun - Ein dataChanged kann Einfügungen/Löschungen enthalten. Wenn das der Fall ist, könnten die Zuhörer stark in die Irre geführt werden – kleopatra

+0

Wäre das nicht eine Struktur, die dann geändert wird? –

+0

nein, ein structureChanged ist, wenn die Spalten zusammen mit den Daten geändert werden – kleopatra

0

Ich war mit dem gleichen Problem konfrontiert und wenn versucht, den Grund zu suchen, bekam ich diese Frage, aber es scheint ein Bug in Java SDK. http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4276786

Umgehen

Eine vorübergehende Behelfslösung ist verfügbar. Es sollte entfernt werden, sobald dieser Fehler behoben ist, da seine Eignung NICHT gegen feste Versionen getestet wurde.

Verwenden Sie diese Unterklasse von JTable.

Hinweis: Dies ist für den MetalLookAndFeel. Wenn andere Look and Feels verwendet werden, muss die innere FixedTableUI-Unterklasse die TableUI-Unterklasse für dieses Look-and-Feel erweitern.

import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 
import javax.swing.table.*; 
import javax.swing.event.*; 
import javax.swing.plaf.basic.*; 

public class FixedTable extends JTable { 

    private boolean isControlDownInDrag; 

    public FixedTable(TableModel model) { 
     super(model); 
     setUI(new FixedTableUI()); 
    } 

    private class FixedTableUI extends BasicTableUI { 
     private MouseInputHandler handler = new MouseInputHandler() { 
      public void mouseDragged(MouseEvent e) { 
       if (e.isControlDown()) { 
        isControlDownInDrag = true; 
       } 
       super.mouseDragged(e); 
      } 

      public void mousePressed(MouseEvent e) { 
       isControlDownInDrag = false; 
       super.mousePressed(e); 
      } 

      public void mouseReleased(MouseEvent e) { 
       isControlDownInDrag = false; 
       super.mouseReleased(e); 
      } 
     }; 

     protected MouseInputListener createMouseInputListener() { 
      return handler; 
     } 
    } 

    public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) { 
     if (isControlDownInDrag) { 
      ListSelectionModel rsm = getSelectionModel(); 
      ListSelectionModel csm = getColumnModel().getSelectionModel(); 

      int anchorRow = rsm.getAnchorSelectionIndex(); 
      int anchorCol = csm.getAnchorSelectionIndex(); 

      boolean anchorSelected = isCellSelected(anchorRow, anchorCol); 

      if (anchorSelected) { 
       rsm.addSelectionInterval(anchorRow, rowIndex); 
       csm.addSelectionInterval(anchorCol, columnIndex); 
      } else { 
       rsm.removeSelectionInterval(anchorRow, rowIndex); 
       csm.removeSelectionInterval(anchorCol, columnIndex); 
      } 

      if (getAutoscrolls()) { 
       Rectangle cellRect = getCellRect(rowIndex, columnIndex, false); 
       if (cellRect != null) { 
        scrollRectToVisible(cellRect); 
       } 
      } 
     } else { 
      super.changeSelection(rowIndex, columnIndex, toggle, extend); 
     } 
    } 
} 

Hinweis Curtsey zu http://bugs.sun.com

1

als Referenz, wie @Swapnonil Mukherjee erklärte, dies hat den Trick mit einem Tisch mit wählbaren Reihen:

 // preserve selection calling fireTableDataChanged() 
     final int[] sel = table.getSelectedRows(); 

     fireTableDataChanged(); 

     for (int i=0; i<sel.length; i++) 
      table.getSelectionModel().addSelectionInterval(sel[i], sel[i]); 
Verwandte Themen