【原创】轻量级图形组件系统Draw2d(二十二)

  Draw2d提供了在SWT的Canvas上展现和布局的能力,GEF通过Draw2d实现GEF的视图(GEF的视图和插件的视图是完全不同的概念)。

  Draw2d简介

  Draw2d是基于SWT的轻量级组件系统。Draw2d的实例由SWT的组件、Lightweight- System和Draw2d的figures组成。

  SWT的组件是Draw2d的容器,figures是Draw2d中的图形,LightweightSystem是SWT和Draw2d的桥梁,如图1所示。

图1 LightweightSystem

  IFigure可以是图形,也可以是容器。IFigure对象中能加入其他的IFigure对象,通过IFigure的组合生成Draw2d的图形。创建Draw2d的程序步骤如下。

  (1)创建SWT的Canvas组件。

  (2)添加LightweightSystem实例。

  (3)添加IFigure实例。

  (4)把IFigure实例加入到LightweightSystem中。

  要想进行Draw2d的应用,读者应该先安装上GEF插件,添加Draw2d应用所依赖的jar包。

  Draw2d应用的简单实现

  一个简单的Draw2d实例可以由Canvas、LightweightSystem和IFigure组成,如例程1所示。

  例程1 HelloWorld.java

  package com.test.demo;

  import org.eclipse.swt.widgets.Shell;

  import org.eclipse.swt.widgets.Display;

  import org.eclipse.swt.SWT;

  import org.eclipse.draw2d.*;

  import org.eclipse.draw2d.geometry.*;

  public class HelloWorld {

  public static void main(String args[]){

  //新建Shell,Shell是Canvas的子类

  Shell shell = new Shell();

  shell.open();

  shell.setText("Draw2d Hello World");

  //添加LightweightSystem实例

  LightweightSystem lws = new LightweightSystem(shell);

  //添加IFigure实例

  IFigure label = new Label("Hello World");

  //把IFigure添加到LightweightSystem中

  lws.setContents(label);

  Display display = Display.getDefault();

  while (!shell.isDisposed ()) {

  if (!display.readAndDispatch ())

  display.sleep ();

  }

  }

  }

  上例中添加了一个“Hello World”的Label标签,程序运行后效果好像和SWT的程序没有区别,但本程序已经加入了Draw2d的实现,程序运行效果如图2所示。

图2 “Hello World”程序

  图形(Figure)

  图形(Figure)是Draw2d比较重要的部分,它提供了Draw2d中视图展现的实现,具体介绍如下。

  图形的功能

  在Draw2d中,IFigure对象代表图形,IFigure对象还能包含其他的IFigure对象,所有的IFigure对象组合成用户定制的图形,如图3所示。

图3组合图形

  图3为一个组合的图形。图中Table为一个底层的Figure,在Table的Figure上面加入了属性和方法的Figure,通过布局排列Figure的位置,如图4所示。

