Draw2d: Unterschied zwischen den Versionen

Aus Eclipse
Wechseln zu: Navigation, Suche
(Verbindungen und Anker)
(Routing)
Zeile 203: Zeile 203:
  
 
=== Routing ===
 
=== Routing ===
 +
Wie man oben gesehen hat, zeichnet die ''PolylineConnection'' eine gerade Linie zwischen den von Anker festgelegten Punkten. Oft braucht man aber die Möglichkeit, die Linien anderer Formen zu zeichnen. In diesem Fall kann man eine neue Implementierung von ''Connection'' entwickeln. Es besteht aber eine einfachere Möglichkeit - das ''Connection''-Objekt mit einem ''ConnectionRouter'' zu parametrieren. ''ConnectionRouter'' ist ein Interface in draw2d, vom dem es mehrere fertige Implementierungen gibt:
  
 
== Anordnung ==
 
== Anordnung ==

Version vom 12. Juni 2010, 12:43 Uhr

Draw2d

Einführung

Draw2d ist ein auf Diagrammenzeichnung orientiertes Vektorgrafik-Toolkit für Eclipse. Es ist als Teil von GEF entstanden, kann aber unabhängig von GEF benutzt werden. Draw2d weist nicht so viele Möglichkeiten für eine komplizierte Grafikdarstellung auf, legt aber Akzent auf die in verschiedenen Diagrammentypen vorkommende Elemente wie z.B. rechteckige Blöcke mit Text oder Verbindungslinien jeglicher Art. Es bietet weiter die Möglichkeiten für eine automatische Anordnung der Elemente auf der Zeichnung sowie das sogenannte "Hit Testing" - die Erkennung des Elementes unter dem Mauszeiger.
Draw2d benutzt Standard Widget Toolkit (SWT, org.eclipse.swt) für das Rendering der Objekte.
Als Interface zwischen draw2d und SWT dient die Klasse org.eclipse.draw2d.LightweightSystem. Sie bietet die Möglichkeit, die draw2d-Objekte auf dem SWT-Canvas zu zeichnen, ohne das für die draw2d-Objekte OS-Ressourcen beansprucht werden (deswegen heißt die Klasse LightweightSystem).
Jedes sichtbare draw2d-Objekt ist eine Figur.

Packages

  • org.eclipse.draw2d - alle wichtigsten Klassen sind hier definiet.
  • org.eclipse.draw2d.geometry - Basisklassen für geometrische Objekte wie Punkte, Vektoren, Rechtecke usw.
  • org.eclipse.draw2d.graph - Klassen für die Graphendarstellung.
  • org.eclipse.draw2d.images
  • org.eclipse.draw2d.internal
  • org.eclipse.draw2d.parts - enthält im Moment eine Thumbnail-Figur. Das ist eine Figur, die eine andere Figur verkleinert darstellen kann.
  • org.eclipse.draw2d.text - diverse Klassen für die Textdarstellung.
  • org.eclipse.draw2d.widgets

Figuren (Figures)

Eine Figur in Draw2d ist alles, was das Interface IFigure implementiert, wobei es nicht empfohlen wird, in eigenen Klassen direkt dieses Interface zu implementieren, sondern eigene Klassen von existierenden Draw2d-Figuren abzuleiten.
Jede Figur ist ein Container für weitere Figuren. Man kann aus Figuren ganze Hierarchiebäume erzeugen. In der Praxis, für die Darstellung auf einem SWT-Canvas müssen alle Figuren sich in einem Baum befinden. Das Wurzelobjekt dieses Baums, das auch eine Figur ist, wird dem LightweightSystem übergeben.
Jede Figur hat bevorzugte Größe, minimale Größe und maximale Größe.
In der Methode paint muss eine Figur sich Zeichnen. Dafür hat sie die Methoden der abstrakten Klasse org.eclipse.draw2d.Graphics zur Verfügung.

