Zellbiologie: GWT CellTable

Die einzelnen Komponenten, aus denen sich die Benutzeroberfläche der Beispielanwendung zusammensetzt, könnten direkt in Java-Code erzeugt und initialisiert werden. Mit dem Konzept der UIBinder bietet GWT jedoch eine interessante Alternative: Oberflächen lassen sich deklarativ über XML-Dateien definieren. Ein solches Dokument kann dabei sowohl HTML-Tags als auch Verweise auf GWT- oder eigene graphische Komponenten enthalten. Ein Vorteil dieses Ansatzes ist die klare Trennung von Layout und Anwendungslogik. Wir machen deshalb hier von diesem Mechanismus Gebrauch. Listing 2 zeigt die UIBinder-Datei SongOverviewTable.ui.xml.

Listing 2

Neben einigem HTML zur Festlegung des Layouts definiert das XML-Dokument zwei graphische Komponenten: die eigentliche CellTable sowie eine SimplePager-Komponente. Für die Tabelle haben wir eine Seitengröße von 15 Elementen festgelegt, d.h. es werden jeweils 15 Songs angezeigt. Die Pager-Komponente erzeugt eine Navigationsleiste, über die der Benutzer zwischen den einzelnen Ergebnisseiten nach Belieben navigieren kann – diese Funktionalität bekommen wir praktisch zum Nulltarif.

Jede UIBinder XML-Datei ist mit einer Java-Klasse gleichen Namens verbunden. Hier ist die Logik zur Verwaltung der Komponenten implementiert. Über die ui:field-Attribute stellt der UIBinder eine Verknüpfung zu Feldern der Java-Klasse her: Die erzeugten Objekte werden automatisch in gleichnamige Felder, die mit der Annotation @UIField ausgezeichnet sind, injiziert. Listing 3 beinhaltet die zentralen Elemente der SongOverviewTable-Klasse.

Listing 3
public abstract class SongOverviewTable extends Composite {
private static SongOverviewTableUiBinder uiBinder =
GWT.create(SongOverviewTableUiBinder.class);

@UiField(provided = true)
final CellTable cellTable;

@UiField(provided = true)
final SimplePager pager;}

public SongOverviewTable() {
cellTable = new CellTable(KEY_PROVIDER);
SimplePager.Resources pagerResources =
GWT.create(SimplePager.Resources.class);
pager = new SimplePager(TextLocation.CENTER, pagerResources, false, 0,
true);
pager.setDisplay(cellTable);
initWidget(uiBinder.createAndBindUi(this));
initTableColumns();
}

private void initTableColumns() {
cellTable.setWidth("100%", true);
Column colName =
new Column(new TextCell()) {
public String getValue(SongInfo object) {
return object.getName();
}
};
cellTable.addColumn(colName);
cellTable.setColumnWidth(colName, 20, Unit.PCT);
// Add more columns...
}
interface SongOverviewTableUiBinder extends
UiBinder {
}
}

Der Quellcode enthält einige Elemente, die für die Nutzung des UIBinder-Frameworks erforderlich sind. Dazu gehören das leere von UIBinder abgeleitete Interface SongOverviewTableUIBinder sowie die statische uiBinder Variable. Der Aufruf der initWidget()-Methode im Konstruktor startet den UIBinder und löst die Initialisierung der Oberflächen-Komponenten aus.

Bei der Kurzbeschreibung des UIBinder-Mechanismus weiter oben ist eine wichtige Einschränkung unerwähnt geblieben: Das Framework kann nur Komponenten über ihren Standardkonstruktor erzeugen. Zum Anlegen der CellTable und der SimplePager-Komponente benötigen wir jedoch spezielle Konstruktoren. So wird der Tabelle ein KeyProvider übergeben – dazu später mehr -, und der Pager wird gleich mit einer Reihe von Parametern initialisiert. Prinzipiell lassen sich auch solche komplexen Initialisierungen bei Nutzung des UIBinders vornehmen. Die Konstruktoren müssen nur vom Client-Code selbst aufgerufen werden. Das provided-Attribut in der @UIField-Annotation teilt dem UIBinder-Framework mit, dass es sich nicht um die Erzeugung dieser Objekte zu kümmern braucht.

Das Anlegen der Spalten der Tabelle erfolgt in der Hilfsmethode initTableColumns(). Sie legt für jede Spalte eine Instanz der Klasse Column an und fügt sie der CellTable-Komponente hinzu. Column ist eine abstrakte Klasse; die Methode getValue()muss in abgeleiteten Klassen definiert werden. Der Rückgabewert der Methode wird an das Cell-Objekt der Spalte übergeben und schließlich zur Anzeige verwendet. Sowohl die CellTable– als auch die Column-Klasse definieren einen Typ-Parameter für das Datenobjekt, auf dem sie operieren. Dadurch ist ein typsicherer Zugriff auf einzelne Datenfelder möglich.

Noch eine Anmerkung zur Festlegung von Spaltenbreiten: initTableColumns()ruft als erstes setWidth()auf dem Tabellen-Objekt auf und legt über den booleschen Parameter true ein fixes Layout fest. Andernfalls würde die Tabelle ihre Breite an die Spalten anpassen, was bei dynamischem Nachladen von Daten zu Problemen führen kann. Den einzelnen Spalten muss auch jeweils eine Breite zugewiesen werden. Hier sind sowohl absolute als auch Prozentwerte erlaubt.

Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.