<!--[if !supportLists]-->1 <!--[endif]-->模型:
<!--[if !supportLists]-->1.1 <!--[endif]-->图:
<!--[if !supportLists]-->1.2 <!--[endif]-->说明:Draw2D建构于SWT之上。Draw2D通过LightweightSystem沟通了SWT与Draw2D,LightweigthSystem主要负责两部分的工作:一是负责把SWT事件,转变为Draw2D内部的事件,这需要通过两步来实现,首先是把LightweigthSystem注册为Canvas的事件监听器,其次LightweightSystem需要记录系统内所有Figure的位置和尺寸信息,这样,当他收到事件通知以后才能把事件重新转发到对应的Figure上;二是负责管理Figure的更新和绘制,由于Draw2D并不是直接使用SWT提供的组件拼装Figure,而是自己定义了一套组件,当组件需要进行显示前,他会传入一个Draw2D自己定义的Graphics实现SWTGraphics,各Figure在这SWTGraphics上进行内容绘制,因此,与SWT中的组件不同,我们可以对Draw2D的Figure的绘制进行完全的定制。
在Draw2D当中,所有的图形,组件都通过Figure来表示,而Figure是设计成可以添加子Figure的,所以,在Draw2D当中,原则上所有的东西包括图形,控件等都能互相嵌套。
从上面的分析可得,虽然Draw2D建构于SWT之上,但是他使用的也仅是SWT提供的事件通知机制和绘图机制,所以,如果我们能够让Swing平台向Draw2D平台提供相同的服务的话,那么我们就能够在Swing之上实现Draw2D。
另外,Draw2D他自己重新实现了一套边框,布局,组件和图形的库,如果从重用的角度来说,这样显然是不合适的,因为这样就相当于他和SWT具有一个平行的类结构,而不是希望中的垂直结构;但是如果从耦合的角度来说。这样做显然是能最大限度的降低Draw2D与SWT之间的耦合程度。
<!--[if !supportLists]-->2 <!--[endif]-->Figure
<!--[if !supportLists]-->2.1 <!--[endif]-->Border
<!--[if !supportLists]-->2.1.1 <!--[endif]-->说明:每个Figure都可以具有边框,在Draw2D当中提供了以下的边框实现:GroupBoxBorder,TitleBarBorder,LineBorder,CompoundBorder等。由于CompoundBorder区分了innerBorder和outterBorder,所以,相同的两个Border的不同组合顺序将影响最后合成的Border的外观。
<!--[if !supportLists]-->2.1.2 <!--[endif]-->类图:
<!--[if !vml]--><!--[endif]-->
<!--[if !supportLists]-->2.1.3 <!--[endif]-->代码:
private void init() {
…
IFigure panel = new Figure();
ToolbarLayout layout = new ToolbarLayout();
layout.setSpacing(10);
panel.setLayoutManager(layout);
Panel[] panels = new Panel[8];
Border border = null;
Color red = new Color(null, 255, 0, 0);
for (int i = 0; i < panels.length; i++) {
panels[i] = new Panel();
panels[i].setLayoutManager(new BorderLayout());
panels[i].add(new Label("Label " + i), BorderLayout.BOTTOM);
panel.add(panels[i]);
switch (i) {
case 0:
border = new GroupBoxBorder("Group");
break;
case 1:
border = new TitleBarBorder("Title");
break;
case 2:
border = new FrameBorder("Frame");
break;
case 3:
border = new LineBorder(red);
break;
case 4:
border = new SchemeBorder(SchemeBorder.SCHEMES.RAISED);
break;
case 5:
border = new SimpleLoweredBorder(5);
break;
case 6:
border = new CompoundBorder(new LineBorder(red),
new TitleBarBorder("Title"));
break;
case 7:
border = new CompoundBorder(new TitleBarBorder("Title"),
new LineBorder(red));
break;
}
panels[i].setBorder(border);
}
lws.setContents(panel);
…
}
<!--[if !supportLists]-->2.1.4 <!--[endif]-->运行图:
<!--[if !vml]--><!--[endif]-->
<!--[if !supportLists]-->2.2 <!--[endif]-->Layout
<!--[if !supportLists]-->2.2.1 <!--[endif]-->说明:Layout用于对Figure内部的子Figure进行布局。
<!--[if !supportLists]-->2.2.2 <!--[endif]-->类图:
<!--[if !vml]--><!--[endif]-->
<!--[if !supportLists]-->2.2.3 <!--[endif]-->代码:
private void init() {
…
Color black = display.getSystemColor(SWT.COLOR_BLACK);
Color red = display.getSystemColor(SWT.COLOR_RED);
Color green = display.getSystemColor(SWT.COLOR_GREEN);
Panel[] panels = new Panel[3];
LayoutManager layout = null;
ToolbarLayout layouts = new ToolbarLayout();
layouts.setSpacing(10);
panel.setLayoutManager(layouts);
for (int i = 0; i < panels.length; i++) {
panels[i] = new Panel();
Label l1 = new Label("Label 1");
l1.setForegroundColor(red);
Label l2 = new Label("Label 2");
l2.setForegroundColor(green);
panels[i].add(l1);
panels[i].add(l2);
panels[i].setBorder(new LineBorder(black));
switch (i) {
case 0:
layout = new StackLayout();
break;
case 1:
layout = new XYLayout();
layout.setConstraint(l1, new Rectangle(10, 10, -1, -1));
layout.setConstraint(l2, new Rectangle(80, 40, -1, -1));
break;
case 2:
layout = new FlowLayout();
break;
}
panels[i].setLayoutManager(layout);
panel.add(panels[i]);
}
…
}
<!--[if !supportLists]-->2.2.4 <!--[endif]-->运行图:
<!--[if !vml]--><!--[endif]-->
<!--[if !supportLists]-->2.2.5 <!--[endif]-->补充:StackLayout会把组件在Z轴上堆叠起来。XYLayout需要对每个子组件添加对应的Constraint,用于设定其在界面上显示的位置和尺寸。
<!--[if !supportLists]-->3 <!--[endif]-->Shape
<!--[if !supportLists]-->3.1 <!--[endif]-->说明:Draw2D提供了代表主要几何图形的Figure,例如椭圆,矩形等。Draw2D中的几何图形与一般的SWT,Java 2D中的几何图形的一个非常主要的区别是,Draw2D中的几何图形是由Figure继承而来的,因此,我们可以为这些图形设定布局管理器,边框等,而且,当我们需要在图形内部添加图形时,我们是以一种父子关系树的方式添加的,而在其他的图形编程当中,当我们需要完成同样的功能时,我们使用的是图形覆盖的方式。还有另外的一点就是,由于Draw2D中的几何图形都是Figure,所以,我们需要使用处理一般控件的方式,即通过setSize()方法来设定他们的尺寸。而不是像在SWT和Java 2D当中那样,在构造函数中指明他的左上角坐标和尺寸。
<!--[if !supportLists]-->3.2 <!--[endif]-->Polyline:
<!--[if !supportLists]-->3.2.1 <!--[endif]-->说明:折线的Figure实现。
<!--[if !supportLists]-->3.2.2 <!--[endif]-->代码:
private void init() {
…
Polyline l1 = new Polyline();
for (int i = 0; i < 20; i++)
l1.addPoint(new Point(i * 20, i % 2 * 20));
panel.add(l1);
…
}
注:不能在Polyline上调用add()添加子Figure。
<!--[if !supportLists]-->3.2.3 <!--[endif]-->运行图:
<!--[if !vml]--><!--[endif]-->
<!--[if !supportLists]-->3.3 <!--[endif]-->Polygone:
<!--[if !supportLists]-->3.3.1 <!--[endif]-->说明:封闭多边形的Figure实现。
<!--[if !supportLists]-->3.3.2 <!--[endif]-->代码:
private void init() {
…
Polygon p1 = new Polygon();
PointList list = new PointList();
list.addPoint(0, 0);
list.addPoint(80, 80);
list.addPoint(240, 80);
list.addPoint(160, 0);
p1.setPoints(list);
Polygon p2 = new Polygon();
p2.addPoint(new Point(0, 0));
p2.addPoint(new Point(40, 40));
p2.addPoint(new Point(120, 40));
p2.addPoint(new Point(80, 0));
p2.setBackgroundColor(display.getSystemColor(SWT.COLOR_BLUE));
panel.add(p1);
p1.setLayoutManager(new FlowLayout());
p1.add(p2);
…
}
<!--[if !supportLists]-->3.3.3 <!--[endif]-->运行图:
<!--[if !vml]--><!--[endif]-->
<!--[if !supportLists]-->3.4 <!--[endif]-->RectangleFigure,RoundRectangle,Triangle,Ellipse:
<!--[if !supportLists]-->3.4.1 <!--[endif]-->说明:矩形,圆角矩形,三角形,椭圆的Figure实现。
<!--[if !supportLists]-->3.4.2 <!--[endif]-->代码:
private void init() {
…
Shape[] shapes = new Shape[4];
Color[] colors = new Color[] { ColorConstants.red,
ColorConstants.green, ColorConstants.blue,
ColorConstants.yellow };
for (int i = 0; i < shapes.length; i++) {
switch (i) {
case 0:
shapes[i] = new RectangleFigure();
break;
case 1:
shapes[i] = new RoundedRectangle();
break;
case 2:
shapes[i] = new Triangle();
break;
case 3:
shapes[i] = new Ellipse();
break;
}
shapes[i].setSize(100, 50);
shapes[i].setBackgroundColor(colors[i]);
panel.add(shapes[i]);
}
lws.setContents(panel);
…
}
<!--[if !supportLists]-->3.4.3 <!--[endif]-->运行图:
<!--[if !vml]--><!--[endif]-->
<!--[if !supportLists]-->4 <!--[endif]-->Widge
<!--[if !supportLists]-->4.1 <!--[endif]-->说明:Draw2D提供了部分控件的Figure实现,包括标签,按钮,复选框等。由于这些控件都是从Figure中继承而来,因此他们都能在内部添加子Figure。
<!--[if !supportLists]-->4.2 <!--[endif]-->Label:
<!--[if !supportLists]-->4.2.1 <!--[endif]-->说明:标签的Figure实现。
<!--[if !supportLists]-->4.2.2 <!--[endif]-->代码:
private void init() {
…
Label[] labels = new Label[50];
BorderLayout layout = null;
Random r = new Random();
Color color = null;
for (int i = 0; i < labels.length; i++) {
labels[i] = new Label();
color = new Color(null, r.nextInt(255), r.nextInt(255), r
.nextInt(255));
labels[i].setBorder(new LineBorder(color));
if (i > 0) {
layout = new BorderLayout();
labels[i - 1].setLayoutManager(layout);
labels[i - 1].add(labels[i], BorderLayout.CENTER);
}
}
lws.setContents(labels[0]);
…
}
<!--[if !supportLists]-->4.2.3 <!--[endif]-->运行图:
<!--[if !vml]--><!--[endif]-->
<!--[if !supportLists]-->4.3 <!--[endif]-->Button,ToggleButton,CheckBox:
<!--[if !supportLists]-->4.3.1 <!--[endif]-->说明:按钮,图钉,复选框的Figure实现。
<!--[if !supportLists]-->4.3.2 <!--[endif]-->代码:
private void init() {
…
Panel panel = new Panel();
ToolbarLayout tbl = new ToolbarLayout();
tbl.setSpacing(10);
panel.setLayoutManager(tbl);
Panel[] panels = new Panel[3];
FlowLayout layout = null;
IFigure figure = null;
for (int i = 0; i < panels.length; i++) {
panels[i] = new Panel();
layout = new FlowLayout();
panels[i].setLayoutManager(layout);
for (int j = 0; j < 4; j++) {
switch (i) {
case 0:
figure = new Button("Button " + j);
break;
case 1:
figure = new ToggleButton("ToggleButton " + j);
break;
case 2:
figure = new CheckBox("CheckBox " + j);
break;
}
panels[i].add(figure);
}
panel.add(panels[i]);
}
lws.setContents(panel);
…
}
<!--[if !supportLists]-->4.3.3 <!--[endif]-->运行图:
<!--[if !vml]--><!--[endif]-->
<!--[if !supportLists]-->4.4 <!--[endif]-->ScrollBar:
<!--[if !supportLists]-->4.4.1 <!--[endif]-->说明:滚动条的Figure实现。
<!--[if !supportLists]-->4.4.2 <!--[endif]-->代码:
private void init() {
…
ScrollBar t1 = new ScrollBar();
t1.setMinimum(0);
t1.setMaximum(100);
t1.setStepIncrement(1);
t1.setHorizontal(true);
t1.setForegroundColor(display.getSystemColor(SWT.COLOR_RED));
Image image = new Image(display, "icons/thumb.gif");
ImageFigure imagef = new ImageFigure(image);
imagef.setBorder(new LineBorder(1));
Button up = new Button();
up.setBackgroundColor(display.getSystemColor(SWT.COLOR_BLUE));
Button down = new Button();
down.setBackgroundColor(display.getSystemColor(SWT.COLOR_GREEN));
t1.setThumb(imagef);
t1.setPageUp(up);
t1.setPageDown(down);
…
}
<!--[if !supportLists]-->4.4.3 <!--[endif]-->运行图:
<!--[if !vml]--><!--[endif]-->
<!--[if !supportLists]-->5 <!--[endif]-->Layer and Panes
<!--[if !supportLists]-->5.1 <!--[endif]-->ScrollPane:
<!--[if !supportLists]-->5.1.1 <!--[endif]-->说明:滚动面板的Figure实现,他负责管理他内部的Figure的滚动。
<!--[if !supportLists]-->5.1.2 <!--[endif]-->代码:
private void init() {
…
ScrollPane sp = new ScrollPane();
sp.setSize(200, 50);
sp.setScrollBarVisibility(ScrollPane.ALWAYS);
Panel p = new Panel();
p.setLayoutManager(new ToolbarLayout());
Random r = new Random();
Label label = null;
for (int i = 0; i < 10; i++) {
label = new Label("Label " + i);
label.setForegroundColor(new Color(null, r.nextInt(255), r
.nextInt(255), r.nextInt(255)));
p.add(label);
}
panel.add(sp);
sp.setContents(p);
…
}
<!--[if !supportLists]-->5.1.3 <!--[endif]-->运行图:
<!--[if !vml]--><!--[endif]-->
<!--[if !supportLists]-->5.2 <!--[endif]-->ScalePane:
<!--[if !supportLists]-->5.2.1 <!--[endif]-->说明:能对面板内的内容进行拉伸。
<!--[if !supportLists]-->5.2.2 <!--[endif]-->代码:
private void init() {
…
ScrollBar bar = new ScrollBar();
bar.setHorizontal(true);
bar.setMinimum(0);
bar.setMaximum(10);
bar.setExtent(1);
bar.setStepIncrement(1);
bar.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
try {
int value = Integer.parseInt(evt.getNewValue().toString());
slp.setScale(value);
} catch (Exception e) {}
}
});
slp = new ScalableLayeredPane();
RectangleFigure rect = new RectangleFigure();
rect.setBackgroundColor(display.getSystemColor(SWT.COLOR_BLUE));
slp.add(rect);
panel.setLayoutManager(new BorderLayout());
panel.add(bar, BorderLayout.TOP);
panel.add(slp, BorderLayout.CENTER);
…
}
<!--[if !supportLists]-->5.2.3 <!--[endif]-->运行图:
<!--[if !vml]--><!--[endif]-->
<!--[if !vml]--><!--[endif]-->
<!--[if !supportLists]-->6 <!--[endif]-->Graphics
<!--[if !supportLists]-->6.1 <!--[endif]-->说明:在Figure被显示以前,他将调用paintFigure(),paintClientArea()和paintBorder()等方法,对他的内容以及子Figure进行绘画,通过重写这些方法,我们可以对Figure所显示的内容进行定制。
<!--[if !supportLists]-->6.2 <!--[endif]-->代码:
private void init() {
…
Panel panel = new Panel();
Label label = new Label("right") {
public void paintFigure(Graphics g) {
super.paintFigure(g);
String text = super.getText();
Image image = new Image(null, "icons/" + text + ".gif");
org.eclipse.swt.graphics.Rectangle rect = image.getBounds();
Color old = g.getForegroundColor();
Color red = new Color(null, 255, 0, 0);
g.setForegroundColor(red);
g.drawRectangle(new Rectangle(0, 0, rect.width, rect.height));
g.drawImage(image, 0, 0);
g.setForegroundColor(old);
}
};
panel.add(label);
lws.setContents(panel);
…
}
<!--[if !supportLists]-->6.3 <!--[endif]-->运行图:
<!--[if !vml]--><!--[endif]-->
<!--[if !supportLists]-->7 <!--[endif]-->Connection
<!--[if !supportLists]-->7.1 <!--[endif]-->说明:Connection提供了用于表示在两个Figure之间的连线。Draw2D提供了PolylineConnection实现类。
<!--[if !supportLists]-->7.2 <!--[endif]-->Anchor:
<!--[if !supportLists]-->7.2.1 <!--[endif]-->说明:当两个图形需要建立连线时,需要先添加用于连接的Anchor,然后在Connection上设定源和目标的Anchor。Draw2D提供了ChopboxAnchor(指向Figure中心),LabelAnchor(指向提供的Label),EllipseAnchor(指向提供的Ellipse),XYAnchor(指向提供的坐标)。
<!--[if !supportLists]-->7.2.2 <!--[endif]-->代码:
private void init() {
…
Panel panel = new Panel();
Button b1 = new Button("Button 1");
b1.setBackgroundColor(ColorConstants.green);
Button b2 = new Button("Button 2");
b2.setBackgroundColor(ColorConstants.yellow);
PolylineConnection con = new PolylineConnection();
ChopboxAnchor sor = new ChopboxAnchor(b1);
ChopboxAnchor tar = new ChopboxAnchor(b2);
con.setSourceAnchor(sor);
con.setTargetAnchor(tar);
XYLayout layout = new XYLayout();
layout.setConstraint(b1, new Rectangle(10, 10, -1, -1));
layout.setConstraint(b2, new Rectangle(80, 80, -1, -1));
panel.setLayoutManager(layout);
panel.add(b1);
panel.add(b2);
panel.add(con);
lws.setContents(panel);
…
}
<!--[if !supportLists]-->7.2.3 <!--[endif]-->运行图:
<!--[if !vml]--><!--[endif]-->
<!--[if !supportLists]-->7.3 <!--[endif]-->Decoration:
<!--[if !supportLists]-->7.3.1 <!--[endif]-->说明:当我们需要在连接上添加类似UML图中的聚合标签时,我们可以使用Decoration类。Draw2D提供了PolylineDecoration(折线)和PolygonDecoration(多边形)两个实现类。
<!--[if !supportLists]-->7.3.2 <!--[endif]-->代码:
private void init() {
…
PolygonDecoration dec = new PolygonDecoration();
PointList list = new PointList();
list.addPoint(0, 0);
list.addPoint(-1, 1);
list.addPoint(-2, 0);
list.addPoint(-1, -1);
dec.setTemplate(list);
con.setSourceDecoration(dec);
…
}
<!--[if !supportLists]-->7.3.3 <!--[endif]-->运行图:
<!--[if !vml]--><!--[endif]-->
<!--[if !supportLists]-->7.4 <!--[endif]-->Locator:
<!--[if !supportLists]-->7.4.1 <!--[endif]-->说明:由于Connection使用的是DelegatingLayout,所以,当我们需要为Connection添加子标签或者图形时,我们都需要指定一个用于布局的Locator。Draw2D提供了ArrowLocator,BendpointLocator,MidpointLocator,ConnectionEndPointLocator,RelativeLocator(相对于提供的某一Figure)实现。
<!--[if !supportLists]-->7.4.2 <!--[endif]-->代码:
private void init() {
…
ConnectionEndpointLocator tarL = new ConnectionEndpointLocator(con,
true);
tarL.setUDistance(5);
tarL.setVDistance(5);
Label sll = new Label("1..*");
con.add(sll, tarL);
…
}
<!--[if !supportLists]-->7.4.3 <!--[endif]-->运行图:
<!--[if !vml]--><!--[endif]-->
<!--[if !supportLists]-->7.5 <!--[endif]-->Routers:
<!--[if !supportLists]-->7.5.1 <!--[endif]-->说明:用于指定Connection的连接路线。Draw2D提供了FanRouter,(最短路径) ,BendpointConnectionRouter(随意插入节点),ManhattanConnecionRouter(曼哈顿式),ShortestPathConnectionRouter。
<!--[if !supportLists]-->7.5.2 <!--[endif]-->代码:
private void init() {
…
BendpointConnectionRouter rou = new BendpointConnectionRouter();
ArrayList<AbsoluteBendpoint> plist = new ArrayList<AbsoluteBendpoint>();
plist.add(new AbsoluteBendpoint(80, 50));
plist.add(new AbsoluteBendpoint(10, 70));
rou.setConstraint(con, plist);
con.setConnectionRouter(rou);
…
}
<!--[if !supportLists]-->7.5.3 <!--[endif]-->运行图:
<!--[if !vml]--><!--[endif]-->
<!--[if !supportLists]-->8 <!--[endif]-->DirectedGraph
<!--[if !supportLists]-->8.1 <!--[endif]-->说明:Draw2D通过DirectedGraph提供了一个图的抽象,我们通过指定DirectedGraph的节点和边列表,就可以完整的描述一个图,当我们需要把图在Figure上显示时,我们首先需要使用DirectedGraphLayout来对DirectedGraph进行布局,他会根据边的关系,来对各节点进行布局,并设定他们的坐标,因此当真正在Figure上进行布局时,我们只需获取这些点上的坐标即可。
<!--[if !supportLists]-->8.2 <!--[endif]-->代码:
public class DirectGraphDemo {
public DirectGraphDemo() {
…
Panel panel = new Panel();
panel.setLayoutManager(new XYLayout());
DirectedGraph graph = createGraph():
buildGraph(panel, graph);
lws.setContents(panel);
…
}
private DirectedGraph createGraph(){
NodeList nodelist = new NodeList();
Node node1 = new Node("node 1");
Node node2 = new Node("node 2");
Node node3 = new Node("node 3");
Node node4 = new Node("node 4");
nodelist.add(node1);
nodelist.add(node2);
nodelist.add(node3);
nodelist.add(node4);
EdgeList edgelist = new EdgeList();
edgelist.add(new Edge(node1, node2));
edgelist.add(new Edge(node2, node3));
edgelist.add(new Edge(node1, node4));
DirectedGraph graph = new DirectedGraph();
graph.nodes = nodelist;
graph.edges = edgelist;
new DirectedGraphLayout().visit(graph);
return graph;
}
private void buildGraph(IFigure contents, DirectedGraph graph) {
for (int i = 0; i < graph.nodes.size(); i++) {
Node node = graph.nodes.getNode(i);
buildNodeFigure(contents, node);
}
for (int i = 0; i < graph.edges.size(); i++) {
Edge edge = graph.edges.getEdge(i);
buildEdgeFigure(contents, edge);
}
}
private void buildNodeFigure(IFigure contents, Node node) {
Label label = new Label();
label.setBackgroundColor(ColorConstants.orange);
label.setOpaque(true);
label.setBorder(new LineBorder());
label.setText(node.data.toString());
contents.add(label);
contents.setConstraint(label, new Rectangle(node.x, node.y, node.width,
node.height));
}
private void buildEdgeFigure(IFigure contents, Edge edge) {
PolylineConnection connx = new PolylineConnection();
XYAnchor sourceAnchor = new XYAnchor(edge.start);
XYAnchor targetAnchor = new XYAnchor(edge.end);
connx.setSourceAnchor(sourceAnchor);
connx.setTargetAnchor(targetAnchor);
contents.add(connx);
}
public static void main(String[] args) {
DirectGraphDemo demo = new DirectGraphDemo();
}
}
<!--[if !supportLists]-->8.3 <!--[endif]-->运行图:
<!--[if !vml]--><!--[endif]-->