用Draw2D绘制UML图(中文版)

来源:互联网 发布:送货单打印软件免费 编辑:程序博客网 时间:2024/06/05 07:42
Copyright © 2003 International Business Machines Corp.
Eclipse Corner Article

用Draw2D绘制UML图

摘要

图形编辑框架(GEF)运作于Draw2D之上。Draw2D是一个提供绘画和布局管理的插件,为GEF应用程序提供图形以及布局管理器来构建程序的图形表示层。本文仅着眼于如何使用Draw2D来绘制UML图。Draw2D可以独立使用,然而其并不是一个编辑框架。大多的应用程序会使用GEF插件实现编辑功能。


介绍

Draw2D提供了在SWT画布上绘画以及布局的轻量级实现。图形(Figure)、布局管理器(LayoutManager),以及边框(Border)可以被任意组合和内嵌来构建复杂的图形来适应任何的应用程序。选择正确的图形组合来创建想要的图形是一件很精细微妙的工作,本文将指导你如何创建一个复杂的图形。

由于本文的范围所限,本文的示例代码将独立使用Draw2D,但大多数的应用程序会将GEF和Draw2D结合使用。

创建Draw2D图形

示例

下图是一个简单的UML类图,本文建立在创建这个图形的基础之上。

设计图形

创建图形的第一步是确定使用什么组件来合成图形,以及它们是如何排列的。


例图由三个子图形组成。图形本身为UMLClassFigure,它的第一个子图形是Label,用来显示类名(本例为“Table”),另外两个子图形是用来放置属性及方法的容器。我们将创建一个叫做CompartmentFigure的图形来达到容器的目的。UMLClassFigure和CompartmentFigure都使用ToolbarLayout来放置子图形,下图是它在概念上的上层结构图:



创建CompartmentFigure类

CompartmentFigure用来放置方法和属性,这个类继承org.eclipse.draw2d.Figure类,并且使用ToolbarLayout来管理子图形的布局,同时,CompartmentFigure使用了一个自定义的边框。这个边框只是简单的在它的上端画一条1个象素粗细的线,作为两个CompartmentFigure的分隔。CompartmentFigure的代码如下:


public class CompartmentFigure extends Figure {

public CompartmentFigure() {
ToolbarLayout layout = new ToolbarLayout();
layout.setMinorAlignment(ToolbarLayout.ALIGN_TOPLEFT);
layout.setStretchMinorAxis(false);
layout.setSpacing(2);
setLayoutManager(layout);
setBorder(new CompartmentFigureBorder());
}

public class CompartmentFigureBorder extends AbstractBorder {
public Insets getInsets(IFigure figure) {
return new Insets(1,0,0,0);
}
public void paint(IFigure figure, Graphics graphics, Insets insets) {
graphics.drawLine(getPaintRectangle(figure, insets).getTopLeft(),
tempRect.getTopRight());
}
}
}

创建UMLClassFigure类

UMLClassFigure类在很多地方都和CompartmentFigure类很相似,它包含三个子图形——用来放置方法和属性的两个CompartmentFigure和一个用来显示类名的Draw2D标签(Label)。它也使用了垂直导向的ToolbarLayout来管理子图形的布局。UMLClassFirgure使用Draw2D的LineBorder在自己的边缘绘制矩形边框。


public class UMLClassFigure extends Figure {
public static Color classColor = new Color(null,255,255,206);
private CompartmentFigure attributeFigure = new CompartmentFigure();
private CompartmentFigure methodFigure = new CompartmentFigure();
public UMLClassFigure(Label name) {
ToolbarLayout layout = new ToolbarLayout();
setLayoutManager(layout);
setBorder(new LineBorder(ColorConstants.black,1));
setBackgroundColor(classColor);
setOpaque(true);

add(name);
add(attributeFigure);
add(methodFigure);
}
public CompartmentFigure getAttributesCompartment() {
return attributeFigure;
}
public CompartmentFigure getMethodsCompartment() {
return methodFigure;
}
}

增加连接

Draw2D提供了一种成为连接(Connection)特殊的图形,用来连接两个图形。要在Draw2D中创建连接,首先要创建连接的两个端点(endpoint)。这辆个端点成为源支撑点(source anchor)和目标支撑点(targetanchor)。端点由实现了ConnectionAnchor接口的类来创建。在支撑点创建好后,便可通过调用setSourceAnchor(ConnectionAnchor)方法和setTargetAnchor(ConnectionAnchor)方法来将其设定为端点。本例使用了称为ChopboxAnchor的支撑点,这种支撑点将端点放置在图形的边缘,并且将方向指向图形的中心。