"Hello world" in draw2d

In diesem Beispiel wird die Zusammenarbeit von SWT und draw2d demonstriert. Ausserdem sieht man hier, wie die Wurzelfigur für das LightweightSystem eingestellt wird und wie ein Figurenbaum entsteht.
In diesem Beispiel werden die SWT-Klassen Display und Shell benutzt. Weit SWT ausserhalb des Geltungsbereiches dieses Artikels ist, werden diese Klassen hier nicht weiter beschrieben. Siehe dazu die SWT-Dokumentation.

import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.draw2d.*;
 
public class draw2d_test {
 
	public static void main(String[] args) {
		Display display = new Display();
		Shell shell = new Shell(display);
 
		LightweightSystem lwSystem = new LightweightSystem(shell);
 
		IFigure contents = new Figure();
		LineBorder border = new LineBorder();
		border.setWidth(5);
		contents.setBorder(border);
 
		ToolbarLayout layout = new ToolbarLayout(false);
		layout.setSpacing(10);
		contents.setLayoutManager(layout);
 
		Label label = new Label("Hello world!!!");
		contents.add(label);
 
		shell.open();
 
		lwSystem.setContents(contents);
		while(!shell.isDisposed() )
		{
			if(!display.readAndDispatch() )
			{
				display.sleep();
			}
		}
 
		display.dispose();
	}
 
}


Das Output von diesem Beispiel sieht so aus:
Dratva 1919 example1 draw2d.png

In diesem Beispiel werden zwei Figuren erstellt, contents und label. Das label wird mit add an das contents angehängt, contents wird als Wurzelfigur im lwSystem gesetzt. Damit man die Wurzelfigur contents sehen kann, wird ihr ein dicker Rahmen hinzugefügt.

Zeichnungsreihenfolge und Überlappung der Figuren

Verbindungen und Routing

Verbindungen und Anker

Eine spezielle Art der Figuren sind die Verbindungen. Verbindungen müssen das Interface Connection implementieren, das das IFigure erweitert.
Diese Verbindungsfiguren stellen Verbindungslinien dar, die zwei Figuren miteinander verbinden. Der Verlauf einer solchen Linie wird von einem anderen Objekt - einem ConnectionRouter definiert.
Für die polygonartige Verbindungslinien existiert die Klasse org.eclipse.draw2d.PolylineConnection. Das ist die einzige Connection-Implementierung in draw2d. Diese Klasse wird auch im nächsten Beispiel verwendet.

 
	Label label1 = new Label("Label 1");
	LineBorder borderL1 = new LineBorder();
	label1.setBorder(borderL1);
	contents.add(label1);
 
	Label label2 = new Label("Label 2");
	label2.setBorder(borderL1);
	contents.add(label2);
 
	PolylineConnection connection = new PolylineConnection();
	connection.setSourceAnchor(new ChopboxAnchor(label1) );
	connection.setTargetAnchor(new ChopboxAnchor(label2) );
	contents.add(connection);


Dratva 1919 example2 draw2d.png



In diesem Beispiel sieht man, dass eine Verbindung zwei so genannte Anker braucht, um sicht richtig darzustellen. Ein Anker ist eine Implementierung des Interfaces ConnectionAnchor. Diese Anker werden nicht nur in PolylineConnection verwendet, sondern in jeder Connection-Implementierung. Die Methoden setSourceAnchor und setTargetAnchor sind nähmlich in diesem Interface definiert. Diese zwei Anker legen zwei Punkte fest, die von der Linie verbunden werden. Die Eigenschaften des hier verwendeten ChopboxAnchor werden im nächsten Beispiel besser demonstriert:

	Label label1 = new Label("Label 1");
	LineBorder borderL1 = new LineBorder();
	label1.setBounds(new Rectangle(10, 10, 100, 50) );
	label1.setBorder(borderL1);
	contents.add(label1);
 
	Label label2 = new Label("Label 2");
	label2.setBounds(new Rectangle(150, 150, 100, 50) );
	label2.setBorder(borderL1);
	contents.add(label2);
 
	PolylineConnection connection = new PolylineConnection();
	connection.setSourceAnchor(new ChopboxAnchor(label1) );
	connection.setTargetAnchor(new ChopboxAnchor(label2) );
	contents.add(connection);



