相信学过编程的同学都会用过Eclipse,Eclipse作为一个集成开发环境(IDE),给我们带来了不错的开发体验(虽然我知道大家都用IDEA了),但是Eclipse的作用却不仅限于此。

Eclipse本身是一个框架平台,由于众多插件的支持,使得Eclipse拥有较佳的灵活性,所以许多软件开发商以Eclipse为框架开发自己的IDE。如果你的想开发属于自己的IDE,那么选择Eclipse作为你的开发框架是个不错的选择。随着业务变得越来越复杂以及可视化的需求越来越多,如果你想在基于Eclipse平台的IDE中画个UML图,流程图,工作流 ,那么应该怎么去实现呢?

GEF(Graphical Edit Framework)是Eclipse官方提供的一个图形编辑框架,它允许开发人员以图形化的方式展示和编辑模型,从而提升用户体验,基于GEF框架开发的应用有很多种类型,例如:UML 类编辑器、图形化XML编辑器、界面设计工具以及图形化数据库结构设计工具等等。归结一下,可以发现它们在图形化编辑方面具有以下共同之处:

  • 提供一个编辑区域和一个工具条,用户在工具条里选择需要的工具,以拖动或单击的方式将节点或连接放置在编辑区域;
  • 节点可以包含子节点;
  • 用户能够查看和修改某个节点或连接的大部分属性;
  • 连接端点锚定在节点上;
  • 提供上下文菜单和键盘命令;
  • 提供图形的缩放功能;
  • 提供一个大纲视图,显示编辑区的缩略图,或是树状模型结构
  • 支持撤销/重做功能;
  • 等等。

▲用GEF编写的流程编辑器

GEF是标准的MVC(Model-View-Control)框架,开发人员可以利用GEF来完成以上这些功能,而不需要自己重新设计。与其他一些MVC编辑框架相比,GEF的一个主要设计目标是尽量减少模型和视图之间的依赖,好处是可以根据需要选择任意模型和视图的组合,而不必受开发框架的局限。不仅如此,GEF框架中也包含着许多经典设计模式,最突出的是Command模式,方便的实现编辑器中的Undo/Redo功能等等。无论是从业务还是学习,GEF都会是一个值得学习的框架。下面我会从GEF框架的核心组建和一次挪动后GEF框架内的工作流程来给大家讲讲GEF框架。

GEF中的核心组件

▲GEF结构图

模型(Model)

GEF中的模型只与控制器(Editpart)打交道,而不知道任何与视图(View)有关的内容。为了能让控制器知道模型发生的变化,应该把控制器作为事件监听者注册在模型中。这样当模型发生变化时,就会触发相应的事件给控制器,控制器会负责通知各个视图进行更新。

下面来看一下代码是如何实现的,首先在模型类中需要加入PropertyChangeSupport类型的成员变量来维护监听器成员即控制器,如下示例代码。

PropertyChangeSupport listeners = new PropertyChangeSupport(this);public void addPropertyChangeListener(PropertyChangeListener l) {    listeners.addPropertyChangeListener(l);}protected void firePropertyChange(String prop, Object old, Object newValue) {    listeners.firePropertyChange(prop, old, newValue);}public void removePropertyChangeListener(PropertyChangeListener l) {    listeners.removePropertyChangeListener(l);}

那么控制器作为事件监听者如何加入到这个监听列表里面呢?在控制器类初始化的时候,会去调用active()方法,在该方法内去注册监听即可。​​​​​​​

public void activate() {    if (isActive()) {        return;    }    super.activate();    ((Node) getModel()).addPropertyChangeListener(this);}

当模型发生变化时,可以调用firePropertyChange()方法去通知控制器发生改变。

