JFace TableViewer

Ein JFace TableViewer funktioniert ähnlich zum Combo-/ListViewer. Hinzu kommt hier lediglich, dass je ein LabelProvider für jede Spalte gesetzt wird. Dazu ist zunächst für jede Spalte ein JFace TableViewerColumn-Objekt anzulegen. Dieses erzeugt und verwaltet eine SWT TableColumn:

TableViewerColumn viewerNameColumn = new TableViewerColumn(tableViewer, SWT.NONE);
viewerNameColumn.getColumn().setText("Some Column");
viewerNameColumn.getColumn().setWidth(100);

Den Spalten ist ein LabelProvider zu setzen. Der LabelProvider ist dafür zuständig, die Zellen der Spalte zu befüllen. Je Tabellenzelle wird er einmal aufgerufen, um die Zelle mit Inhalten zu befüllen. Dabei hat er das Element für die jeweilige Zeile zur Verfügung:

TableViewerColumn

TableViewerColumn viewerNameColumn = new TableViewerColumn(tableViewer, SWT.NONE);
viewerNameColumn.setLabelProvider(new CellLabelProvider() {

    @Override
    public void update(ViewerCell cell) {
        cell.setText(((SomeObject) cell.getElement()).getSomeProperty());
    }

});

Zusammengefasst: Ein TableViewer befüllt eine SWT Table mit Inhalten aus seinem Input-Objekt. Der ContentProvider konvertiert dazu das Input-Objekt in Zeilenobjekte. Jede Spalte des TableViewers bekommt einen CellLabelProvider gesetzt, der die Zellen der Spalte mit den Daten aus dem Zeilenobjekt befüllt:

// JFace TableViewer
TableViewer tableViewer = new TableViewer(parentComposite, SWT.NONE);
// SWT Table
Table table = tableViewer.getTable();
// Spaltenköpfe und Zeilenbegrenzungen sichtbar machen
table.setHeaderVisible(true);
table.setLinesVisible(true);

// ArrayContentProvider kann verwendet werden, da Input-Objekt eine Java Collection ist
tableViewer.setContentProvider(ArrayContentProvider.getInstance());

// Für jede Spalte ein TableViewerColumn erzeugen
TableViewerColumn viewerNameColumn = new TableViewerColumn(tableViewer, SWT.NONE);
viewerNameColumn.getColumn().setText("Test");
viewerNameColumn.getColumn().setWidth(100);

// LabelProvider für jede Spalte setzen
viewerNameColumn.setLabelProvider(new CellLabelProvider() {
    public void update(ViewerCell cell) {
        cell.setText(((SomeObject) cell.getElement()).getSomeProperty());
    }
});

// List<SomeObject> als Input-Objekt setzen
tableViewer.setInput(someList);

Prozentuale Spaltenbreiten

Mit TableColumnLayout kann die Breite von Tabellenspalten prozentual verteilt werden. Dazu wird ein Composite um die Tabelle herum benötigt, welches nur die Tabelle enthält. Diesem wird das TableColumnLayout gesetzt. Das Layout übernimmt dann die Verteilung der Spaltenbreiten in der enthaltenen Tabelle:

Composite tableComposite = new Composite(parent, SWT.NONE);
TableColumnLayout tableColumnLayout = new TableColumnLayout();
tableComposite.setLayout(tableColumnLayout);
TableViewer tableViewer = new TableViewer(tableComposite, SWT.BORDER | SWT.FULL_SELECTION);

Auf dem Layout-Objekt kann für jede Spalte ein ColumnLayoutData-Objekt gesetzt werden, um dem Layout den Platzbedarf der Tabellenspalte mitzuteilen:

tableColumnLayout.setColumnData(viewerNameColumn.getColumn(), new ColumnPixelData(50));

ColumnPixelData erlaubt die absolute Angabe einer Spaltenbreite in Pixeln, ColumnWeightData erlaubt die Angabe einer prozentualen Spaltengewichtung, minimaler Breite in Pixel sowie die Angabe, ob die Spaltenbreite vom Benutzer verändert werden darf:

