Eclipse GEF

来源:互联网 发布:mac怎么转换音频格式 编辑:程序博客网 时间:2024/04/30 06:08

刚开始学习Java的时候,许多书籍都用讲过是使用Java2D和AWT/Swing进行图形绘制,那时候认为java绘制出来的图形很丑,界面很灰,怎么看怎么不舒服,后来SWT可以根据操作系统的不同调用本地方法,使得界面看起来更舒服,之后是基于SWT的draw2D图形处理包,这个处理包使我们可以更加容易的绘制一些我们想要的图形。

那么Draw2D和GEF的关系是什么呢?GEF本身是一个更大的概念,官网给出大量的举例说明其是一个MVC图像处理框架,其中Model由我们自己根据业务来设计,它要能够提供某种模型改变通知的机制,用来把Model的变化告诉Control层;Control层由一些EditPart实现,EditPart是整个GEF的核心部件;而View层(大多数情况下)就是我们这里要说的Draw2D了,其作用是把Model以图形化的方式表现给使用者。

GEF框架用Draw2D作为自己的视图层,同样我们可以独立使用Draw2D。
如果对SWT有一定的了解,那么draw2D就是依托于SWT Canvas的一个轻量级图形组件。为什么说是轻量级呢?因为所有的图形组件可以用称为figures的java普通对象来表示,一个轻量级组件系统本身需要一个figure来与SWT Canvas关联,并且可以挂接大多数SWT事件监听器,并把这些监听器传送到事件转发器上,事件转发器的作用在于可以处理适当的figure动作。

figure是有父子关系的,并且有属于自己的边界,可以通过不同的布局来管理这些figure,通过更新管理机制可以对figure的形状大小等进行改变。
这里写图片描述
总结Draw2D具有以下特点:

有效地布局与呈现支持多种图形对象和布局实现图形边界光标和工具箱支持连接锚点, 连接路径, 连接装饰多样化的,透明层灵活的坐标系统视窗预览打印

轻量级图形组件LWS是连接SWT和Draw2D的桥梁,利用它,我们不仅可以轻松创建任意形状的图形(不仅仅限于矩形),同时能够节省系统资源(因为是轻量级组件)。一个典型的纯Draw2D应用程序代码具有类似下面的结构:

