- 浏览: 2469446 次
- 性别:
- 来自: 杭州
文章分类
- 全部博客 (574)
- Book (62)
- Architecture (6)
- Java (39)
- Taobao (41)
- Distributed (4)
- Life (72)
- Database (7)
- Spring (16)
- Photography (15)
- Bicycle (41)
- Test (20)
- jBPM (8)
- Business (12)
- Movie (3)
- Ajax (15)
- Code (7)
- Eclipse (96)
- VIM (2)
- Music (6)
- Groovy (10)
- AutoHotKey (3)
- Dorado (10)
- Maven (7)
- Scrum (5)
- English (20)
- Financial (12)
- OSGi (3)
- Other (4)
- Tool (6)
- Browser (1)
- PPT (1)
- Project Management (4)
- Agile (6)
- Nosql (1)
- Search engine (6)
- Shell (2)
- Open Source (4)
- Storm (10)
- Guava (3)
- Baby (1)
- netty (1)
- Algorithm (1)
- Linux (1)
- Python (2)
最新评论
-
roy2011a:
https://github.com/ebottabi/sto ...
storm的序列化问题及与spring的结合方式 -
roy2011a:
能抗能打 写道哥们儿,你好!能共享下那个storm与sprin ...
storm的序列化问题及与spring的结合方式 -
Alick1:
兄弟,你之前是不是在深圳的正阳公司呆过啊?
storm的ack和fail -
liuleixwd:
先点个赞,写的非常好!有个问题请教下,如果我再bolt里不用e ...
storm的ack和fail -
yao-dd:
solr的facet查询
FROM:http://www.ibm.com/developerworks/cn/opensource/os-ecl-gef/part1/index.html
2006 年 11 月 30 日
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
GEF的Shapes示例是一个很基础的GEF程序,用户可以在其上放置椭圆和长方形的图形,然后可以用两种样式的线连接它们。由于其使用了ChopboxAnchor,它不支持在两个图形之间创建多条连线,也不能移动锚点。我们将在它的基础上实现一个可移动的锚点。
第一步,确定锚点的表示策略
设计自定义Anchor的第一个问题是"我想把什么位置做为Anchor?",比如对于一个矩形,你可以选择图形的中心,或者四条边的中心,或者边界上的任何点。在我们这个例子里,我们希望是椭圆边界的任何点。因此我们可以考虑用角度来表示Anchor的位置,如图2所示:
图2. Anchor的表示方式
我们可以用一个变量表示角度,从而计算出中心射线与边界的交点,把这个交点作为图形的锚点。通过这样的方式,边界上的任一点都可以成为锚点,可以通过手工调整锚点,避免连线重叠。
第二步,修改Model
为了表示锚点,我们需要一个表示角度的变量,这个变量应该放到模型中以便能够把锚点信息记录到文件中。对于一条来说,它有两个锚点,所以应该在连线对象中添加两个成员,在Shapes例子中,连线对象是org.eclipse.gef.examples.shapes.model.Connection, 我们修改它添加两个成员和相应的Getter和Setter方法:
- private double sourceAngle;
- private double targetAngle;
- public double getSourceAngle() {
- return sourceAngle;
- }
- public void setSourceAngle(double sourceAngle) {
- this.sourceAngle = sourceAngle;
- }
- public double getTargetAngle() {
- return targetAngle;
- }
- public void setTargetAngle(double targetAngle) {
- this.targetAngle = targetAngle;
- }
sourceAngle保存了源锚点的角度,targetAngle保存了目标锚点的角度,使用弧度表示。
第三步,实现ConnectionAnchor接口
锚点的接口是由org.eclipse.draw2d.ConnectionAnchor定义的,我们需要实现这个接口,但是一般来说我们不用从头开始,可以通过继承其它类来减少我们的工作。由于存在椭圆和长方形两种图形,所以我们还需要实现两个子类。最终我们定义了基础类BorderAnchor和RectangleBorderAnchor,EllipseBorderAnchor两个子类。BorderAnchor的代码如下:
- package org.eclipse.gef.examples.shapes.anchor;
- import org.eclipse.draw2d.ChopboxAnchor;
- import org.eclipse.draw2d.IFigure;
- import org.eclipse.draw2d.geometry.Point;
- public abstract class BorderAnchor extends ChopboxAnchor {
- protected double angle;
- public BorderAnchor(IFigure figure) {
- super(figure);
- angle = Double.MAX_VALUE;
- }
- public abstract Point getBorderPoint(Point reference);
- public Point getLocation(Point reference) {
- // 如果angle没有被初始化,使用缺省的ChopboxAnchor,否则计算一个边界锚点
- if(angle == Double.MAX_VALUE)
- return super.getLocation(reference);
- else
- return getBorderPoint(reference);
- }
- public double getAngle() {
- return angle;
- }
- public void setAngle(double angle) {
- this.angle = angle;
- }
- }
重要的是getLocation()方法,它有一个参数"Point reference",即一个参考点,在计算锚点时,我们可以根据参考点来决定锚点的位置,对于ChopboxAnchor来说,参考点就是另外一个图形的中心点。BorderAnchor类有一个angle成员,保存了锚点的角度,它会被初始化为Double.MAX_VALUE,所以我们判断angle是否等于Double.MAX_VALUE,如果是则BorderAnchor相当于一个ChopboxAnchor,如果否则调用一个抽象方法getBorderPoint()来计算我们的锚点。BorderAnchor的两个子类分别实现了计算椭圆和长方形锚点的算法,EllipseBorderAnchor的代码如下所示:
- package org.eclipse.gef.examples.shapes.anchor;
- import org.eclipse.draw2d.IFigure;
- import org.eclipse.draw2d.geometry.Point;
- import org.eclipse.draw2d.geometry.PrecisionPoint;
- import org.eclipse.draw2d.geometry.Rectangle;
- public class EllipseBorderAnchor extends BorderAnchor {
- public EllipseBorderAnchor(IFigure figure) {
- super(figure);
- }
- @Override
- public Point getBorderPoint(Point reference) {
- //得到owner矩形,转换为绝对坐标
- Rectangle r = Rectangle.SINGLETON;
- r.setBounds(getOwner().getBounds());
- getOwner().translateToAbsolute(r);
- // 椭圆方程和直线方程,解2元2次方程
- double a = r.width >> 1;
- double b = r.height >> 1;
- double k = Math.tan(angle);
- double dx = 0.0, dy = 0.0;
- dx = Math.sqrt(1.0 / (1.0 / (a * a) + k * k / (b * b)));
- if(angle > Math.PI / 2 || angle < -Math.PI / 2)
- dx = -dx;
- dy = k * dx;
- // 得到椭圆中心点,加上锚点偏移,得到最终锚点坐标
- PrecisionPoint pp = new PrecisionPoint(r.getCenter());
- pp.translate((int)dx, (int)dy);
- return new Point(pp);
- }
- }
值的注意的地方是我们可以通过getOwner().getBounds()来得到Owner的边界矩形,这是我们能够计算出锚点的重要前提。此外我们要注意的是必须把坐标转换为绝对坐标,这是通过getOwner().translateToAbsolute(r)来实现的。最后,我们返回了锚点的绝对坐标,中间的具体计算过程只不过是根据椭圆方程和射线方程求值而已。在我们的实现中,并没有用到参考点,如果你想有更多的变数,可以把参考点考虑进去。
同样,RectangleBorderAnchor也是如此,只不过求长方形边界点的方法稍微不一样而已,我们就不一一解释了,代码如下:
- package org.eclipse.gef.examples.shapes.anchor;
- import org.eclipse.draw2d.IFigure;
- import org.eclipse.draw2d.geometry.Point;
- import org.eclipse.draw2d.geometry.PrecisionPoint;
- import org.eclipse.draw2d.geometry.Rectangle;
- public class RectangleBorderAnchor extends BorderAnchor {
- public RectangleBorderAnchor(IFigure figure) {
- super(figure);
- }
- @Override
- public Point getBorderPoint(Point reference) {
- // 得到owner矩形,转换为绝对坐标
- Rectangle r = Rectangle.SINGLETON;
- r.setBounds(getOwner().getBounds());
- getOwner().translateToAbsolute(r);
- // 根据角度,计算锚点相对于owner中心点的偏移
- double dx = 0.0, dy = 0.0;
- double tan = Math.atan2(r.height, r.width);
- if(angle >= -tan && angle <= tan) {
- dx = r.width >> 1;
- dy = dx * Math.tan(angle);
- } else if(angle >= tan && angle <= Math.PI - tan) {
- dy = r.height >> 1;
- dx = dy / Math.tan(angle);
- } else if(angle <= -tan && angle >= tan - Math.PI) {
- dy = -(r.height >> 1);
- dx = dy / Math.tan(angle);
- } else {
- dx = -(r.width >> 1);
- dy = dx * Math.tan(angle);
- }
- // 得到长方形中心点,加上偏移,得到最终锚点坐标
- PrecisionPoint pp = new PrecisionPoint(r.getCenter());
- pp.translate((int)dx, (int)dy);
- return new Point(pp);
- }
- }
这样我们就完成了自定义的锚点实现。在ConnectionAnchor接口中,还有其他4个方法,虽然我们没有用到,但是有必要了解一下它们:
- void addAnchorListener(AnchorListener listener);
- void removeAnchorListener(AnchorListener listener);
- Point getReferencePoint();
- IFigure getOwner();
addAnchorListener()和removeAnchorListener()可以添加或删除一个锚点监听器,这样我们可以知道锚点何时发生了移动。getOwner()则是返回锚点的Onwer图形,显然我们可以指定另外一个图形为锚点的Owner,虽然这种需求可能不太多。而getReferencePoint()则是返回一个参考点,要注意的是,这个参考点不是给自己用的,而是给另外一个锚点用的。比如对于源锚点来说,它会调用目标锚点的getReferencePoint()方法,而对于目标锚点来说,它会调用源锚点的getReferencePoint()方法。我们可以看看ChopboxAnchor的getReferencePoint()实现,它返回的就是它的Owner的中心。
第四步,修改EditPart
锚点实现完成后,我们需要修改ShapeEditPart使它能够使用我们定义的锚点。EditPart中的getSourceConnectionAnchor(ConnectionEditPart connection)和getTargetConnectionAnchor(ConnectionEditPart connection)是决定使用哪种锚点的关键方法。它们还有一个重载版本,用来处理Reconnect时的锚点更新。这四个方法我们都需要修改,同时为了减少对象创建的次数,我们可以在ConnectionEditPart里面添加两个成员用来保存源锚点对象和目标锚点对象,如下:
- /* In ConnectionEditPart.java */
- private BorderAnchor sourceAnchor;
- private BorderAnchor targetAnchor;
- public BorderAnchor getSourceAnchor() {
- return sourceAnchor;
- }
- public void setSourceAnchor(BorderAnchor sourceAnchor) {
- this.sourceAnchor = sourceAnchor;
- }
- public BorderAnchor getTargetAnchor() {
- return targetAnchor;
- }
- public void setTargetAnchor(BorderAnchor targetAnchor) {
- this.targetAnchor = targetAnchor;
- }
这样的话,在ShapeEditPart中应该检查一下ConnectionEditPart中的成员是否有效,如果有效则直接返回,无效则创建一个新的锚点对象。而Reconnect时的代码稍微复杂一些,我们需要根据鼠标的当前位置,重新计算angle的值,鼠标的当前位置是包含在ReconnectRequest里面的。我们给出getSourceConnectionAnchor()的代码,对于getTargetConnectionAnchor(),只要将Source换成Target即可。
- /* In ShapeEditPart.java */
- /*
- * (non-Javadoc)
- * @see org.eclipse.gef.NodeEditPart#getSourceConnectionAnchor
- (org.eclipse.gef.ConnectionEditPart)
- */
- public ConnectionAnchor getSourceConnectionAnchor
- (ConnectionEditPart connection) {
- org.eclipse.gef.examples.shapes.parts.ConnectionEditPart con =
- (org.eclipse.gef.examples.shapes.parts.ConnectionEditPart)connection;
- BorderAnchor anchor = con.getSourceAnchor();
- if(anchor == null || anchor.getOwner() != getFigure()) {
- if(getModel() instanceof EllipticalShape)
- anchor = new EllipseBorderAnchor(getFigure());
- else if(getModel() instanceof RectangularShape)
- anchor = new RectangleBorderAnchor(getFigure());
- else
- throw new IllegalArgumentException("unexpected model");
- Connection conModel = (Connection)con.getModel();
- anchor.setAngle(conModel.getSourceAngle());
- con.setSourceAnchor(anchor);
- }
- return anchor;
- }
- /*
- * (non-Javadoc)
- * @see org.eclipse.gef.NodeEditPart#getSourceConnectionAnchor
- (org.eclipse.gef.Request)
- */
- public ConnectionAnchor getSourceConnectionAnchor(Request request) {
- if(request instanceof ReconnectRequest) {
- ReconnectRequest r = (ReconnectRequest)request;
- org.eclipse.gef.examples.shapes.parts.ConnectionEditPart con =
- (org.eclipse.gef.examples.shapes.parts.ConnectionEditPart)r.
- getConnectionEditPart();
- Connection conModel = (Connection)con.getModel();
- BorderAnchor anchor = con.getSourceAnchor();
- GraphicalEditPart part = (GraphicalEditPart)r.getTarget();
- if(anchor == null || anchor.getOwner() != part.getFigure()) {
- if(getModel() instanceof EllipticalShape)
- anchor = new EllipseBorderAnchor(getFigure());
- else if(getModel() instanceof RectangleBorderAnchor)
- anchor = new RectangleBorderAnchor(getFigure());
- else
- throw new IllegalArgumentException("unexpected model");
- anchor.setAngle(conModel.getSourceAngle());
- con.setSourceAnchor(anchor);
- }
- Point loc = r.getLocation();
- Rectangle rect = Rectangle.SINGLETON;
- rect.setBounds(getFigure().getBounds());
- getFigure().translateToAbsolute(rect);
- Point ref = rect.getCenter();
- double dx = loc.x - ref.x;
- double dy = loc.y - ref.y;
- anchor.setAngle(Math.atan2(dy, dx));
- conModel.setSourceAngle(anchor.getAngle());
- return anchor;
- } else {
- if(getModel() instanceof EllipticalShape)
- return new EllipseBorderAnchor(getFigure());
- else if(getModel() instanceof RectangularShape)
- return new RectangleBorderAnchor(getFigure());
- else
- throw new IllegalArgumentException("unexpected model");
- }
- }
到这里我们的修改就完成了,但是由于Shapes示例不允许创建多条连线,所以我们还需要把ConnectionCreateCommand和ConnectionReconnectCommand中的一些代码注释掉,这个内容就不做更多介绍了,大家可以下载本文附带的代码查看具体的修改。最终,我们修改后的Shapes可以创建多条连线,并且可以手动调整它们的锚点以避免重叠,如图3所示:
图3. 新的Shapes示例
结束语
一个灵活的锚点实现对于复杂的图形编辑程序来说是必须的,我们所要做的仅仅只是实现ConnectionAnchor接口。本文实现的BorderAnchor是一个通用的锚点实现,你可以随意应用到自己的GEF程序中。或者在此基础上实现更为灵活的锚点功能。
org.eclipse.gef.examples.shapes_anchor.zip | HTTP |
- 有关GEF的项目信息,请访问 GEF Project Home
- 了解GEF的基础知识,请阅读developerWorks文章: 使用图形编辑框架创建基于 Eclipse 的应用程序
马若劼,IBM 公司软件工程师,主要从事 Workplace Forms 的设计与开发。他在 Java,Eclipse 以及 Eclipse 插件技术方面拥有多年经验,同时也是开源项目 LumaQQ 的创立者。
发表评论
-
Java程序员25个必备的Eclipse插件
2012-01-12 22:36 21926原文:http://www.fromdev.com/2012/ ... -
关于插件更新安装的错误
2007-12-21 20:12 2209在更新插件的时候出现这样的错误: Unable to comp ... -
最近做eclipse branding, features的一些经验
2007-12-16 01:24 4527知道eclipse的splash怎么做 ... -
GEF学习笔记
2007-12-07 20:20 4151GEF以前学习过, 而且还 ... -
SWT布局深入学习
2007-11-30 23:00 7939以下内容是学习"The Definitive Gui ... -
Eclipse Action 深入学习笔记(3)
2007-11-25 17:59 4079filter元素是用来指定当 ... -
Eclipse Action 深入学习笔记(2)
2007-11-25 17:14 5201Object Action 这种Action是跟弹出的上下文菜 ... -
Eclipse Action 深入学习笔记(1)
2007-11-25 17:07 7663以前做插件用到的ActionSet都只是依葫芦画瓢,没有真正理 ... -
JFace Text Editor完全掌握之终极指南(4)
2007-11-24 17:08 5671错误标识(Error Marking) Error Marki ... -
JFace Text Editor完全掌握之终极指南(3)
2007-11-24 16:56 5499内容大纲 之所以要给编 ... -
JFace Text Editor完全掌握之终极指南(2)
2007-11-24 16:53 6723最后一步就是实现各种功能 语法高亮 首先我们要实现的是语法高亮 ... -
JFace Text Editor完全掌握之终极指南(1)
2007-11-24 16:17 9986JFace Text Editor是JFace里面一个功能强大 ... -
最近的Eclipse plugin开发总结
2007-11-24 11:30 4936List控件没有提供addDblClickListener方法 ... -
eclipse3.3关于JavaFileEditorInput兼容性问题的解决
2007-11-24 11:22 4668在eclipse3.3中,JavaFileEditor ... -
Eclipse WTP Projects Facets实战指南(2)
2007-11-21 21:13 5251修饰工作 给facet在选择列表中添加图标 格式如下: xml ... -
Eclipse WTP Projects Facets实战指南(1)
2007-11-21 20:21 9583这个文章基本是"Building Project F ... -
也说关于WizardPage的动态生成
2007-11-05 14:26 5154在Eclipse中一个Wizard=Wiza ... -
关于多页编辑器中不同Editor之间的Redo&Undo冲突的解决
2007-09-03 15:17 4056在我们的插件工具的开 ... -
TextEditor原理分析笔记
2007-08-23 15:48 3376Editor的语法着色原理:Eclipse使用damage , ... -
最近的Eclipse开发总结
2007-08-23 15:46 2105java.lang.IllegalAccessError: t ...
相关推荐
GEF示例 博文链接:https://xyhsm.iteye.com/blog/67809
IBM中文文档中的"GEF进阶"部分可能涵盖了以下内容: 1. **模型-视图-控制器(MVC)架构**:GEF遵循MVC设计模式,将图形界面的逻辑分离为模型(Model)、视图(View)和控制器(Controller)三部分,使得代码更易于...
- **IBM社区文档**:“GEF进阶,第一部分:Anchor”(http://www.ibm.com/developerworks/cn/opensource/os-ecl-gef/part1/index.html) - **其他资源**:了解更多的GEF教程和技术文档,可以帮助开发者更好地理解和运用...
【标签】"org.eclipse.gef.examples.shapes_anchor.zip"标签进一步确认了该压缩包是Eclipse GEF库的一部分,专门涉及图形元素(shapes)的锚点(anchors)。 【压缩包子文件的文件名称列表】: org.eclipse.gef....
GEF: Graphical Editing Framework <br>GEF是一套MVC Framework,它能帮你比较容易的建立图形化的编辑器,V(View)的部分常常是基于SWT的Draw2D,因此Draw2D也看作是GEF的一部分。依赖:org.eclipse.gef***, org...
当前的代码库是与2004年以来提供的原始Draw2d 3.x , GEF(MVC)3.x和Zest 1.x项目组件并行开发的。直到4.0版本为止。 0(Neon)在2016年发布,此代码库分别称为'GEF4'或org.eclipse.gef4 ,这就是为什么这些术语仍...
**RCP(Rich Client Platform)** 是Eclipse项目的一个核心组成部分,它提供了一个框架,用于构建功能丰富的桌面应用程序。RCP允许开发者利用Java语言和Eclipse插件体系结构来创建可扩展、模块化的应用程序,这些...
Gef框架详解:初学者入门与进阶指南 Gef(GDB Enhanced Framework)是一个强大的GDB(GNU调试器)扩展,旨在提供一个更现代、功能更丰富的交互式环境,用于调试C、C++和其他支持GDB的语言。这个压缩包包含了关于Gef...
GEF(Graphical Editor Framework)是一种流行的图形化编辑框架,主要应用于提供图形化编辑模型的功能,以提升用户体验。该框架广泛应用于图形化的流程设计器、UML 类图编辑器等领域。 1.GEF 的特点: GEF 框架...
Eclipse图形化编辑框架(GEF)是Eclipse平台中的一个重要组件,主要用于构建可自定义的图形编辑工具。它为开发人员提供了一套全面的API和设计模式,使得创建复杂的图形用户界面(GUI)变得相对简单。在本篇博文中,...
`GEF_RCP_DEMO`通常包含了一个完整的GEF应用实例,可能包括以下关键部分: - **EditorPart**: 实现编辑器的入口,加载和保存模型,创建图表视图。 - **Model类**: 定义图形元素的数据结构。 - **EditPolicy**: 为...
Gef,全称Graphical Editing Framework,是Eclipse项目的一部分,是一个用于构建图形编辑框架的开源库,主要用于开发基于Swing或SWT的图形用户界面应用。这个框架支持模型驱动的编辑环境,允许开发者创建复杂的图形...
在图形编辑框架(GEF,Graphical Editing Framework)中,锚点(Anchor)是一个关键概念,它是连接模型元素之间的连接线在元素上的固定点。在GEF中,锚点的定位直接影响到连接线的形状和行为,特别是当用户通过鼠标...
Java GEF(Graphical Editing Framework)开发实例是一个深入理解并应用GEF框架的优秀实践案例。GEF是Eclipse平台上用于构建图形编辑器的库,它提供了构建图形用户界面(GUI)所需的基础结构,尤其适合创建复杂的...
由于工作的需要,最近开始研究GEF(Graphical Editor Framework)这个框架,它可以用来给用户提供图形化编辑模型的功能,从而提升用户体验,典型的应用如图形化的流程设计器、UML类图编辑器等等。
【描述】中的"六个小例子"是指通过一系列逐步进阶的教程,帮助开发者从基础到高级理解并掌握GEF的使用。这些例子旨在帮助初学者逐步理解GEF的工作原理,以及如何利用其功能构建复杂的图形用户界面。每个例子都增加了...
2. **创建第一个项目**:使用GEF工作流创建一个简单的图形编辑器,如画板和基本图形。 3. **实现命令**:编写自定义命令以处理用户操作,如添加、删除和移动图形元素。 4. **图形交互**:实现DirectEdit和手势识别,...
【GEF_Demo_Code20170307】是一个关于图形编辑框架(Graphical Editing Framework,简称GEF)的示例代码集合,发布于2017年3月7日。这个项目旨在演示如何利用GEF进行图形界面开发,并且特别关注了通过适配器...