典型的模型对象不仅会包含监听者列表,对于与其他对象具有连接关系的模型,要维护连入(Inputs)/连出(Outputs)的连接列表;如果模型对象的节点具有大小和位置信息,也需要维护它们。这些变量可能并不是业务模型本身必须的信息,维护它们使得模型变得不够清晰,但是你可以通过构造一些抽象模型类来维持它们的可读性。总结一下,模型其实是根据我们的业务去自由设计的,但真实的GEF模型不仅仅包含着业务模型有关的数据,其中还包含着坐标、大小一些图形信息,这个值得我们去注意。

接下来我们讲控制器(EditPart)。

控制器(EditPart)

与一般MVC框架中的Controller不同,控制器在GEF中叫做Editpart。控制器是模型与视图之间连接的桥梁,也是整个GEF应用的核心组件。它不仅监听着模型发生的变化,当用户编辑视图时,还要把编辑器结果反应到模型上。 每一个模型都会对应一个Editpart对象,一个个EditPart对象组合起来共同完成了控制器的作用。

▲EditPart对象

那么怎样去操作EditPart呢,GEF中将用户的编辑行为转化为了一系列请求(Request),然后将请求交给控制器去处理。这倒与SpringMVC有着异曲同工之妙,SpringMVC也是在Controller中接收HTTP请求然后进行处理的。GEF中的请求种类是非常多的,有针对布局的一系列请求,如CreateRequest(创建节点请求)、ChangeBoundsRequest(改变节点大小请求),还有针对连线的一些列请求等等。如果在EditPart对象中统一处理这些请求的话,那么它的类需要非常大了。为了解决这种情况,GEF将这些请求进行了分类,针对某一类请求,可以加入处理这一类请求的“特殊控制器”。这些请求种类在GEF里被称为角色(Role),而这种“特殊控制器”被称为编辑策略(EditPolicy)。

如下面代码所示,EditPart类中会有createEditPolicies()方法,该方法可以让你针对控制器的不同自由的去安装这些编辑策略,有点类似插件的概念。这样做的直接好处就是可以在不同的EditPart之间共享一些重复的操作。

protected void createEditPolicies() {    installEditPolicy(EditPolicy.DIRECT_EDIT_ROLE, new NodeDirectEditPolicy());    installEditPolicy(EditPolicy.COMPONENT_ROLE, new NodeEditPolicy());    installEditPolicy(EditPolicy.GRAPHICAL_NODE_ROLE, new NodeGraphicalNodeEditPolicy());}

接下来控制器接收到了请求之后,会做什么呢?接下来就到了最为关键的部分。编辑策略(EditPolicy)接收到请求后,根据请求创建相应的命令(Command),命令会直接操作模型对象。如下面的实例代码,是一个创建模型的请求。​​​​​​​

protected Command getCreateCommand(CreateRequest request) {    if (request.getNewObject() instanceof Node) {        CreateNodeCommand cmd = new CreateNodeCommand();        cmd.setDiagram((Diagram) getHost().getModel());        cmd.setNode((Node) request.getNewObject());        Rectangle constraint = (Rectangle) getConstraintFor(request);        cmd.setLocation(constraint.getLocation());        return cmd;    }    return null;}

基本已经把控制器这一部分讲完了,如果还有些地方不理解,可以根据下面图再去理解一下控制器的通信流程。下面讲视图。

▲通信链(请求-控制器-命令)

视图(View)

GEF中的视图是依赖于Draw2D框架的,其作用是把Model以图形化的方式表现给用户。Draw2D是一个图形框架,在这里有关Draw2D的知识我就不讲了,有兴趣可以上网搜一下。我们这里讲一下GEF是如果引用Draw2D的。如下面示例代码,在控制器中,有这么一个抽象方法让我们去创建模型的视图。

protected abstract IFigure createFigure();

工具(Tool)

我们已经知道控制器是通过请求去操作的,那么是什么生成请求的呢?那就要说到工具(Tool)了。GEF的工具可以分为很多种,如MarqueeSelectionTool(框选工具)、SelectionTool(选择)等等。这个工具其实跟Photoshop中的工具库是同一个概念,我们可以选择不同的工具或者创造自己的工具去操作模型。工具会接收到用户的鼠标键盘事件(KeyBoardEvent、MouseEvent),不同的工具接收到事件后生成不同的请求。