public ColumnPixelData(int width)
public ColumnWeightData(int weight, int minimumWidth, boolean resizable)

Tabellen sortieren

Um die Reihenfolge der Zeilen eines JFace TableViewers festzulegen, kann dem TableViewer ein ViewerComparator gesetzt werden:

tableViewer.setComparator(ViewerComparator comparator)

Die Sortierung erfolgt dabei rein auf Anzeigeebene, das zugrundeliegende Input-Objekt bleibt unverändert. Der ViewerComparator implementiert die Vergleichsoperation für die Zeilen-Elemente und legt so die Reihenfolge der Zeilen fest:

tableViewer.setComparator(new ViewerComparator() {
    
    @Override
    public int compare(Viewer viewer, Object e1, Object e2) {
        if (e1 instanceof SomeObject && e2 instanceof SomeObject) {
            return ((SomeObject) e1).getName().compareToIgnoreCase(
                   ((SomeObject) e2).getName());
        }
        throw new IllegalArgumentException("Not comparable: " + e1 + " " + e2);
    }

});

Tabellen filtern

Um die Zeilen eines JFace StructuredViewers zu filtern, kann mit addFilter bzw. setFilters eine Liste von ViewerFilter-Objekten gesetzt werden. Die jeweilige Zeile wird nur dann zur Anzeige gebracht, wenn alle gesetzten Filter der Anzeige zugestimmt haben. So lässt sich beispielsweise eine Suche über die Inhalte der Tabelle realisieren:

ViewerFilter searchFilter = new ViewerFilter() {
    
    @Override
    public boolean select(Viewer viewer, Object parentElement, Object element) {
        return ((SomeObject) element).getName().contains("searchString");
    }
    
};

tableViewer.addFilter(searchFilter);

Editierbare Tabellen

Die Spalten in einem JFace-Viewer können editierbar gemacht werden, indem auf der TableViewerColumn ein EditingSupport-Objekt für die Spalte gesetzt wird. Durch die EditingSupport-Implementierung wird festgelegt, welche Zellen bearbeitbar sein sollen, welches Control zur Bearbeitung verwendet werden soll (im Beispiel TextCellEditor) und wie die Werte zu holen und zu setzen sind:

tableViewerColumn.setEditingSupport(new EditingSupport(tableViewer) {

    protected boolean canEdit(Object element) {
        return true;
    }

    protected CellEditor getCellEditor(Object element) {
        return new TextCellEditor(tableViewer.getTable());
    }

    protected Object getValue(Object element) {
        return ((SomeObject) element).getName();
    }

    protected void setValue(Object element, Object value) {
        ((SomeObject) element).setName(String.valueOf(value));
        tableViewer.refresh(element);
    }

});

Als CellEditor stehen TextCellEditor, ColorCellEditor, ComboBoxCellEditor, CheckboxCellEditor sowie DialogCellEditor zur Verfügung.

Eclipse RCP

Eclipse RCP eBook

Die Entwicklung von Desktop-Anwendungen mit der Eclipse Rich Client Platform anschaulich erklärt in 23 Kapiteln. Mit über 20 ausführlichen Schritt-für-Schritt-Tutorials zur Entwicklung einer RCP-Beispielanwendung. Ab sofort erhältlich als eBook in den Formaten PDF und MOBI (geeignet für Kindle und Kindle Reading Apps)

Ralf Ebert

Ralf Ebert schreibt und publiziert das eBook “Eclipse RCP - Entwicklung von Desktop-Anwendungen mit der Eclipse Rich Client Platform 3.7”. Darin vermittelt er seine Kenntnisse und Erfahrungswerte aus zahlreichen RCP-Projekten, die er als Entwickler erfolgreich umgesetzt und als Berater begleitet hat. Seit 2006 hat er in mehr als 50 Schulungsveranstaltungen die Verwendung des Eclipse RCP-Frameworks geschult.