| Version 3.4.7 |
| Das Eclipse Graphical Editing Framework (GEF) |
Das Graphical Editing Framework (GEF) besteht
aus mehreren Eclipse Plugins, mit deren Hilfe graphische Editoren erstellt werden
können, um damit beliebige Datenmodelle zu visualisieren. Diese Bibliothek ist sehr
populär, so dass QF-Test die Aufnahme und Wiedergabe von GEF Elementen bereits seit
Version 2.2 unterstützt. Dies ist auch ein gutes Beispiel für die Stärke des
ItemResolver Konzepts (siehe Abschnitt 39.2), denn
das gef Jython Modul enthält eine Implementierung genau dieser
Schnittstelle. In älteren QF-Test Versionen musste das gef Modul noch
explizit mit Hilfe eines Skriptknotens eingebunden werden, doch mittlerweile geschieht
dies automatisch.
Das gef Modul verwendet GEF Editoren in generischer Weise und kann sogar
mit mehreren Editoren gleichzeitig umgehen. Allerdings gibt es Grenzen, was die
automatische Erkennung angeht: Je nachdem wie die zugrunde liegenden Modell-Klassen
aussehen, bleibt noch etwas Arbeit zu tun, nämlich die Implementierung eigener
Resolver, die brauchbare Namen und Werte für die Elemente liefern.
| Aufnahme von GEF Elementen |
Die folgenden Abschnitte nehmen Bezug auf das GEF Shapes Beispiel. Dieses erlaubt
es, Rechtecke, Ellipsen sowie Verbindungen zwischen den Figuren auf den
FigureCanvas zu zeichnen. Die Art der Figur wird dabei aus der Palette
ausgewählt, die ebenfalls zum GEF Editor gehört. Nehmen wir an, es wurde ein
Rechteck auf den Canvas gezeichnet und man nimmt mit QF-Test einen Mausklick darauf
auf. Ohne GEF ItemResolver erhält man einen 'Mausevent' Knoten
für die Canvas Komponente. Die Klickposition ist relativ zum Canvas und es gibt
nicht den kleinsten Hinweis, dass es das Rechteck war, das angeklickt wurde. Im
Gegensatz dazu wird mit registriertem GEF Resolver das Element als Ziel des Klicks
aufgenommen:
canvas@/ShapesDiagram\\\@1e1968d/Rectangle 16329001
Dem pfad-artigen Index kann man entnehmen, dass auf ein 'Rectangle' geklickt wurde,
welches selbst Teil eines 'ShapesDiagram' ist. Dieser Index ist nicht wirklich
schön. Viel schlimmer ist aber, dass er vollkommen wertlos ist. Warum ist das so? Die
Zahlen, die hier im Index auftauchen, sind beides Hashwerte, die sich ändern, wenn die
Anwendung neu gestartet wird und man die gespeicherte Zeichnung wieder öffnet. Wenn
man dann versucht, den Mausklick abzuspielen, läuft man in eine
IndexNotFoundException.
Mit etwas Glück sorgt Ihre GEF Anwendung jedoch für saubere Elementnamen, so dass etwa ein Index wie folgt herauskommt:
/ShapesDiagram/My blue rectangle
Wenn das nicht der Fall ist, gibt es drei Möglichkeiten:
/0/1 sagt nichts über das Element aus.
toString() für das
Datenmodell eines Elements zu liefern. Das würde Ihnen das Leben leicht machen,
aber eben nur, wenn die Entwickler kooperativ sind.
ItemNameResolver2 Schnittstelle. Das ist nicht
ganz einfach - doch leider wahrscheinlich nötig. Dieses Thema wird im nächsten
Abschnitt behandelt.
| Implementierung eines ItemNameResolver2 für GEF |
Im letzten Abschnitt haben wir gesehen, dass die Elemente im GEF Shapes Beispiel
keine brauchbaren Namen haben. Wie in Abschnitt 39.1
ausgeführt wird, ist ItemNameResolver2 die Schnittstelle, um Namen für
Elemente zu ändern oder überhaupt erst zu definieren.
Um anzufangen - sei es mit dem Shapes Beispiel oder der eigenen GEF Anwendung -, füge man ein Jython 'SUT Skript' mit dem folgenden Code in 'Extrasequenzen' ein:
|
|
|
|||
|
| Beispiel 39.12: Ein erster GEF ItemNameResolver2 | |||
Um die Installation des Resolvers zu vereinfachen, wird das in Abschnitt 39.1.10 beschriebene resolvers Modul verwendet. Der
Resolver wird auf die Klasse FigureCanvas registiert, dort liegen die
Elemente. Wie oben erwähnt liefert QF-Test normalerweise
item.getModel().toString() als Elementnamen. Diesen Wert erhält die
Funktion getItemName() beim Aufruf als drittes Argument. Wenn man das
Skript nun ausführt und dann den Aufnahmeknopf drückt, werden beim Überfahren der
Elemente - man sollte zuvor davon ein paar gezeichnet haben - Informationen im
Terminal von QF-Test ausgegeben, etwa so etwas:
name: Rectangle 16329001
item: org.eclipse.gef.examples.shapes.parts.ShapeEditPart
model: org.eclipse.gef.examples.shapes.model.RectangularShape
Abgesehen von den Ausgaben ist der Resolver ohne Funktion. Die Frage ist nun: Gibt
es im Datenmodell irgendeine Eigenschaft oder Methode, die einen vernüftigen Namen
für das Element liefert? Für das GEF Shapes Beispiel lautet die Antwort: Nein.
Hoffentlich sind Sie mit Ihrer Anwendung in einer besseren Lage. Um das
herauszufinden, fügen Sie der Funktion getItemName() die Zeile
print dir(model)
hinzu und führen das Skript erneut aus. Nun werden beim Bewegen der Maus über die
Elemente (im Aufnahmenmodus) auch die Methoden des Modells angezeigt. Mit etwas
Glück tauchen hier Methoden wie getName() oder getLabel()
auf, so dass man einen Resolver wie den folgenden implementieren kann.
|
|
|
|||
|
| Beispiel 39.13: Ein einfacher ItemNameResolver2 | |||
Zurück zum GEF Shapes Beispiel, wo es solche Methoden nicht gibt. Hier sind nur Informationen über die Geometrie verfügbar, doch das ist wenig hilfreich. Zumindest lassen sich aber Rechtecke und Ellipsen unterscheiden. Um die Elementnamen eindeutig zu machen, fügen wir einfach den Index der Figur (des Kind-Knotens) an, wie im folgenden Resolver gezeigt:
|
|
|
|||
|
| Beispiel 39.14: Ein ItemNameResolver2 für GEF Shapes | |||
Mit diesem Resolver wird der Element-Index zu etwas wie
/Diagram/Rectangle 1
wobei die abschließende Zahl der Index des Kind-Knotens ist. Diese Implementierung
liefert auch Namen für die Verbindungen, indem getItemName() rekursiv für
das Quell- und Zielelement aufgerufen wird. Die Typüberprüfung erfolgt mit der
Methode ResolverRegistry.isInstance (siehe Abschnitt 39.1.11), wodurch einem das Importieren der GEF-Klassen
(was nicht ganz einfach ist) erspart bleibt.
Sobald der Resolver funktionstüchtig ist, sollte man das Skript in die 'Vorbereitung' Sequenz packen, direkt hinter den 'Warten auf Client' Knoten. Auf diese Weise wird der Resolver automatisch registriert, wenn man das SUT startet.
| Implementierung eines ItemValueResolver2 für GEF |
Oben wurde bereits erwähnt, dass der GEF Editor normalerweise aus zwei Teilen
besteht. Bislang hatten wir uns auf den Canvas konzentriert, in den die Figuren
gezeichnet werden. Nun werfen wir einen Blick auf die Palette, in der die Art der zu
zeichnenden Figur ausgewählt wird (Rechteck, Ellipse oder Verbindung). Die Einträge
sehen zwar aus wie Buttons, doch tatsächlich ist die Palette ebenfalls ein
FigureCanvas. Erfreulicherweise funktioniert hier alles, ohne dass
besondere Vorkehrungen getroffen werden müssten, d.h. ohne einen
ItemNameResolver2 zu implementieren. Wenn man etwa auf den 'Rectangle'
Button klickt, erkennt QF-Test ein
/Palette Root/Palette Container (Shapes)/Palette Entry (Rectangle)
Element. Was wird wohl passieren, wenn man einen 'Object value' Check für diesen Button aufnimmt? Man könnte erwarten, den Text 'Rectangle' zu erhalten, doch tatsächlich ist der Wert des Elements
Palette Entry (Rectangle)
Der Grund dafür ist, dass Name und Wert eines Elements normalerweise gleich sind. Um
dieses Verhalten zu ändern und selbstdefinierte Werte zu erhalten, muss ein
ItemValueResolver2 implementiert werden. Diese Schnittstelle ist der
ItemNameResolver2 Schnittstelle ganz ähnlich. Für die Palette können
wir etwa das Folgende codieren:
|
|
|
|||
|
| Beispiel 39.15: Ein ItemValueResolver2 für die GEF Shapes Palette | |||
Die Methode getLabel() liefert den Text des Elements, so wie er in der
Palette angezeigt wird.
| Letzte Änderung: 23.04.2012 Copyright © 1999-2012 Quality First Software GmbH |