编辑器(EditorPart)

我们在Eclipse中如果想使用GEF框架,必须要依靠Eclipse提供的编辑器(EditorPart)。编辑器作为Eclipse和GEF的纽带,作用非常大。在编辑器中里不仅仅包含了模型的根节点、视图、Actions等等。你可以在编辑器中配置快捷键,实现保存和读取文件的功能等等。具体这里就不展开讲了。有兴趣的可以搜一下Eclipse RCP的框架平台。

编辑域(EditDomain)

编辑域也是GEF中重要的一个组件,它的源码中是这样描述的。

| The collective state of a GEF "application", loosely defined by a CommandStack, one or more EditPartViewers, and the active Tool. An EditDomain is usually tied with an Eclipse IEditorPart. However, the distinction between EditorPart and EditDomain was made to allow for much flexible use of the Graphical Editing Framework.

它的作用是为了解耦与编辑器的一些属性。如果将GEF里面所有的对象和内容都放在编辑器中,那么这个类会变得很大,属性很多,所以GEF将其解耦出来了。编辑域中包含着所有工具的集合、视图的集合还有最重要的是它包含着命令栈(CommandStack)。命令栈里面包含着所有GEF中执行过的命令(Command),通过命令栈的push和pop,可以实现一系列命令的撤销和重做功能。

挪动一次节点,GEF中发生了什么

▲GEF各组件交互图

基本的组件和概念已经讲完了,接下来我们通过讲述挪动一次模型,GEF中发生了什么来回顾一下之前讲的内容。

1.首先用户会通过鼠标去操作模型,Eclipse接收到鼠标事件(MouseEvent)后交给编辑域(EditDomain)去处理;

2.编辑域根据鼠标事件去选择相对应的工具,挪动模型会用到GEF中DragEditPartsTracker这个工具;

3.这个工具接收到鼠标事件后,根据事件发生的坐标生成一个改变位置的请求(Request),然后将请求转交给控制器(EditPart)处理;

4.控制器接收到请求后,会在自己对象里面找到一个处理这个请求的编辑策略(EditPolicy),让编辑策略去处理请求;

5.编辑策略接收到请求后,根据请求的信息去产生一个命令(Command),这里命令包含着改变模型位置的数据;

6.产生命令后,会存储在编辑域(EditDomain)中的命令栈(CommandStack)中,并且执行;

7.命令(Command)执行后,修改模型里面有关位置的数据。当模型位置数据发生变化时,控制器作为模型的监听者接收到了模型的变化;

8.控制器(EditPart)监听到模型位置发生的变化后,改变了视图(View)的位置。

好了,Eclipse GEF就讲到这里,相信大家对GEF这个框架有了一定的认识,下次有机会再讲讲GEF的实践部分吧。

