八进制

少年壮志无烟抽

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  235 随笔 :: 0 文章 :: 3088 评论 :: 14 引用

鸡年第一天,首先向大家拜个年,恭祝新春快乐,万事如意。一年之计在于春,你对新的一年有什么安排呢?好的,下面还是进入正题吧。

关于Java2D相信大家都不会陌生,它是基于AWT/Swing的二维图形处理包, JDK附带的示例程序向我们展示了Java2D十分强大的图形处理能力。在Draw2D出现以前,SWT应用程序在这方面一直处于下风,而Draw2D这个SWT世界里的Java2D改变了这种形势。

可能很多人还不十分了解GEF和Draw2D的关系:一些应用程序是只使用Draw2D,看起来却和GEF应用程序具有相似的外观。原因是什么,下面先简单解释一下:

GEF是具有标准MVC(Model-View-Control)结构的图形编辑框架,其中Model由我们自己根据业务来设计,它要能够提供某种模型改变通知的机制,用来把Model的变化告诉Control层;Control层由一些EditPart实现,EditPart是整个GEF的核心部件,关于EditPart的机制和功能将在以后的帖子里介绍;而View层(大多数情况下)就是我们这里要说的Draw2D了,其作用是把Model以图形化的方式表现给使用者。

虽然GEF可以使用任何图形包作为View层,但实际上GEF对Draw2D的依赖是很强的。举例来说:虽然EditPart(org.eclipse.gef.EditPart)接口并不要求引入任何Draw2D的类,但我们最常使用的AbstractGraphicalEditPart类的createFigure()方法就需要返回IFigure类型。由于这个原因,在GEF的SDK中索性包含了Draw2D包就不奇怪了,同样道理,只有先了解Draw2D才可能掌握GEF。

这样,对于一开始提出的问题可以总结如下:Draw2D是基于SWT的图形处理包,它适合用作GEF的View层。如果一个应用仅需要显示图形,只用Draw2D就够了;若该应用的模型要求以图形化的方式被编辑,那么最好使用GEF框架。

现在让我们来看看Draw2D里都有些什么,请看下图。


图1 Draw2D的结构

Draw2D通过被称为LightweightSystem(以下简称LWS)的部件与SWT中的某一个Canvas实例相连,这个Canvas在Draw2D应用程序里一般是应用程序的Shell,在GEF应用程序里更多是某个Editor的Control(createPartControl()方法中的参数),在界面上我们虽然看不到LWS的存在,但其他所有能看到的图形都是放在它里面的,这些图形按父子包含关系形成一个树状的层次结构。

LWS是Draw2D的核心部件,它包含三个主要组成部分:RootFigure是LWS中所有图形的根,也就是说其他图形都是直接或间接放在RootFigure里的;EventDispatcher把Canvas上的各种事件分派给RootFigure,这些事件最终会被分派给适当的图形,请注意这个RootFigure和你应用程序中最顶层的IFigure不是同一个对象,前者是看不见的被LWS内部使用的,而后者通常会是一个可见的画布,它是直接放在前者中的;UpdateManager用来重绘图形,当Canvas被要求重绘时,LWS会调用它的performUpdate()方法。

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

//创建SWT的Canvas(Shell是Canvas的子类)
Shell shell = new Shell();
shell.open();
shell.setText(
"A Draw2d application");
//创建LightweightSystem,放在shell上
LightweightSystem lws = new LightweightSystem(shell);
//创建应用程序中的最顶层图形
IFigure panel = new Figure();
panel.setLayoutManager(
new FlowLayout());
//把这个图形放置于LightweightSystem的RootFigure里
lws.setContents(panel); 

//创建应用程序中的其他图形,并放置于应用程序的顶层图形中
panel.add();
while (!shell.isDisposed ()) {
if (!display.readAndDispatch ())
   display.sleep ();
}

接下来说说图形,Draw2D中的图形全部都实现IFigure(org.eclipse.draw2d.IFigure)接口,这些图形不仅仅是你看到的屏幕上的一块形状而已,除了控制图形的尺寸位置以外,你还可以监听图形上的事件(鼠标事件、图形结构改变等等,来自LWS的EventDispatcher)、设置鼠标指针形状、让图形变透明、聚焦等等,每个图形甚至还拥有自己的Tooltip,十分的灵活。