Der Output von diesem Program sieht so aus:

Dratva 1919 example3 draw2d.png



Hier sieht man deutlich die Eigenschaften des in diesem Beispiel gewählten ChopboxAnchor. Die Linie wird zwischen Zentren der gewählten Figuren gezeichnet, wobei die Teile der Linie, die auf den Figuren selbst liegen, werden verborgen.

Neben dem ChopboxAnchor existieren in draw2d folgende vorgefertigten Implementierungen des ConnectionAnchor:

  • ConnectionAnchorBase - abstrakte Implementierung, die einen Listener-Mechanismus für die Verschiebung des Ankers anbietet.
  • XYAnchor - eine konkrete Implementierung, die eine feste Position für den Anker definiert, unabhängig von anderen draw2d-Objekten.
  • AbstractConnectionAnchor - abstrakte Basisklasse für alle Anker, deren Position von Eigenschaften einer Figur abhängig ist.
  • ChopboxAnchor - eine Implementierung von AbstractConnectionAnchor, die sich wie im obigen Beispiel verhält.
  • EllipseAnchor - auch eine Implementierung von AbstractConnectionAnchor, die ähnlich dem ChopboxAnchor ist. Der Unterschied ist die Art, wie der unsichtbare Teil der Linie festgelegt wird. Im Fall von EllipseAnchor ist es der der Ellipse, der in das Rechteck der Figur eingebettet ist, der die Grenze der Linie festlegt.



Wenn man das vorherige Beispiel auf folgende Weise modifiziert:

	Label label1 = new Label("Label 1");
	LineBorder borderL1 = new LineBorder();
	label1.setBounds(new Rectangle(10, 10, 100, 100) );
	label1.setBorder(borderL1);
	contents.add(label1);
 
	Label label2 = new Label("Label 2");
	label2.setBounds(new Rectangle(150, 150, 100, 100) );
	label2.setBorder(borderL1);
	contents.add(label2);
 
	PolylineConnection connection = new PolylineConnection();
	connection.setSourceAnchor(new EllipseAnchor(label1) );
	connection.setTargetAnchor(new EllipseAnchor(label2) );
	contents.add(connection);



sieht man, wir der EllipseAnchor funktioniert:

Dratva 1919 example4 draw2d.png



Die roten Kreise in diesem Bild sind nicht Teil der Figuren, sondern wurden auf dem Screenshot gezeichnet, um die Eingenschaften des EllipseAnchor darzustellen.

Im folgenden Beispiel wird eine freischwebende Linie mithilfe von XYAnchor gezeichnet:

	PolylineConnection connection = new PolylineConnection();
	connection.setSourceAnchor(new XYAnchor(new org.eclipse.draw2d.geometry.Point(10, 20) ) );
	connection.setTargetAnchor(new XYAnchor(new org.eclipse.draw2d.geometry.Point(100, 40) ) );
	contents.add(connection);



Dratva 1919 example5 draw2d.png

Routing

Wie man oben gesehen hat, zeichnet die PolylineConnection eine gerade Linie zwischen den von Anker festgelegten Punkten. Oft braucht man aber die Möglichkeit, die Linien anderer Formen zu zeichnen. In diesem Fall kann man eine neue Implementierung von Connection entwickeln. Es besteht aber eine einfachere Möglichkeit - das Connection-Objekt mit einem ConnectionRouter zu parametrieren. ConnectionRouter ist ein Interface in draw2d, vom dem es mehrere fertige Implementierungen gibt:

Anordnung