JTable sortieren: Unterschied zwischen den Versionen
K |
K |
||
Zeile 8: | Zeile 8: | ||
Das sieht dann folgendermaßen aus: | Das sieht dann folgendermaßen aus: | ||
− | < | + | <syntaxhighlight lang="java"> |
import java.awt.*; | import java.awt.*; | ||
import java.util.Random; | import java.util.Random; | ||
Zeile 85: | Zeile 85: | ||
} | } | ||
} | } | ||
− | </ | + | </syntaxhighlight> |
− | < | + | <syntaxhighlight lang="java"> |
// Ein Renderer für java.awt.Point | // Ein Renderer für java.awt.Point | ||
public class PointRender extends DefaultTableCellRenderer{ | public class PointRender extends DefaultTableCellRenderer{ | ||
Zeile 98: | Zeile 98: | ||
hasFocus, row, column ); | hasFocus, row, column ); | ||
} | } | ||
− | }</ | + | }</syntaxhighlight> |
[[Bild:JTableSort1.png]] | [[Bild:JTableSort1.png]] | ||
Zeile 106: | Zeile 106: | ||
Der Code vom Beispiel oben leicht abgeändert: | Der Code vom Beispiel oben leicht abgeändert: | ||
− | < | + | <syntaxhighlight lang="java"> |
import java.awt.*; | import java.awt.*; | ||
import java.util.Comparator; | import java.util.Comparator; | ||
Zeile 143: | Zeile 143: | ||
[...] | [...] | ||
− | }</ | + | }</syntaxhighlight> |
− | < | + | <syntaxhighlight lang="java"> |
// Ein Comparator für Punkte | // Ein Comparator für Punkte | ||
public class PointComparator implements Comparator<Point>{ | public class PointComparator implements Comparator<Point>{ | ||
Zeile 160: | Zeile 160: | ||
return 0; | return 0; | ||
} | } | ||
− | }</ | + | }</syntaxhighlight> |
Das Resultat: die Punkte werden zuerst nach der x, dann nach der y-Koordinate sortiert: | Das Resultat: die Punkte werden zuerst nach der x, dann nach der y-Koordinate sortiert: | ||
Version vom 8. März 2018, 19:39 Uhr
Mit Java 1.6 wurde Swing weiterentwickelt. Unter anderem kann die JTable nun sortiert werden.
Für die Sortierung muss man beim JTable
einen RowSorter<? extends TableModel>
über die Methode setRowSorter()
registrieren. Die JTable wird diesen RowSorter
benutzen, um die Einträge des TableModel
s hin und her zu schieben.
1. Der TableRowSorter
Zwar wäre es möglich einen RowSorter selbst zu implementieren, die weitaus einfachere Variante ist aber die Benutzung der Klasse TableRowSorter
.
Der unkonfigurierte TableRowSorter sortiert jeweils eine Spalte. Sollten die Elemente dieser Spalte eine natürliche Ordnung (durch das Interface Comparable
definiert) haben, so wird diese Ordnung benutzt. Andernfalls werden die Elemente in Strings umgewandelt, und mittels eines Collators verglichen.
Das sieht dann folgendermaßen aus:
import java.awt.*;
import java.util.Random;
import javax.swing.*;
import javax.swing.table.*;
public class JTableDemo{
public static void main( String[] args ){
// Ein TableModel mit zufälligen Werten füllen
TableModel model = randomModel();
// Die JTable initialisieren
JTable table = new JTable( model );
table.setDefaultRenderer( Point.class, new PointRender());
// Der TableRowSorter wird die Daten des Models sortieren
TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>();
// Der Sorter muss dem JTable bekannt sein
table.setRowSorter( sorter );
// ... und der Sorter muss wissen, welche Daten er sortieren muss
sorter.setModel( model );
JFrame frame = new JFrame( "Demo" );
frame.getContentPane().add( new JScrollPane( table ) );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.pack();
frame.setVisible( true );
}
// Diese Methode generiert ein TableModel mit zufälligen Werten
private static TableModel randomModel(){
Object[] names = { "String", "Integer", "Point" };
DefaultTableModel model = new DefaultTableModel( names, 0 ){
@Override
public Class<?> getColumnClass( int column ) {
switch( column ){
case 0: return String.class;
case 1: return Integer.class;
case 2: return Point.class;
default: return Object.class;
}
}
};
Random random = new Random();
for( int i = 0; i < 100; i++ ){
Object[] row = {
randomString( random ),
randomInt( random ),
new Point( randomInt( random ), randomInt( random ))
};
model.addRow( row );
}
return model;
}
// Generiert einen zufälligen String
private static String randomString( Random random ){
int length = random.nextInt( 4 ) + 4;
StringBuilder result = new StringBuilder( length );
for( int i = 0; i < length; i++ )
result.append( (char)('a' + random.nextInt( 'z' - 'a' + 1 )));
return result.toString();
}
// Generiert einen zufälligen int
private static int randomInt( Random random ){
return random.nextInt( 1000 ) + 1;
}
}
// Ein Renderer für java.awt.Point
public class PointRender extends DefaultTableCellRenderer{
@Override
public Component getTableCellRendererComponent( JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column ) {
Point point = (Point)value;
String text = point.x + " / " + point.y;
return super.getTableCellRendererComponent( table, text, isSelected,
hasFocus, row, column );
}
}
2. Ein eigener Comparator
Im Beispiel des 1. Abschnittes wurden die String
- und die Integer
-Spalte sinnvoll sortiert, die Point
-Spalte sah hingegen komisch aus. Damit auch diese Spalte sinnvoll sortiert wird (ohne dass man eine neue Point-Klasse implementiert), muss man einen Comparator
bereitstellen. Dieser Comparator kann man über die Methode setComparator()
des TableRowSorters einbinden.
Der Code vom Beispiel oben leicht abgeändert:
import java.awt.*;
import java.util.Comparator;
import java.util.Random;
import javax.swing.*;
import javax.swing.table.*;
public class JTableDemo{
public static void main( String[] args ){
// Ein TableModel mit zufälligen Werten füllen
TableModel model = randomModel();
// Die JTable initialisieren
JTable table = new JTable( model );
table.setDefaultRenderer( Point.class, new PointRender());
// Der TableRowSorter wird die Daten des Models sortieren
TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>();
// Der Sorter muss dem JTable bekannt sein
table.setRowSorter( sorter );
// ... und der Sorter muss wissen, welche Daten er sortieren muss
sorter.setModel( model );
// Den Comparator für die 2. Spalte (mit den Points) setzen.
sorter.setComparator( 2, new PointComparator());
JFrame frame = new JFrame( "Demo" );
frame.getContentPane().add( new JScrollPane( table ) );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.pack();
frame.setVisible( true );
}
[...]
}
// Ein Comparator für Punkte
public class PointComparator implements Comparator<Point>{
public int compare( Point o1, Point o2 ) {
if( o1.x < o2.x )
return -1;
else if( o1.x > o2.x )
return 1;
else if( o1.y < o2.y )
return -1;
else if( o1.y > o2.y )
return 1;
else
return 0;
}
}
Das Resultat: die Punkte werden zuerst nach der x, dann nach der y-Koordinate sortiert:
3. Weitere Methoden
Der TableRowSorter bietet eine Reihe weiterer Methoden, die Aufmerksamkeit verdienen:
setStringConverter()
setzt ein Delegate um aus Objects Strings zu generieren. Praktisch das Selbe, was die MethodetoString()
macht. Wenn einTableStringConverter
gesetzt ist, wird dieser Converter an Stelle der toString()-Methode benutzt, um einen sortierbaren String aus unbekannten Objekten zu generieren. Vorteilhaft ist dieses Vorgehen, wenn die toString()-Methode nicht überschrieben werden kann (weil die Objekte z.B. aus einer Library kommen), oder verschiedene Tabellen nach unterschiedlichen Kriterien sortieren sollen.setMaxSortKeys()
sagt dem Sorter, wie viele Spalten beim Sortieren beachtet werden sollen. Angenommen der Wert ist auf 3, der Benutzer sortiert zuerst Spalte 2, dann 1: sollte nun in Spalte 1 ein Element doppelt vorkommen, so werden die Zeilen nach der 2. Spalte sortiert. Würde der Benutzer noch auf die 4. Spalte klicken, so würde zuerst nach der 4., dann nach der 1., dann nach der 2. Spalte sortiert.setRowFilter()
setzt einenRowFilter
. Der RowFilter entscheidet in seiner include()-Methode zeilenweise, welche Zeilen angezeigt werden sollten. Ein RowFilter eignet sich z.B. für eine Suchfunktion: sobald der Benutzer in ein Textfeld etwas eintippt, erlaubt der RowFilter nur noch diejenigen Daten, welche zu dem eingetippten Text passen. Der Sorter kann über die Methode sort aufgefordert werden, den veränderten Filter zu benutzen.