450 likes | 587 Views
Draw2d. Projektarbeit Software Engineering 12.11.2003 Von Olga Kiefel und Tobias Gunkel. Was ist Draw2d? - 1. Entsprang dem GEF-Projekt für Eclipse (Model – View – Controller) und ist im Lieferumfang von GEF enthalten Draw2d kann zusammen mit SWT auch außerhalb von Eclipse genutzt werden
E N D
Draw2d Projektarbeit Software Engineering 12.11.2003 Von Olga Kiefel und Tobias Gunkel
Was ist Draw2d? - 1 • Entsprang dem GEF-Projekt für Eclipse (Model – View – Controller) und ist im Lieferumfang von GEF enthalten • Draw2d kann zusammen mit SWT auch außerhalb von Eclipse genutzt werden • Erweiterung von SWT: bietet die Möglichkeit komplexe, zusammengesetzte grafische Komponenten zu erstellen
Das LightweightSystem • Um mit Draw2d arbeiten zu können, muss ein Objekt der Klasse LightweightSystem erzeugt werden.
Grundgerüst von Draw2d import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.draw2d.*; publicstaticvoid main(String[] args) { Display disp = new Display(); Shell shell = new Shell(disp); /* Dispatcher, UpdateManager und Root-Figure werden vom LWS erzeugt. / * Lediglich der Canvas muss übergeben werden (hier unsere Shell) */ LightweightSystem lws = new LightweightSystem(shell); // Diese Figure wird als Container für weitere Figures benutzt IFigure contents = new Figure(); // Container-Figure wird Inhalt des LWS und Kind der Root-Figure lws.setContents(contents); Figure rect = new RectangleFigure(); contents.add(rect); shell.open(); while(!shell.isDisposed()) { if(!disp.readAndDispatch()) disp.sleep(); } disp.dispose(); }
Figures – Die Hauptelemente • Grafische Elemente (Figures) implementieren das Interface IFigure • Jede Figure kann als Behälter für weitere Figures dienen • Hierarchie von Figures • Root-Figure des LightweightSystems ist die Wurzel der Hierarchie • Kinder einer Figure werden intern in einer Liste gehalten • Einfügen eines Kindes in die Liste entweder mittels • IFigure.add(IFigure child): Einfügen ans Ende der Liste oder • IFigure.add(IFigure child, int index): An Position índex einfügen • Nachträgliche Änderung der Position nur durch Entfernen und erneutes Einfügen • Gezeichnet wird beginnend mit der ersten Figure der Liste (mit Unterelementen), zum Schluss wird das letzte Element der Liste gezeichnet • Überlappen zwei Kinder, ist das Kind mit höherem Index vorne
RectangleFigure Figure rect = new RectangleFigure(); rect.setBounds(new Rectangle(200,200,50,50)); root.add(rect);
Rechteck mit Farbe und Text Figure rect = new RectangleFigure() rect.setBounds(new Rectangle(200, 200, 50, 50)); Label lab = new Label("Beispiel"); rect.add(lab); rect.setBackgroundColor(ColorConstants.blue); root.add(rect);
Beispiel: ImageFigure Image image = new Image(null, „bild.gif"); ImageFigure imf = new ImageFigure(image); • Konstruktur von Image verlangt ein Device und den Pfad des Bildes • Ist Device null, wird der Bildschirm genommen • Das Bild wird in einer ImageFigure gezeigt
Text mit Bild Label lbl = new Label("Beispiel", image); // Bild unten, Text oben anzeigen lbl.setTextPlacement(PositionConstants.EAST); • Dem Konstruktur wird der Text und das Bild übergeben • setTextPlacement verändert die Position von Bild und Text • Die Position bestimmt man mit den in PositionConstants definierten Konstanten NORTH, SOUTH, WEST, EAST • IFigure.setBackgroundColor setzt die Hintergrundfarbe • Analog setzt setForegroundColor die Textfarbe
Polyline und Polygon • Polyline-Objekte sind geschlossene Linienzüge • Unterschied Polygone zu Polyline: Polygon ist gefüllt • Übergabe der Stützpunkte entweder einzeln durch Polyline.addPoint(Point p) oder mittels setPoints(PointList pl) • Polygon/Polyline verwendet nicht die Werte, die mit setLocation oder setBounds übergeben wurden, sondern nur die Koordinaten der Punkte um Poly-Objekt nachträglich zu bewegen, muss jeder Punkt einzeln bewegt werden (oder die Klasse abgeleitet und setBounds überschrieben werden) kann nicht in LayoutManagern verwendet werden
Beispiel zu Polygon Polygon poly = new Polygon(); poly.addPoint(new Point(20,20)); poly.addPoint(new Point(60,20)); poly.addPoint(new Point(60,40)); poly.addPoint(new Point(10,40));
Connections • Verbinden zwei Figures durch eine Linie • Klasse, die dies tut, heißt PolylineConnection • Aussehen der Linie kann man durch Router beeinflussen • Anfangs- und Endpunkt der Verbindungslinie müssen über Anchors bestimmt werden (Connection.setSourceAnchor und Connection.setTargetAnchor)
Beispiel: PolylineConnection conn = new PolylineConnection(); conn.setSourceAnchor(new ChopboxAnchor(rect1)); conn.setTargetAnchor(new ChopboxAnchor(rect2));
PolygonDecoration oder PolylineDecoration können an eine Connection angefügt werden Eine Decoration hat standardmäßig das Aussehen eines Dreiecks Ändern des Umrisses durch Übergabe einer Liste von Punkten mit der Methode PolygonDecoration.setTemplate(PointList pl) Connection.setTargetDecoration(PolygonDecoration) setzt Decoration ans Ende der Verbindungslinie, mit setSourceDecoration an Anfang der Linie Decorations
Beispiel: PolygonDecoration deco = new PolygonDecoration(); // Umriss einer Raute durch PointList definieren PointList points = new PointList(); points.addPoint(0, 0); points.addPoint(-1, 3); points.addPoint(-2, 0); points.addPoint(-1,-1); // Umriss der Dekoration ändern deco.setTemplate(points); connection.setTargetDecoration(deco);
Locator • Bestimmt eine Position auf der Verbindungslinie • Kann genutzt werden, um eine Figure an der Linie anzuzeigen (Connection.add(IFigure f, Locator l) • Mehrere Klassen implementieren das Interface Locator, die wichtigsten sind: • ConnectionEndpointLocator: • Je nach Wert des zweiten Parameters im Konstruktur bestimmt Locator Anfangs- (false) oder Endposition (true) der Connection • Ein Offset kann der Position hinzugefügt werden (uDistance, vDistance) • MidpointLocator: bestimmt die Mitte der Connection
Beispiel: vDistance in Abhängigkeit des Verbindungswinkel: vDistance = vert. Achse vDistance = hor. Achse ConnectionEndpointLocator targetLocator = new ConnectionEndpointLocator(connection, true); //Entfernung vom Rechteck entlang der Verbindungslinie targetLocator.setUDistance(40); // vDistance = Entfernung von der Verbindungslinie bei // -45°–45° o. 135°-225°: auf vertikaler Achse oder bei // 45°-135° o. 225°-315°: auf horizontaler Achse targetLocator.setVDistance(100); Label label = new Label("Label"); // Label an die mit Locator bestimmte Stelle setzen connection.add(label, targetLocator);
Router • Ohne weitere Angaben verwendet PolylineConnection eine gerade Linie • Aussehen der Verbindung kann mit Routern geändert werden • FanRouter und BendpointConnectionRouter können geschachtelt werden (FanRouter.setNextRouter)
Beispiel . . . Definition einer Connection connection . . . BendpointConnectionRouter router = new BendpointConnectionRouter(); connection.setConnectionRouter(router); ArrayList list = new ArrayList(); // Ecke bei absoluter Koordinate (20, 20) list.add(new AbsoluteBendpoint(20, 20)); // Liste der Bendpoints für connection benutzen connection.setRoutingConstraint(list);
ToolTips • Werden angezeigt, wenn die Maus längere Zeit über einer Komponente schwebt • Sollen weitere Information zur Komponente liefern • Unter SWT nur textuelle ToolTips • Schon das Interface IFigure bietet die Methode zum setzen von ToolTips an • Jede grafische Komponente in Draw2d unterstützt ToolTips
Beispiel 1: normaler ToolTip mit Text . . . kreis.setToolTip(new Label("Dies ist ein ToolTip!")); . . . Beispiel 2: erweiterte Möglichkeiten eines Draw2d ToolTip ImageFigure imageFig = new ImageFigure(); imageFig.setImage(new Image(null, "tool.jpg")); ellipse.setToolTip(imageFig);
Nachrichtenverarbeitung durch Listener • Jede Figure kann Listener mit Figure.addXYZListener einbinden um Events zu behandeln • Listener von Draw2d nicht kompatibel mit denen von AWT oder SWT • Listener sind Interfaces alle Methoden müssen implementiert werden • Um Arbeit zu sparen gibt es Stubs (ähnlich den SWT-Adaptern, siehe Beispiel)
Die wichtigsten Listener • AncestorListener: • Methoden behandeln das Einfügen, Entfernen und Bewegen einer übergeordneten Figure (ancestor). • FigureListener: • Methode figureMoved wird aufgerufen, wenn Figure bewegt wurde • MouseListener: • Methoden werden aufgerufen bei Maustastendruck, Loslassen der Taste wurde Doppelklick • MouseMotionListener: • Methoden zur Reaktion auf Mausbewegungen über der Figure, Verlassen oder Eintreten in die Figure. • Bewegung der Maus mit gedrückter Taste durch mouseDragged gesondert behandelt • KeyListener: • Methoden werden aufgerufen, wenn Taste auf Keyboard gedrückt oder losgelassen wurde
Beispiel: class DragAndDrop { privatefinal Point oldPos = new Point(); public DragAndDrop() { owner.addMouseListener(newMouseListener.Stub() { publicvoid mousePressed(MouseEvent me) { me.consume(); oldPos.x = me.x; oldPos.y = me.y; } }); owner.addMouseMotionListener(newMouseMotionListener.Stub() { publicvoid mouseDragged(MouseEvent me) { Dimension diff = (new Point(me.x, me.y)).getDifference(oldPos); Figure owner = (Figure)me.getSource(); Point newPos = owner.getLocation().getTranslated(diff); owner.setLocation(newPos); oldPos.x = me.x; oldPos.y = me.y; } }); }}
Layout-Manager • Problem: Position und Größe der Kinder einer Figure äbhängig von Größe der Figure • Bounds müssen zur Laufzeit gesetzt werden • Layout-Manager bieten genau diese Funktionalität • LayoutManager können durch die Methode IFigure.setLayoutManager jeder Figure zugeordnet werden • Standard LayoutManager einer Figure ist das null-Layout; hierbei werden die mit setBounds und setLocation gesetzten Werte benutzt • Einige Layouts benötigen ein Constraint-Objekt (Anordnungsvorschrift) für jedes der Kinder • setzen beim Einfügen durch Figure.add(IFigure child, Object constraint) oder nachträglich durch LayoutManager.setConstraint(IFigure figure, Object constraint)
XYLayout • Ähnlich dem null-Layout-Manager • Unterschied: Position wird als Constraint übergeben • Nur wenn die Constraints einer Figure null sind, werden die mit setBounds gesetzten Werte genutzt
Beispiel: LayoutManager layout = new XYLayout(); figure.setLayoutManager(layout); . . . // fügt Ellipse in figure ein an Koordinaten //(0, 0) mit Breite = 150 und Höhe = 100 // Pixel Figure ellipse = new Ellipse(); Rectangle bounds = new Rectangle(0,0,150,100); figure.add(ellipse, bounds);
ToolbarLayout • Die Kinder der Figure werden entlang einer Hauptachse (vertikal oder horizontal) angeordet • Dabei werden die Kinder standardmäßig an der Nebenachse auf die Größe des Vaters gestreckt
FlowLayout • Teilt die Zeichenfläche der Figure in Zeilen bzw. Spalten auf • Die Unterelemente der Figure werden nun von links nach rechts bzw. von oben nach unten angeordnet • Ist eine Zeile/Spalte aufgefüllt, wird am Anfang der nächsten angefügt
Beispiel: LayoutManager layout = new FlowLayout(); figure.setLayoutManager(layout); . . . figure.add(new RectangleFigure()); figure.add(new Ellipse()); figure.add(new Button("Button"));
StackLayout • Jedes Unterelement wird auf die Breite und Höhe seines Vaters gestreckt • Kinder mit höherem Index in der Liste der Vater-Figure werden beim Zeichnen weiter nach vorne gesetzt
BorderLayout • Teilt die Zeichenfläche der Figure in die Regionen Top, Bottom, Left, Right und Center ein • Je nach Region, werden die Kinder auf einer Achse gestreckt • Das Center-Objekt bekommt den verbleibenden Platz in der Mitte, nachdem die Randbereiche besetzt wurden • In welcher Region ein Kind angezeigt werden soll, muss als Constraint übergeben werden
Beispiel: BorderLayout layout = new BorderLayout(); figure.setLayoutManager(layout); // Rechtecke top, bottom, left, right und center anlegen . . . figure.add(top, BorderLayout.TOP); figure.add(bottom, BorderLayout.BOTTOM); figure.add(left, BorderLayout.LEFT); figure.add(right, BorderLayout.RIGHT); figure.add(center, BorderLayout.CENTER);
Delegating Layout • Platzierung durch ein Locator-Objekt, das mittels einer relocate-Methode die Position und Größe eines Kindes bestimmt • Locator-Objekt muss Interface Locator implementieren und als Constraint übergeben werden • Positionierung und Größe der Kinder können von verschiedenen Faktoren abhängig gemacht werden (z.B. gewählter Ansichtsmodus)
Beispiel: LayoutManager layout = new DelegatingLayout(); figure.setLayoutManager(layout); . . . Figure rect = new RectangleFigure(); Locator locator = new Locator() { publicvoid relocate(IFigure target) { target.setBounds(new Rectangle(30, 20, 50, 50)); } }); figure.add(rect, locator);
Borders • Viele Grafikkomponenten werden ohne Umrandung angezeigt • Mit IFigure.setBorder kann für jedes Objekt einer Klasse, die IFigure implementiert, ein Rand eingefügt werden • Abmessungen hängen von der Größe der Figure ab, die entweder mit setBounds() oder durch einen LayoutManager gesetzt werden • Innenraum-Abmessungen über getInsets() • Erstellen neuer Ränder durch Ableiten der Klasse AbstractBorder und Implementierung der Methoden getInsets() und paint()
Beispiel FrameBorder: Label lbl = new Label("FrameBorder"); lbl.setBorder(new FrameBorder("FrameBorder")); Beispiel SchemeBorder: Label lbl = new Label("SchemeBorder2"); Color[] highlight = {ColorConstants.blue, ColorConstants.red}; Color[] shadow = {ColorConstants.white, ColorConstants.red}; lbl.setBorder(new SchemeBorder(new SchemeBorder.Scheme(highlight, shadow)));
Thumbnails • dienen als Vorschau von Grafikelementen (Figures) • Abbild der Quelle wird auf Größe des Thumbnails skaliert. Das Verhältnis von Breite zu Höhe bleibt erhalten • Thumbnail wird automatisch an Änderungen der Quelle angepasst • Ein Thumbnail sollte auf keinen Fall ein Element der Figure sein, die von dem Thumbnail als Vorschau angezeigt werden soll. Obwohl keine Fehlermeldung erscheint, versucht sich das Thumbnail selbst zu zeichnen • Wird mit 100% CPU-Auslastung bestraft
Beispiel: import org.eclipse.draw2d.parts.Thumbnail; . . . Figure ellipse = new Ellipse(); ellipse.setBounds(new Rectangle(20,20,50,50)); . . . Thumbnail tn = new Thumbnail(root); . . .
ScrollableThumbnail • ScrollableThumbnail zeigt im Thumbnail ein Auswahlrechteck an, mit dem die Ansicht des Quellfensters geändert werden kann • Konstruktor erwartet Viewport einer ScrollPane • ScrollableThumbnail darf nicht als Unterelement einer Figure eingefügt werden, die von dem Thumbail angezeigt werden soll
Beispiel: import org.eclipse.draw2d.parts.ScrollableThumbnail; . . . // Eine ScrollPane zum Anzeigen der Figure ScrollPane scroll = new ScrollPane(); . . . // neues Thumbnail, bei Auswahl eines Bereichs im Thumbnail // soll der Viewport der ScrollPane den neuen Bereich anzeigen ScrollableThumbnail thumb = new ScrollableThumbnail(scroll.getViewport()); // Das Thumbnail soll figure mit allen Unterelementen als // Vorschau anzeigen thumb.setSource(figure);