用Draw2D绘制UML图(译)

 
Copyright © 2003 International Business Machines Corp.

Eclipse Corner Article

Display a UML Diagram using Draw2D

用Draw2D绘制UML图

Summary 摘要
The Graphical Editing Framework (GEF) ships with a painting and layout plug-in called Draw2D. Draw2D provides figures and layout managers which form the graphical layer of a GEF application. This article focuses only on the use of Draw2D to render a simple UML class diagram. While Draw2D can be used for standalone purposes, it is not an editing framework. Most applications will use the GEF plug-in as the editing layer.

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

By Daniel Lee, IBM
August 25, 2003

Interpretted by Wayne
February 22, 2006



Introduction

介绍

Draw2d provides lightweight rendering and layout capabilities on an SWT Canvas. Figures, Layout Managers, and Borders can be combined and nested to create more complex figures to suit just about any application. Choosing the right combination of figures and layouts to create the desired effect can be a delicate task. This article will walk you through creating a complex figure.

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

Due to the scope of this article, the example code presented uses Draw2d in isolation, but most applications will use GEF and Draw2d together.

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

Creating the Draw2d Figure

创建Draw2D图形

An Example 示例

This article will be based upon the creation of the following Draw2d Figure, a simplified UML class diagram:

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

Designing the Figure 设计图形

The first step in the creation of a figure is to decide on the components that will comprise the figure, and how they will be arranged.

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

The example figure is composed of three children figures. The composition itself is named UMLClassFigure. Its first child, a Label figure, will display the class name (”Table” in this example). The next two children are containers for the class’ attributes and methods. We will create a figure called CompartmentFigure for this purpose. Both the class and compartment figures will use a ToolbarLayout to place their children. Here is a conceptual diagram of the overall structure:

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

Creating the CompartmentFigure Class

创建CompartmentFigure类

CompartmentFigure is used to hold both methods and attributes. This class extends org.eclipse.draw2d.Figure, and uses a ToolbarLayout to place its children. In addition, CompartmentFigure uses a custom border. This border simply paints a line 1 pixel in thickness across its top, to serve as the separator between the CompartmentFigures. The code for CompartmentFigure is as follows:

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());    }  }}

Creating the UMLClassFigure Class

创建UMLClassFigure类

The UMLClassFigure class is in many ways similar to the CompartmentFigure class. It contains three children — two CompartmentFigures for attributes and methods and a Draw2d Label to display the class name. It also uses a vertically oriented ToolbarLayout to place its children. UMLClassFigure uses Draw2d’s LineBorder to draw a box around its edges. The code for the UMLClassFigure class is as follows:

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;  }}

Adding a Connection

增加连接

Draw2d offers a special type of figure, called a connection, for connecting two figures. To create a connection in Draw2d, it is first necessary to establish the two endpoints of the connection. These endpoints are called the source and the target anchors. Endpoints are created using objects that implement the ConnectionAnchor interface. Once these anchors are created, they are set as endpoints via calls to the connection’s setSourceAnchor(ConnectionAnchor) and setTargetAnchor(ConnectionAnchor) methods. This is demonstrated below using a ChopboxAnchor. This type of anchor places the connection endpoint on the edge of the figure and causes it to point towards the figure’s center.

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

The following code demonstrates the addition of a connection:

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

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


Two UMLClassFigures connected by a PolyLineConnection

由PolyLineConnection连接的两个UMLClassFirgure

Adding a Decoration to the Connection

连接的装饰

Draw2d also provides means for endpoint decorations, such as arrow-tips. Staying with the UML theme, we will create a decoration that represents a composed relationship, which is shown in UML as a filled diamond. This is done using a PolygonDecoration. The default shape of a PolygonDecoration is a filled arrowhead, but any shape can be used by creating a template for the decoration using a PointList, and calling the PolygonDecoration’s setTemplate(PointList) method.

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

The following code demonstrates the addition of a PolygonDecoration to a Connection:

以下代码演示了如何将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);


Connection with a PolygonDecoration

具有PolygonDecoration的连接

Adding Labels to the Connection Using Locators

使用Locator给连接加上标签

In addition to decorations, it is possible to add other Draw2d figures to the connection itself. This is done by calling the connection’s add(IFigure figure, Object constraint) method where ‘figure’ is the figure that you wish to add, and ‘constraint’ is an object that implements the Locator interface. The Locator places the figure on the connection. We will use this technique to add labels to our class diagram. The ConnectionEndpointLocator will be used for these labels. This locator places its figure relative to the connection’s source or target endpoint. It allows the user to define the distance that the figure will appear relative to the end point via its setUDistance(int) and setVDistance(int) methods. (uDistance is the distance from the connection’s owner to the figure. vDistance is the distance from the figure to the connection itself).

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

The following code demonstrates the use of ConnectionEndpointLocators to add Labels to a Connection:

以下代码演示了如何使用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);


Adding Labels to the Connection

增加了标签的连接

Creating a Test Class

创建测试类

This class contains a main method that creates an SWT shell and places a Draw2d LightweightSystem on that shell. The LightweightSystem class provides the link between SWT and Draw2d. The test class creates a Draw2d figure to act as the contents of the LightweightSystem and adds two UMLClassFigures to this figure. It then connects the two class figures with a polyline connection, adds a diamond polygon decorator, and adds the UML relationship labels to the connection.

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

This class uses the following images: { }. Download them and place them at the root of a Java project directory.

测试类使用了几个图片{ },请自行下载并放在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(); }}

Conclusions

结论

This article has served as an introduction to the customized use of the Graphical Editing Framework’s visual component, Draw2d figures. The concepts of Draw2d connections, decorations, and locators have also been introduced. For more information on GEF, see the GEF website. (http://www.eclipse.org/gef).

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

Acknowledgements

感谢

The author would like to thank Randy Hudson and Eric Bordeau for providing constructive comments on the article.

感谢Randy Hudson和Eric Bordeau为本文提供的建设性意见。

Java and all Java-based trademarks and logos are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States, other countries, or both.

Technorati Tags: , ,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值