以下代码增加了一个连接:

PolylineConnection c = new PolylineConnection();
ChopboxAnchor sourceAnchor = new ChopboxAnchor(classFigure);
ChopboxAnchor targetAnchor = new ChopboxAnchor(classFigure2);
c.setSourceAnchor(sourceAnchor);
c.setTargetAnchor(targetAnchor);
 



由PolyLineConnection连接的两个UMLClassFirgure

连接的装饰

Draw2d同时也为端点提供了箭头等形状的可以具有一定意义的装饰。和UML一样,我们将创建一个实心的菱形装饰来表示组合关系。这将由PolygonDecoration来实现。PolygonDecoration的缺省形状是实心箭头,然而可以通过创建新模板来实现任何形状。模板由PointList定义,通过调用setTemplate(PointList)来指定。


以下代码演示了如何将PolygonDecoration加到连接上去:


PolygonDecoration decoration = new PolygonDecoration();
PointList decorationPointList = new PointList();
decorationPointList.addPoint(0,0);
decorationPointList.addPoint(-2,2);
decorationPointList.addPoint(-4,0);
decorationPointList.addPoint(-2,-2);
decoration.setTemplate(decorationPointList);
c.setSourceDecoration(decoration);




具有PolygonDecoration的连接

使用Locator给连接加上标签

除了装饰之外,我们还可以给连接增加其他的Draw2d图形。这可以通过调用连接的add(IFigure figure, Objectconstratint)方法实现,其中figure为要增加的图形,constraint是一个实现了Locator接口的类,由Locator将图形放置在连接上。我们将使用这种技术来为我们的类图加上标签。ConnectionEndpointLocator可以将图形放置在连接的源端点或目标端点上,因而我们选用它来放置标签。我们还可以通过调用setUDistance(int)和setVDistance(int)方法来指定图形与端点的举例(其中uDistance是连接的图形到将要加上去的图形的距离,而vDistance则是将要加上的图形到连接本身的举例)。


以下代码演示了如何使用ConnectionEndpointLocator给一个连接加上标签:


ConnectionEndpointLocator targetEndpointLocator = 
new ConnectionEndpointLocator(c, true);
targetEndpointLocator.setVDistance(15);
Label targetMultiplicityLabel = new Label("1..*");
c.add(targetMultiplicityLabel, targetEndpointLocator);
ConnectionEndpointLocator sourceEndpointLocator =
new ConnectionEndpointLocator(c, false);
sourceEndpointLocator.setVDistance(15);
Label sourceMultiplicityLabel = new Label("1");
c.add(sourceMultiplicityLabel, sourceEndpointLocator);

ConnectionEndpointLocator relationshipLocator =
new ConnectionEndpointLocator(c,true);
relationshipLocator.setUDistance(30);
relationshipLocator.setVDistance(-20);
Label relationshipLabel = new Label("contains");
c.add(relationshipLabel,relationshipLocator);




增加了标签的连接


创建测试类

测试类包含了一个main方法来创建一个含有Draw2dLightweightSystem(LWS,用来连接SWT和Draw2d)的SWTShell。例子使用Draw2d的Figure类作为LWS的内容,并在Figure上增加了两个UMLClassFigure。然后在两个图形间创建了一个带有菱形端点装饰和标签的连接。


测试类使用了几个图片{ },请自行下载并放在java工程的根文件夹下。


import org.eclipse.draw2d.*;
import org.eclipse.draw2d.geometry.PointList;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