图4 Figure的组成

  Table的Figure为UMLClassFigure,属性和方法的Figure为CompartmentFigure,通过ToolbarLayout垂直排列Figure中的元素,Figure可以通过setLayoutManager方法设置当前图形中采用的布局方式。

  图形的实现

  通常用户可以继承Figure类实现自己的图形。Figure实现了IFigure接口,如例程2所示。

  例程2 KCGCommonFigure.java

  package com.free.table.editor.figure;

  import org.eclipse.draw2d.ColorConstants;

  import org.eclipse.draw2d.Figure;

  import org.eclipse.draw2d.FlowLayout;

  import org.eclipse.draw2d.Label;

  import org.eclipse.draw2d.LineBorder;

  import org.eclipse.draw2d.PositionConstants;

  import org.eclipse.swt.graphics.Image;

  public class KCGCommonFigure extends Figure {

  //在Figure中添加标签(标签也是Figure)

  protected Label label = new Label();

  public KCGCommonFigure(String fieldLabel, Image typeIcon) {

  //设置背景色

  setBackgroundColor(ColorConstants.tooltipBackground);

  //设置前景色

  setForegroundColor(ColorConstants.tooltipForeground);

  //设置Figure的边框

  setBorder(new LineBorder());

  //设置label中文字的对齐方式

  label.setTextAlignment(PositionConstants.LEFT);

  //设置label的图标

  label.setIcon(typeIcon);

  //设置Figure的布局方式

  setLayoutManager(new FlowLayout());

  //把label添加到Figure中

  add(label);

  //设置label的显示文字

  setLabelText(fieldLabel);

  }

  public void setLabelText(String newLabel){

  label.setText(newLabel);

  }

  }

  上例中实现了一个Figure,设置边框为LineBorder(边框类似为连线),另外还添加了一个Label作为显示的Figure,并设置为Label的显示文字和文字对齐方式,以及Figure的布局。

  连线(Connection)

  连线(Connection)是图形和图形之间的关系,Draw2d提供了一些连线的实现方式,具体介绍如下。

  连线的功能

  在图形的显示中,连线是比较常用的部分,它表现了图形和图形之间的关系,图形可以通过连线找到与其相关的图形。

  图形化应用程序的一个常见任务就是在两个图形之间建立连线。想象一下UML类图中的各种连接线,或者程序流程图中表示数据流的线条,它们有着不同的外观,有些连接线还要显示名称,而且最好能不交叉。

  利用Draw2d中的Router、Anchor和Locator,可以实现多种连接样式。其中Router负责连接线的外观和操作方式,最简单的是设置Router为null(无Router),这样会使用直线连接,其他连接方式包括折线、具有控制点的折线等,若想控制连接线不互相交叉也需要在Router中做文章。

  连线的实现

  Anchor控制连接线端点在图形上的位置,即“锚点”的位置,最易于使用的是ChopBoxAnchor,它先假设图形中心为连接点,然后计算这条假想连线与图形边缘的交汇点作为实际的锚点,其他Anchor,还有EllipseAnchor、LabelAnchor和XYAnchor等。

  Locator的作用是定位图形,例如希望在连接线中点处以一个标签显示此连线的名称,就可以使用MidpointLocator来帮助定位这个标签,其他Locator还有ArrowLocator用于定位可旋转的修饰(Decoration,例如PolygonDecoration)、BendpointerLocator用于定位连接控制点、ConnectionEndpointLocator用于定位连接端点(通过指定uDistance和vDistance属性的值可以设置以端点为原点的坐标)。

  实现简单图形的连接只要设置好连线对应的锚点即可,如例程3所示。

  例程3 Connection.java

  package com.test.demo;

  import org.eclipse.swt.SWT;

  import org.eclipse.swt.widgets.Shell;

  import org.eclipse.swt.widgets.Display;

  import org.eclipse.draw2d.*;

  import org.eclipse.draw2d.geometry.*;

  public class Connection {

  public static void main(String args[]){

  Shell shell = new Shell();

  shell.setSize(350,350);

  shell.open();

  shell.setText("Demo 4");

  LightweightSystem lws = new LightweightSystem(shell);

  IFigure panel = new Figure();

  lws.setContents(panel);

  //创建两个四边形的图形实例

  RectangleFigure

  node1 = new RectangleFigure(),

  node2 = new RectangleFigure();

  //设置node1的背景色

  node1.setBackgroundColor(ColorConstants.red);

  //设置node1的大小和位置

  node1.setBounds(new Rectangle(30, 30, 64, 36));

  //设置node2的背景色

  node2.setBackgroundColor(ColorConstants.blue);

  //设置node2的大小和位置

  node2.setBounds(new Rectangle(100, 100, 64, 36));

  //创建一个连线的实例

  PolylineConnection conn = new PolylineConnection();

  //设置连线起点的锚点

  conn.setSourceAnchor(new ChopboxAnchor(node1));

  //设置连线目标的锚点

  conn.setTargetAnchor(new ChopboxAnchor(node2));

  //设置连线目标的装饰器

  conn.setTargetDecoration(new PolygonDecoration());

  Label label = new Label("Midpoint");

  label.setOpaque(true);

  label.setBackgroundColor(ColorConstants.buttonLightest);

  label.setBorder(new LineBorder());

  //添加连线的Locator

  conn.add(label, new MidpointLocator(conn, 0));

  //在底层Figure中添加子Figure

  panel.add(node1);

  panel.add(node2);

  panel.add(conn);

  //添加node1拖动的监听器

  new Dragger(node1);

  //添加node2拖动的监听器

  new Dragger(node2);

  Display display = Display.getDefault();

  while (!shell.isDisposed()) {

  if (!display.readAndDispatch())

  display.sleep ();

  }

  }

  static class Dragger extends MouseMotionListener.Stub implements MouseListener {

  public Dragger(IFigure figure){

  figure.addMouseMotionListener(this);

  figure.addMouseListener(this);

  }

  Point last;

  public void mouseReleased(MouseEvent e){}

  public void mouseClicked(MouseEvent e){}

  public void mouseDoubleClicked(MouseEvent e){}

  public void mousePressed(MouseEvent e){

  last = e.getLocation();

  }

  public void mouseDragged(MouseEvent e){

  Point p = e.getLocation();

  Dimension delta = p.getDifference(last);

  last = p;

  Figure f = ((Figure)e.getSource());

  //设置拖动的Figure的位置

  f.setBounds(f.getBounds().getTranslated(delta.width, delta.height));

  }

  };

  }

  上例中,通过PolylineConnection建立了node1和node2的连线,并且设置了node1和node2拖动的监听器,用户可以拖动图形到窗口的任意位置,如图5所示。