import org.eclipse.draw2d.ButtonGroup;import org.eclipse.draw2d.ButtonModel;import org.eclipse.draw2d.ChangeEvent;import org.eclipse.draw2d.ChangeListener;import org.eclipse.draw2d.CheckBox;import org.eclipse.draw2d.Clickable;import org.eclipse.draw2d.Figure;import org.eclipse.draw2d.Label;import org.eclipse.draw2d.LightweightSystem;import org.eclipse.draw2d.ToggleModel;import org.eclipse.draw2d.XYLayout;import org.eclipse.draw2d.geometry.Rectangle;import org.eclipse.swt.widgets.Display;import org.eclipse.swt.widgets.Shell;public class Draw2D_example {  public static void main(String args[]) {    final Label label = new Label("Press a button!");    Shell shell = new Shell();    LightweightSystem lws = new LightweightSystem(shell);    Figure parent = new Figure();    parent.setLayoutManager(new XYLayout());    lws.setContents(parent);    Clickable above = new CheckBox("I'm above!");    parent.add(above, new Rectangle(10, 10, 80, 20));    ButtonModel aModel = new ToggleModel();    aModel.addChangeListener(new ChangeListener() {      public void handleStateChanged(ChangeEvent e) {        label.setText("Above");      }    });    above.setModel(aModel);    Clickable below = new CheckBox("I'm below!");    parent.add(below, new Rectangle(10, 40, 80, 20));    ButtonModel bModel = new ToggleModel();    bModel.addChangeListener(new ChangeListener() {      public void handleStateChanged(ChangeEvent e) {        label.setText("Below");      }    });    below.setModel(bModel);    ButtonGroup bGroup = new ButtonGroup();    bGroup.add(aModel);    bGroup.add(bModel);    bGroup.setDefault(bModel);    parent.add(label, new Rectangle(10, 70, 80, 20));    shell.setSize(130, 120);    shell.open();    shell.setText("Example");    Display display = Display.getDefault();    while (!shell.isDisposed()) {      if (!display.readAndDispatch())        display.sleep();    }  }

Draw2D提供了很多缺省图形,最常见的有三类:1、形状(Shape),如矩形、三角形、椭圆形等等;2、控件(Widget),如标签、按钮、滚动条等等;3、层(Layer),它们用来为放置于其中的图形提供缩放、滚动等功能,在3.0版本的GEF中,还新增了GridLayer和GuideLayer用来实现”吸附到网格”功能。在以IFigure为根节点的类树下有相当多的类。
我们上例使用的类Clickable属于空间类,类定义:public class Clickable extends Figure可以看到其继承了Figure类,而Figure类实现了public class Figure implements IFigure接口。

每个图形都可以拥有一个边框(Border),Draw2D所提供的边框类型有GroupBoxBorder、TitleBarBorder、ImageBorder、ButtonBorder,以及可以组合两种边框的CompoundBorder等等,在Draw2D里还专门有一个Insets类用来表示边框在图形中所占的位置,它包含上下左右四个整型数值。

我们知道,一个图形可以包含很多个子图形,这些被包含的图形在显示的时候必须以某种方式被排列起来,负责这个任务的就是父图形的LayoutManager。同样的,Draw2D已经为我们提供了一系列可以直接使用的LayoutManager,如FlowLayout适合用于表格式的排列,如我们上述例子所用的XYLayout适合让用户在画布上用鼠标随意改变图形的位置,等等。如果没有适合我们应用的LayoutManager,可以自己定制。每个LayoutManager都包含某种算法,该算法将考虑与每个子图形关联的Constraint对象,计算得出子图形最终的位置和大小。

图形化应用程序的一个常见任务就是在两个图形之间做连接,想象一下UML类图中的各种连接线,或者程序流程图中表示数据流的线条,它们有着不同的外观,有些连接线还要显示名称,而且最好能不交叉。利用Draw2D中的Router、Anchor和Locator,可以实现多种连接样式,其中Router负责连接线的外观和操作方式,最简单的是设置Router为null(无Router),这样会使用直线连接,其他连接方式包括折线、具有控制点的折线等等(见图3),若想控制连接线不互相交叉也需要在Router中作文章。Anchor控制连接线端点在图形上的位置,即”锚点”的位置,最易于使用的是ChopBoxAnchor,它先假设图形中心为连接点,然后计算这条假想连线与图形边缘的交汇点作为实际的锚点,其他Anchor还有EllipseAnchor、LabelAnchor和XYAnchor等等;最后,Locator的作用是定位图形,例如希望在连接线中点处以一个标签显示此连线的名称/作用,就可以使用MidpointLocator来帮助定位这个标签,其他Locator还有ArrowLocator用于定位可旋转的修饰(Decoration,例如PolygonDecoration)、BendpointerLocator用于定位连接控制点、ConnectionEndpointLocator用于定位连接端点(通过指定uDistance和vDistance属性的值可以设置以端点为原点的坐标)。

下面举一个UML类图的例子,这个和例子是从网上找到的。
下图是一个简单的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)和目标支撑点(target anchor)。端点由实现了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, Object constratint)方法实现,其中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方法来创建一个含有Draw2d LightweightSystem(LWS,用来连接SWT和Draw2d)的SWT Shell。例子使用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(); }}

运行后如图所示,红色部分是本实例部分:
这里写图片描述

参考实例:http://blog.csdn.net/pengpeng2395/article/details/2952230
网址:http://www.eclipse.org/gef/draw2d/index.php
文章:http://www.cnblogs.com/bjzhanghao/archive/2005/02/13/104045.html

1 0
原创粉丝点击