Draw2D提供了很多缺省图形,最常见的有三类:1、形状(Shape),如矩形、三角形、椭圆形等等;2、控件(Widget),如标签、按钮、滚动条等等;3、层(Layer),它们用来为放置于其中的图形提供缩放、滚动等功能,在3.0版本的GEF中,还新增了GridLayer和GuideLayer用来实现"吸附到网格"功能。在以IFigure为根节点的类树下有相当多的类,不过我个人感觉组织得有些混乱,幸好大部分情况下我们只用到其中常用的那一部分。


图2 一个Draw2D应用程序

每个图形都可以拥有一个边框(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属性的值可以设置以端点为原点的坐标)。


图3 三种Router的外观

此外,Draw2D在org.eclipse.draw2d.geometry包里提供了几个很方便的类型,如Dimension、Rectangle、Insets、Point和PointList等等,这些类型既在Draw2D内部广泛使用,也可以被开发人员用来简化计算。例如Rectangle表示的是一个矩形区域,它提供getIntersection()方法能够方便的计算该区域与另一矩形区域的重叠区域、getTransposed()方法可以得到长宽值交换后的矩形区域、scale()方法进行矩形的拉伸等等。在自己实现LayoutManager的时候,由于会涉及到比较复杂的几何计算,所以更推荐使用这些类。

以上介绍了Draw2D提供的大部分功能,利用这些我们已经能够画出十分漂亮的图形了。但对大多数实际应用来说这样还远远不够,我们还要能编辑它,并把对图形的修改反映到模型里去。为了漂亮的完成这个艰巨任务,GEF绝对是不二之选。从下一次开始,我们将正式进入GEF的世界。

参考资料:

posted on 2005-02-09 21:49 八进制 阅读(13664) 评论(48)  编辑 收藏 网摘 所属分类: EclipseGEF

评论

#1楼  2005-03-22 19:08 howjay [未注册用户]
关于Connection,想和您探讨一下。不知道你有没有用过Visio或者一些流程图软件,里面有表示“循环”的线的Anchor是连接在两个Node的旁边的。我想作出类似的效果。然后发现使用BendpointRouter的话可以画出折线。但是一开始的时候线是直的。

然后我又尝试XYAnchor,有那么一点意思,不过移动Node的时候Connection并不随着移动。

其实根本意思也就是一个Node的上面的锚点能够自定义,在GEF里点击一个Node不是边框上有8个点吗,不知道怎样才能自由的把Connection连接到这8个点上?

同理这里你给出的那个图,里面的结点有自定以的3个锚点,不知道是怎样做出来的呢?
  回复  引用    

#2楼  2005-03-22 20:15 howjay [未注册用户]
我想起来了,这是Logic的例子。我正在看源码。

不知道你还没有什么其它的建议?
  回复  引用    

#3楼 [楼主] 2005-03-22 21:04 八进制      
这个问题我以前没研究过,因为现在做的项目里不需要有连接(Connection),呵呵,连接只做过最简单的。 刚才我看了一下,应该是继承AbstractConnectionAnchor类,然后把这些实例加到作为Node的Figure上,即figure维护一个anchor列表,然后在你的继承NodeEditPart的子类中,实现getSourceConnectionAnchor和getTargetConnectionAnchor方法。 你可以试试看。
  回复  引用  查看    

zoomIn 和 zoomOut 是否可以作用于 images 对象呢?每个 image 都是一个新创建的类的实例。 我试着做 zoom, 可是只有 connections 之类的元素积极响应, 我原有的那些 image icons 却都消失了。

有谁可以给些指导和建议吗? 谢过了先。
  回复  引用    

怎样控制图形间的距离和连接线的长度呢? ^_^???

谢谢答复。
  回复  引用    

还有我用的是manhattan router,怎样控制 connection 不交叉呢?
  回复  引用    

#7楼 [楼主] 2005-07-23 00:20 八进制      
图形间的距离就是由两个图形的位置决定的,连接线的长度是由图形间距离和连接线的router决定。要让connection不交叉得自己扩展manhattan router,而且有些情况是必须存在交叉的。
  回复  引用  查看    

#8楼  2005-08-23 17:04 吴陶 [未注册用户]
我希望进一步研究,请问能够提供一些参考资料吗?