图5 Draw2d的连线

  UML关系图实现

  Draw2d可以通过图形和连线表现图的关系,本节将用实例介绍如何通过图形和连线绘制UML的关系图。

  UML关系图实现的要求

  表关系实例中要包括表和列的UML图形(Figure),其中表和列又包含属性和方法子图形。表和列之间要建立一个一对多的关系连线,如图6所示。

图6 UML关系图

  从图6中可以看出,实例应该建立一个UML的Class图形,另外,Class图形中包括属性和方法的子图形,UML的Class图形之间通过连线连接。

  CompartmentFigure实现

  CompartmentFigure是方法和属性的图形,如图6所示。UML关系图中有四个CompartmentFigure图形,即每个UML的Class都包含两个CompartmentFigure图形。另外,图形还带边框,每一项属性和方法都有图标关联(图标是通过Label设置的)。CompartmentFigure的代码如例程4所示。

  例程4 CompartmentFigure.java

  package com.test.table;

  import org.eclipse.draw2d.AbstractBorder;

  import org.eclipse.draw2d.Figure;

  import org.eclipse.draw2d.Graphics;

  import org.eclipse.draw2d.IFigure;

  import org.eclipse.draw2d.ToolbarLayout;

  import org.eclipse.draw2d.geometry.Insets;

  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是UML Class的图形,如图6所示,UML关系图中有两个UMLClassFigure图形,其中每个UMLClassFigure中又包含两个CompartmentFigure。UMLClassFigure的代码如例程5所示。

  例程5 UMLClassFigure.java

  package com.test.table;

  import org.eclipse.draw2d.ColorConstants;

  import org.eclipse.draw2d.Figure;

  import org.eclipse.draw2d.Label;

  import org.eclipse.draw2d.LineBorder;

  import org.eclipse.draw2d.ToolbarLayout;

  import org.eclipse.swt.graphics.Color;

  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;

  }

  }

  连线及测试类

  如图6所示,连线中添加了装饰器用来表示一对多的菱形,以及用来描述关系的三个Locator(“1..*”、“1”和“contains”),另外每个标签都设置了相应的显示图标,代码如例程6所示。

  例程6 UMLClassFigureTest.java

  package com.test.table;

  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;

  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

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

  //新建连线

  PolylineConnection c = new PolylineConnection();

  //添加图形的锚点

  ChopboxAnchor sourceAnchor = new ChopboxAnchor(classFigure);

  ChopboxAnchor targetAnchor = new ChopboxAnchor(classFigure2);

  c.setSourceAnchor(sourceAnchor);

  c.setTargetAnchor(targetAnchor);

  //添加连线的装饰器

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

  //添加连线的Locator

  ConnectionEndpointLocator targetEndpointLocator =

  new ConnectionEndpointLocator(c, true);

  targetEndpointLocator.setVDistance(15);

  Label targetMultiplicityLabel = new Label("1..*");

  c.add(targetMultiplicityLabel, targetEndpointLocator);

  //添加连线的Locator

  ConnectionEndpointLocator sourceEndpointLocator =

  new ConnectionEndpointLocator(c, false);

  sourceEndpointLocator.setVDistance(15);

  Label sourceMultiplicityLabel = new Label("1");

  c.add(sourceMultiplicityLabel, sourceEndpointLocator);

  //添加连线的Locator

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

  }

  }

  通过上面的CompartmentFigure、UMLClassFigure和测试类UMLClassFigureTest实现了如图6所示的UML类关系图。

  另外,要运行Draw2d的应用,应该添加Draw2d实现的Jar包才能运行,,还应该在类的同一级目录下加上运行所需要的图片。

  Draw2d是基于SWT的轻量级组件系统,它是实现GEF视图的基础。在此只能概括性地介绍Draw2d的一些概念及实现,读者可以参考Draw2d的联机帮助文档,了解更多的实现。

  下载(com.free.draw2d.demo.rar)

image001.jpg

image002.jpg

image003.jpg

image004.jpg

image005.jpg

image006.jpg

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/13081368/viewspace-400051/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/13081368/viewspace-400051/

你可能感兴趣的:(【原创】轻量级图形组件系统Draw2d(二十二))