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/