谢谢拉

  回复  引用    

#9楼  2005-08-23 17:20 吴陶 [未注册用户]
www.elcipse.org/gef

www.eclipse.org/emf
  回复  引用    

#10楼  2005-12-01 16:20 sealin [未注册用户]
请问,在lws上面只能放置IFigure类型吗?
如果是一个composite/canvas/panel, 如何通过lws显示出来呢?

比如:
Composite composite = new Composite(_parent, SWT.BORDER);
composite.setLayout(new FillLayout());
FigureCanvas canvas = new FigureCanvas(composite);

Panel contents = new Panel();
contents.setLayoutManager(new XYLayout());
initializeSpan(contents.getClientArea());

populateNodesAndEdges();

drawAxis(contents);
for(int i=0; i<_numSeries; i++){
drawDotsAndConnections(contents,getDirectedGraph(i)); // draw the points and connecting wires.
}
canvas.setBackground(ColorConstants.black);
canvas.setContents(contents);

其中用到Draw2d,如何显示出来呢?
  回复  引用    

#11楼 [楼主] 2005-12-01 19:47 八进制      
据我所知lws和IFigure上不能放Composite。
  回复  引用  查看    

#12楼  2005-12-15 13:42 小叶子 [未注册用户]
请问在图形部分,怎么划出椭圆上的线,我画椭圆是这样画的,怎么在椭圆的上半部分划一条线?
Rectangle r = getBounds().getCopy();
Dimension SIZE = this.getSize();

g.setLineStyle(Graphics.LINE_DASHDOTDOT);