/**
* A test class to display a UMLFigure
*/
public class UMLClassFigureTest {
public static void main(String args[]){
Display d = new Display();
final Shell shell = new Shell(d);
shell.setSize(400, 400);
shell.setText("UMLClassFigure Test");
LightweightSystem lws = new LightweightSystem(shell);
Figure contents = new Figure();
XYLayout contentsLayout = new XYLayout();
contents.setLayoutManager(contentsLayout);

Font classFont = new Font(null, "Arial", 12, SWT.BOLD);
Label classLabel1 = new Label("Table", new Image(d,
UMLClassFigureTest.class.getResourceAsStream("class_obj.gif")));
classLabel1.setFont(classFont);

Label classLabel2 = new Label("Column", new Image(d,
UMLClassFigureTest.class.getResourceAsStream("class_obj.gif")));
classLabel2.setFont(classFont);

final UMLClassFigure classFigure = new UMLClassFigure(classLabel1);
final UMLClassFigure classFigure2 = new UMLClassFigure(classLabel2);

Label attribute1 = new Label("columns: Column[]", new Image(d,
UMLClassFigure.class.getResourceAsStream("field_private_obj.gif")));
Label attribute2 = new Label("rows: Row[]", new Image(d,
UMLClassFigure.class.getResourceAsStream("field_private_obj.gif")));
Label attribute3 = new Label("columnID: int", new Image(d,
UMLClassFigure.class.getResourceAsStream("field_private_obj.gif")));
Label attribute4 = new Label("items: List", new Image(d,
UMLClassFigure.class.getResourceAsStream("field_private_obj.gif")));

classFigure.getAttributesCompartment().add(attribute1);
classFigure.getAttributesCompartment().add(attribute2);
classFigure2.getAttributesCompartment().add(attribute3);
classFigure2.getAttributesCompartment().add(attribute4);

Label method1 = new Label("getColumns(): Column[]", new Image(d,
UMLClassFigure.class.getResourceAsStream("methpub_obj.gif")));
Label method2 = new Label("getRows(): Row[]", new Image(d,
UMLClassFigure.class.getResourceAsStream("methpub_obj.gif")));
Label method3 = new Label("getColumnID(): int", new Image(d,
UMLClassFigure.class.getResourceAsStream("methpub_obj.gif")));
Label method4 = new Label("getItems(): List", new Image(d,
UMLClassFigure.class.getResourceAsStream("methpub_obj.gif")));

classFigure.getMethodsCompartment().add(method1);
classFigure.getMethodsCompartment().add(method2);
classFigure2.getMethodsCompartment().add(method3);
classFigure2.getMethodsCompartment().add(method4);

contentsLayout.setConstraint(classFigure, new Rectangle(10,10,-1,-1));
contentsLayout.setConstraint(classFigure2, new Rectangle(200, 200, -1, -1));

/* Creating the connection */
PolylineConnection c = new PolylineConnection();
ChopboxAnchor sourceAnchor = new ChopboxAnchor(classFigure);
ChopboxAnchor targetAnchor = new ChopboxAnchor(classFigure2);
c.setSourceAnchor(sourceAnchor);
c.setTargetAnchor(targetAnchor);

/* Creating the decoration */
PolygonDecoration decoration = new PolygonDecoration();
PointList decorationPointList = new PointList();
decorationPointList.addPoint(0,0);
decorationPointList.addPoint(-2,2);
decorationPointList.addPoint(-4,0);
decorationPointList.addPoint(-2,-2);
decoration.setTemplate(decorationPointList);
c.setSourceDecoration(decoration);

/* Adding labels to the connection */
ConnectionEndpointLocator targetEndpointLocator =
new ConnectionEndpointLocator(c, true);
targetEndpointLocator.setVDistance(15);
Label targetMultiplicityLabel = new Label("1..*");
c.add(targetMultiplicityLabel, targetEndpointLocator);

ConnectionEndpointLocator sourceEndpointLocator =
new ConnectionEndpointLocator(c, false);
sourceEndpointLocator.setVDistance(15);
Label sourceMultiplicityLabel = new Label("1");
c.add(sourceMultiplicityLabel, sourceEndpointLocator);

ConnectionEndpointLocator relationshipLocator =
new ConnectionEndpointLocator(c,true);
relationshipLocator.setUDistance(10);
relationshipLocator.setVDistance(-20);
Label relationshipLabel = new Label("contains");
c.add(relationshipLabel,relationshipLocator);

contents.add(classFigure);
contents.add(classFigure2);
contents.add(c);

lws.setContents(contents);
shell.open();
while (!shell.isDisposed())
while (!d.readAndDispatch())
d.sleep();
}
}

结论

本文介绍了使用Graphical Editing Framework的可视化组件——Draw2d图形——的使用,同时也介绍了Draw2d连接、装饰、locator的概念。更多的信息请访问GEF主页(http://www.eclipse.org/gef


原创粉丝点击