浅谈Eclipse GEF相关推荐

  1. eclipse php 断点,浅谈Eclipse PDT调试PHP程序

    1. 下载eclipse,从官网上找就可以了,并确认当前系统中有java环境,即jdk和jre. 2. 安装pdt了,采用的是在线安装,更新地址在默认中已经包含了.只是更新起来比较麻烦.(如果直接下载 ...

  2. 浅谈几种区块链网络攻击以及防御方案之日蚀攻击

    旧博文,搬到 csdn 原文:http://rebootcat.com/2020/04/12/network_attack_of_blockchain_eclipse_attack/ 写在前面的话 自 ...

  3. java的byte php_java_浅谈java的byte数组的不同写法,(由于篇幅原因阐述的不够详 - phpStudy...

    浅谈java的byte数组的不同写法 (由于篇幅原因阐述的不够详细科学,不喜勿喷). 经常看到java中对byte数组的不同定义,粗略整理的一下: 一个字节(byte)=8位(bit),"b ...

  4. Java 线上问题排查神器 Arthas 快速上手与原理浅谈

    [Arthas 官方社区正在举行征文活动,参加即有奖品拿哦~点击投稿] 作者 | 杨桢栋,笔名叫蛮三刀把刀,是一名一线互联网码农,留美访学一年,主要关注后端开发,数据安全,爬虫,物联网,边缘计算等方向 ...

  5. 浅谈 JavaScript 编程语言的编码规范--转载

    原文:http://www.ibm.com/developerworks/cn/web/1008_wangdd_jscodingrule/ 对于熟悉 C/C++ 或 Java 语言的工程师来说,Jav ...

  6. 浅谈程序员的行业选择---程序人生

    引言 本篇博文接着许久之前的一篇博文<浅谈程序猿的职业规划,看你如何决定自己的未来吧.>,继续探讨一下程序员行业相关的内容. 行业的选择不仅对于程序员来说非常重要,对任何一个人来说都是一样 ...

  7. java中定义byte数组,浅谈java的byte数组的不同写法

    (由于篇幅原因阐述的不够详细科学,不喜勿喷). 经常看到java中对byte数组的不同定义,粗略整理的一下: 一个字节(byte)=8位(bit),"byte数组"里面全部是&qu ...

  8. 浅谈JAVA程序破解(原创)

    浅谈JAVA程序破解 作者:舵手 申明:如转载请保证文章的完整性以及出处 最近对JAVA程序的破解比较感兴趣,拿几个行业软件练了一下手,略有心得,拿出来与菜鸟分享!注意只是一点心得, 本文并不涉及具体 ...

  9. android悬浮按钮阴影,浅谈FloatingActionButton(悬浮按钮)

    一.介绍 这个类是继承自ImageView的,所以对于这个控件我们可以使用ImageView的所有属性 android.support.design.widget.FloatingActionButt ...

最新文章

  1. Services(服务)
  2. java不使用IDE导入json
  3. hdu 5367(线段树+区间合并)
  4. 21-5-22校赛G 自行车调度
  5. 『设计模式』我能进来坐坐吗?--访问者模式
  6. 【JVM】JVM-codecache内存区域介绍
  7. Codeforces Round #479 (Div. 3) F. Consecutive Subsequence (简单dp)
  8. POJ 1789 Truck History(最小生成树)
  9. 【Modbus】 RTU CRC校验码计算方法
  10. 河北计算机应用对口升学,2019年河北省中等职业学校对口升学考试:计算机文化基础+计算机应用基础模拟试卷...
  11. Tkinter教程(每天半小时,3天彻底掌握Tkinter)day1
  12. Multisim14安装教程(下载链接在文末)
  13. ubuntu16.04安装完后无法上网
  14. Android选择颜色,尺码联动
  15. h3c查看光纤光功率
  16. 应届生求职经历-一路坎坷
  17. python(2)提取多层嵌套列表里子元素的最大值
  18. 索引过长 max key length is 767 bytes
  19. SQLyog Community免费版下载地址
  20. 仅仅允许本校报考?多所985/211大学计算机第二学士学位

热门文章

  1. openwrt首次登录密码_什么是路由器登录密码 路由器登录密码介绍【详解】
  2. xbanner 动画特效设置android,Axure教程:如何实现爱彼迎App首页Banner的切换效果
  3. Python机器学习:KNN算法02scikit-learn中的机器学习算法封装
  4. LightGBM常用模板
  5. java 定义utilities_java – 无法运行程序“/Applications/Utilities/...
  6. GWO(灰狼优化)算法
  7. MFC----ListBox用法
  8. python调用系统命令_Python调用外部系统命令
  9. oracle判断某列是否有单引号_sql注入二 ——数据库信息判断
  10. HuggingFace学习3:加载预训练模型完成机器翻译(中译英)任务