anchor用法:GEF 进阶 第一部分: Anchor来源: 发布时间:星期六, 2009年12月19日 浏览:0次 评论:0
GEF(Graphical Editing Framework)是Eclipse Tools子项目它在底层使用Draw2D作为布局和渲染引擎在整体上使用MVC模式管理模型和视图利用GEF开发者可以从应用模型开始迅速构造个可视化编辑环境正如其名字所说它只是个框架很多具体事情仍然要靠开发者完成但这也是GEF灵活方面只要你掌握了相关概念你就可以对个GEF应用进行充分定制本系列目就是介绍GEF相关概念并在GEF些举例基础上演示如何定制、扩展自己GEF应用这是本系列第章主要介绍了Anchor(锚点)概念以及如何自定义个锚点并替代GEF缺省实现
Anchor(锚点) 在个典型GEF中我们通常会在画板上放上些图形然后用些线连接这些图形这些线两个端点就是Anchor(锚点)而锚点所在图形叫做锚点Owner更细化说条线起点叫做Source Anchor(源锚点)终结点叫做Target Anchor(目标锚点)如图1中黑色小方块所示 图1. 源锚点和目标锚点 不难看出锚点具体位置和两个图形位置以及连线方式有关这两个前提确定的后锚点可以通过定思路方法计算得出对于图1情况两个图形的间连线是由两个图形中心点确定那么锚点计算思路方法就是找到这条中心线和图形边界交点Draw2D缺省为我们提供了些Anchor实现最常用大概是ChopboxAnchor它只是简单取两个图形中心线和图形边界交点做为锚点(正是图1 情况)对于简单应用来说ChopboxAnchor可以满足我们需要但是它锚点计算思路方法导致锚点在任何时候都是唯如果这两个图形的间存在多条连线它们会相互重叠使得看上去只有条于是用户不可能用鼠标选择到被覆盖连线 解决这个问题办法有两个: 1. 提供个自定义Connection Router(连线路由器)以便能尽量避免线的间重合甚至也可以每条线都有区别Router 2. 实现个自定义锚点可以让用户自己拖动锚点到区别位置避免线的间重合 对于思路方法1我们在以后系列中会有介绍这里我们考虑思路方法2 Shapes Example GEFShapes举例是个很基础GEF用户可以在其上放置椭圆和长方形图形然后可以用两种样式线连接它们由于其使用了ChopboxAnchor它不支持在两个图形的间创建多条连线也不能移动锚点我们将在它基础上实现个可移动锚点 第步确定锚点表示策略 设计自定义Anchor第个问题是"我想把什么位置做为Anchor?"比如对于个矩形你可以选择图形中心或者 4条边中心或者边界上任何点在我们这个例子里我们希望是椭圆边界任何点因此我们可以考虑用角度来表示Anchor位置如图2所示: 图2. Anchor表示方式 查看原图(大图) 我们可以用个变量表示角度从而计算出中心射线和边界交点把这个交点作为图形锚点通过这样方式边界上任点都可以成为锚点可以通过手工调整锚点避免连线重叠 第 2步修改Model 为了表示锚点我们需要个表示角度变量这个变量应该放到模型中以便能够把锚点信息记录到文件中对于条来说它有两个锚点所以应该在连线对象中添加两个成员在Shapes例子中连线对象是org.eclipse.gef.examples.shapes.model.Connection, 我们修改它添加两个成员和相应Getter和Setter思路方法: private double sourceAngle; sourceAngle保存了源锚点角度targetAngle保存了目标锚点角度使用弧度表示 第 3步实现ConnectionAnchor接口 锚点接口是由org.eclipse.draw2d.ConnectionAnchor定义我们需要实现这个接口但是般来说我们不用从头开始可以通过继承其它类来减少我们工作由于存在椭圆和长方形两种图形所以我们还需要实现两个子类最终我们定义了基础类BorderAnchor和 RectangleBorderAnchorEllipseBorderAnchor两个子类BorderAnchor代码如下: package org.eclipse.gef.examples.shapes.anchor; 重要是getLocation思路方法它有个参数"Po reference"即个参考点在计算锚点时我们可以根据参考点来决定锚点位置对于ChopboxAnchor来说参考点就是另外个图形中心点BorderAnchor类有个angle成员保存了锚点角度它会被化为Double.MAX_VALUE所以我们判断 angle是否等于Double.MAX_VALUE如果是则BorderAnchor相当于个ChopboxAnchor如果否则个抽象思路方法getBorderPo来计算我们锚点BorderAnchor两个子类分别实现了计算椭圆和长方形锚点算法EllipseBorderAnchor代码如下所示: package org.eclipse.gef.examples.shapes.anchor; 值注意地方是我们可以通过 getOwner.getBounds来得到Owner边界矩形这是我们能够计算出锚点重要前提此外我们要注意是必须把坐标转换为绝对坐标这是通过getOwner.translateToAbsolute(r)来实现最后我们返回了锚点绝对坐标中间具体计算过程只不过是根据椭圆方程和射线方程求值而已在我们实现中并没有用到参考点如果你想有更多变数可以把参考点考虑进去 同样RectangleBorderAnchor也是如此只不过求长方形边界点思路方法稍微不样而已我们就不解释了代码如下: package org.eclipse.gef.examples.shapes.anchor; 这样我们就完成了自定义锚点实现在ConnectionAnchor接口中还有其他4个思路方法虽然我们没有用到但是有必要了解下它们: void addAnchorListener(AnchorListener listener); addAnchorListener 和removeAnchorListener可以添加或删除个锚点监听器这样我们可以知道锚点何时发生了移动getOwner则是返回锚点Onwer图形显然我们可以指定另外个图形为锚点Owner虽然这种需求可能不太多而getReferencePo则是返回个参考点要注意是这个参考点不是给自己用而是给另外个锚点用比如对于源锚点来说它会目标锚点getReferencePo 思路方法而对于目标锚点来说它会源锚点getReferencePo思路方法我们可以看看ChopboxAnchor getReferencePo实现它返回就是它Owner中心 第 4步修改EditPart 锚点实现完成后我们需要修改ShapeEditPart使它能够使用我们定义锚点EditPart中 getSourceConnectionAnchor(ConnectionEditPart connection)和getTargetConnectionAnchor(ConnectionEditPart connection)是决定使用哪种锚点关键思路方法它们还有个重载版本用来处理Reconnect时锚点更新这 4个思路方法我们都需要修改同时为了减少对象创建次数我们可以在ConnectionEditPart里面添加两个成员用来保存源锚点对象和目标锚点对象如下: /* In ConnectionEditPart.java */ 这样话在ShapeEditPart 中应该检查下ConnectionEditPart中成员是否有效如果有效则直接返回无效则创建个新锚点对象而Reconnect时代码稍微复杂些我们需要根据鼠标当前位置重新计算angle值鼠标当前位置是包含在ReconnectRequest里面我们给出 getSourceConnectionAnchor代码对于getTargetConnectionAnchor只要将Source换成 Target即可 /* In ShapeEditPart.java */ 到这里我们修改就完成了但是由于 Shapes举例不允许创建多条连线所以我们还需要把ConnectionCreateCommand和 ConnectionReconnectCommand中些代码注释掉这个内容就不做更多介绍了大家可以下载本文附带代码查看具体修改最终我们修改后Shapes可以创建多条连线并且可以手动调整它们锚点以避免重叠如图3所示: 图3. 新Shapes举例 结束语 个灵活锚点实现对于复杂图形编辑来说是必须我们所要做仅仅只是实现ConnectionAnchor接口本文实现BorderAnchor是个通用锚点实现你可以随意应用到自己GEF中或者在此基础上实现更为灵活锚点功能 0
相关文章读者评论发表评论 |