g.setBackgroundColor(new Color(null, 250,230,210
g.fillOval(r);

g.drawOval(r);

  回复  引用    

#13楼 [楼主] 2005-12-15 19:25 八进制      
Graphics#drawLine(),坐标需要自己算。
  回复  引用  查看    

#14楼  2005-12-16 10:40 小叶子 [未注册用户]
谢谢,经过你的指导,我搞定了,呵呵
  回复  引用    

#15楼  2006-02-15 14:38 wd [未注册用户]
问一下draw2d跟java2d有什么区别和联系吗?
  回复  引用    

#16楼 [楼主] 2006-02-15 16:12 八进制      
它们都是画图用的,draw2d在提供了java2d的画点画线等基本功能的基础上,还提供了Figure,以及基于Figure实现的Layer等概念,更适合图形化编辑的需要。
draw2d是基于swt的,java2d基于awt,这可能是最大的区别。
  回复  引用  查看    

#17楼  2006-03-06 14:30 Gef kid [未注册用户]
如何用GEF画 line 呢?

碰到一个问题, 就是需要一个画直线的工具, 但是目前只看到connection 的功能, 也就是线的两端, 一定会有node的存在. 我只是要画直线, 两端不需要有node的. 有什幺editpolicy 或class适合使用的吗?

谢谢
  回复  引用    

#18楼 [楼主] 2006-03-06 17:08 八进制      
和画Rectangle一样,只是figure变成了直线:-)
  回复  引用  查看    

#19楼  2006-03-07 10:41 Gef kid [未注册用户]
@Gef kid
如何用GEF画 line 呢?

谢谢你的回复. 但是如果用画figure的方式会碰到一个问题. 如果仔细看, 但我们在移动figure的constraint时, constraint至多能够被resize 到面积为0. 但是如果将一条 东北-西南 方向的线, drag 成 西北-东南 方向的线时, constraint一定会先被resize成0, 再从反方向增加面积. 而这个过程会在面积被resize成0的时候中断. 这也是为什幺我想试着从anchor的方向着手…不知道XYAnchor能不能解决这方面的问题…

  回复  引用    

#20楼 [楼主] 2006-03-07 21:10 八进制      
是的,我发现自己想得简单了,如果考虑polyline会更复杂些。我觉得可以确定Editpart对应的figure是直线,但要求它只在两端具有两个handle,这个可以通过修改editpolicy实现,可惜我没有时间试验一下。这个链接你看看有没有用http://dev.eclipse.org/newslists/news.eclipse.tools.gef/msg08443.html
  回复  引用  查看    

#21楼  2006-03-08 14:35 Gef kid [未注册用户]
恩, 昨天尝试使用XYAnchor 来实作, 必须要在对应的editpart 实作下面的function. 同时增加相关的editpolicy 和 command

public ConnectionAnchor getSourceConnectionAnchor(ConnectionEditPart connection)
public ConnectionAnchor getTargetConnectionAnchor(ConnectionEditPart connection)
public ConnectionAnchor getSourceConnectionAnchor(Request request)
public ConnectionAnchor getTargetConnectionAnchor(Request request)
protected List getModelSourceConnections()
protected List getModelTargetConnections()

现在开始要想, 是否能改变line width, 以及拖拉line的时候, 能否有feedback的效果? 我也会去eclipse forum那边问问看, 谢谢


  回复  引用    

to gef kid and 八进制

按我的理解,连线的两端位置的确定就是由线的Anchor 的gefLocation 的方法确定的。

 你自己写一个Anchor 覆盖gefLocation方法, 返回的是
  request.getLocation().

  可能就可以解决你所说的问题了。

  回复  引用    

#23楼  2006-09-10 05:33 Beginner [未注册用户]
Hi 小叶子,

请问你的 Graphics 是怎么来的.
可以show这段程序参考参考吗?

因为我想基于graphics这个类使用g.fillOval() method.
麻烦了,谢谢哦
  回复  引用    

请问:哪位朋友有连接线中点处以一个标签显示此连线的名称/作用,并且可以编辑的例子啊?急盼回复!!!
  回复  引用    

#25楼  2007-03-09 05:33 Hzfalcon [未注册用户]
请教lz两个问题,在这章最开始的代码里面,主线程里面display对象是没有被
申明的。。所以。。。。

1. 这段代码里面是不是还应该有一句 Display display = new Display().getDefault() ?

2. Shell对象到底是不是一定要以 new Shell(display) 方式建立?

这些问题很初级,但是因为从来没有涉足过 desktop app 得开发,所以请
不要见笑。 谢谢
  回复  引用    

#26楼  2007-04-26 19:32 spiderman [未注册用户]
请教一下:
由于还没把gef吃透,处于依样画葫芦阶段,怎样使wizard page 变成eidtor呢?多谢.
  回复  引用    

#27楼  2007-04-28 16:56 杨一 [未注册用户]
看完了。。。好迷茫。。。接着看。。。
  回复  引用    

#28楼 [楼主] 2007-04-28 21:27 八进制      
to spiderman: eclipse里的wizard page和editor是两个不同的概念,作用也不同,何谓把wizard page变成editor呢?
  回复  引用  查看    

#29楼  2007-05-08 13:02 蒋 [未注册用户]
这对节点NAME编辑的时候怎么加入换行啊???
现在的文字不能换行,像做标注的时候文字一多不能换行看起来很别扭!~~
帮想想办法,谢谢..
  回复  引用    

#30楼 [楼主] 2007-07-23 23:10 八进制      
我记得用Ctrl+Enter可以换行
  回复  引用  查看    

#31楼  2007-09-17 15:32 help [未注册用户]
在Figure中,加入图片,例如ImageFigure,能不能把图片拉伸,谢谢!!
  回复  引用    

#32楼 [楼主] 2007-09-18 13:50 八进制      
能,但会出现锯齿。
  回复  引用  查看    

#33楼  2007-09-18 16:40 help [未注册用户]
谢谢你这么快的回复,这个问题对我很重要!!
我用ImageFigure加入一个图片后,通过拉伸图片,Figure的大小变了,但是图片的大小没有变,我尝试用label也是一样。

是不是有办法让图片的以填充的方式的方式让它在Figure中两端和上下对齐,我没有找到!!
  回复  引用    

#34楼 [楼主] 2007-09-18 17:16 八进制      
试一下imageFigure.getImage() .getImageData().scaledTo (width,height)
  回复  引用  查看    

#35楼  2007-09-19 11:18 help [未注册用户]
谢谢你的回复,还是不行
即使直接改变宽度和高度也不行,又会被计算回来
是不是要改变ImageData中的byte数组data,
  回复  引用    

#36楼  2007-09-19 12:54 help [未注册用户]
用imageFigure.getImage() .getImageData().scaledTo (width,height) 返回的ImageData就可以了,谢谢!!
  回复  引用    

#37楼  2007-10-18 05:45 river [未注册用户]
我在GEF中实现了画带多个折点的polyline,现在的问题是:当我选中该polyline时,那个Handle为一个矩形(由8个可拖拉的黑点组成),现在我希望,这些点能分布在polyline的拐点上,这样,我就可以通过拖拉这些点,来改变我的polyline,请问该如何实现?(我尝试过修改ResizableEditPolicy中的createSelectionHandles(),但是,它貌似只提供东西南北等8个方向上规则的几个点)
请指教阿!!谢谢!!
  回复  引用    

#38楼  2007-10-18 20:05 river [未注册用户]
接上贴,控制柄我加进去了,思路就是在每个polyline的拐点处加一个resizehandle,新问题是,我拖动polyline时,这些handle没有跟着移动,是不是要加个listener之类的阿?还有就是如何让这些handle对我的鼠标移动进行响应?
下面是我的代码:
protected List<ResizeHandle> createSelectionHandles() {
List<ResizeHandle> list = new ArrayList<ResizeHandle>();
List<Point> points=((GraphicsPolyline)getHost().getModel()).getPointsList();
for(int i=0;i<points.size();i++)
{
Figure moveHandleRef=new Figure();
moveHandleRef.setSize(7, 7);
moveHandleRef.setLocation(new Point(points.get(i).x-2,points.get(i).y-2));
MoveHandleLocator mhl=new MoveHandleLocator(moveHandleRef);
list.add(new ResizeHandle((GraphicalEditPart) getHost(),mhl,null));
}
return list;
}
  回复  引用    

#39楼 [楼主] 2007-10-19 12:55 八进制      
在editpart的refreshVisuals()里刷新一下应该可以。
  回复  引用  查看    

#40楼  2007-10-21 06:21 river [未注册用户]
谢谢搂主啊,问题解决了,原因是因为我没有覆盖getLocator() 方法!

  回复  引用    

#41楼  2008-06-10 13:58 Willem [未注册用户]
如何画一个自连接那?就是像uml那样,自己引用自己。自己画一根线连在自己身上。
谢谢
  回复  引用    

#42楼 [楼主] 2008-06-12 20:42 八进制      
应该和普通连接没有区别。
  回复  引用  查看    

#43楼  2008-08-04 16:43 zhang_std [未注册用户]
@八进制

我想问一下,Draw2d 里面的Label有没有什么好的办法,让里面的文字不是水平显示的,好像Graphics里面有个rotate(float)方法,网上有人建议不要在GEF里面用这个方法,再说我也不会用,不知道能否指教否?
  回复  引用    

#44楼 [楼主] 2008-08-06 19:45 八进制      
抱歉,我也没做过,我想只能在Figure的paintFigure()里想想办法,而这又会用到你说的Graphics#rotate()方法。。
  回复  引用  查看    

#45楼  2008-10-01 10:09 ddd [未注册用户]
40# 覆盖哪个类里的getLocator() 方法
  回复  引用    

#46楼  2008-10-31 14:27 sunway [未注册用户]
请问如何去掉选中一个figure后的那8个锚点和黑色的边框呢,因为我的图形不能改变大小,用鼠标选中这个图形后不要显示可以改变大小的那8个点和黑框。
  回复  引用    

#47楼  2008-11-06 10:59 sunway [未注册用户]
八进制请来回答下我的问题啊。着急。。
  回复  引用    

#48楼  2008-11-11 16:28 mingwei [未注册用户]
八进制你好,我想问一下
我用ImageFigure加入一个图片后,通过拉伸图片,Figure的大小变了,但是图片的大小没有变。
是不是有办法让图片的以填充的方式的方式让它在Figure中两端和上下对齐,我没有找到!!
我也用 imageFigure.getImage() .getImageData().scaledTo (width,height) 但是我不知道我应该在哪里更新,才能使我拖拽我的figure后图片也跟着拉伸啊?急!!!!
  回复  引用    





标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2005-09-23 16:09 编辑过
Google站内搜索

China-pub 计算机图书网上专卖店!6.5万品种 2-8折!
近千种 9-95 新二手计算图书火热销售中!
开发者征途系统新作:《设计模式——基于C#的工程化实现及扩展》

相关文章:

相关链接: