GEF入门

来源:互联网 发布:java小技术分享 编辑:程序博客网 时间:2024/06/06 05:02
1 必须具备知识:在学习GEF之前必须了解Eclipse这个平台的架构体系,所以先讲述Eclipse平台的架构体系.1.1 Eclipse架构体系:图表 1 1 eclipse架构体系正如上面所叙述: Eclipse Platform包括以下插件:1. platform runtime: 注意这个插件是必须要的,启动eclipse需要他.2. workspace3. debug4. help5. team6. workbench:其中workbench 主要有由SWT和JFace组成. JDT插件在Eclipse Platform的基础上为Java开发环境提供的一个插件,使用这个插件可以做Java开发,同时他也提供访问Java一些资源的API(扩展点),可以利用这些扩展点为将来自己做插件开发提供用处. PDE插件开发则是在JDT插件和Eclipse Platform两个基础上为开发插件提供一个环境,提供一个API. Eclipse Project这个东西包括了JDT,PDE,Eclipse Platform. 然后我们可以在Eclipse Platform的基础上做自己的插件开发,比如:another tool, your tool, their tool 就是利用eclipse platform开发出来的插件.图表 1 2 Platform的API上分布情况从上图我们可以看到:org.eclipse.core 这个包涉足到的插件领域有:platform runtime,workspace,team,help,debug.Org.eclipse.ui 这个包涉足到的插件领域有:Workbench, team, help,debug.图表 1 3 eclipse插件的层次结构从上图我们可以看到:Java virtual Machine位于最低层Platform在 JVM之上JDT在Platform基础上开发出来的.PDE又是在JDT的基础上开发出来.1.2 Plugin开发平台首先要弄明白,弄熟悉Plugin开发环境,这方面资料见eclipse的帮助,或者<<eclipse从入门到精通>>这本书.Plugin开发中最重要的一个文件文件就是plugin.xml这个文件,下面对这个文件做一个讲述.图表 1 4 plugin.xml的分析从上面这个图中我们可以看到plugin.xml主要做如下工作: Requires: 提出该插件开发的情况下必须需要那些其他的插件,在PDE上开发需要import进来的包. Runtime: 表明该插件真正在eclipse平台上运行起来需要哪些插件. Extension point: 在哪些其他插件上的扩展点上作出的二次开发 Extension-Point: 向外界提供哪些扩展点,使得别人可以在我开发的插件基础上再做二次开发.图表 1 5 extension与extension point的概念Extension point: 插件A向外界提供一个扩展点,使得其他人可以在A的基础上再做二次开发,Extension: 对 extension point的延生, 再extension point的基础上做的二次开发.1.3 Eclipse开发文档-非常重要图表 1 6 eclipse的help文档从上面我们可以看到eclipse提供了各种各样的文档,基本上分为两类: 用户文档: -----针对软件使用者,相当于使用手册Workbench User GuideJava Development User GuidePDE guide 开发文档: -----针对插件开发人员Platform Plug-in Developer GuideJDT Plug-in Developer GuideGEF Developer GuideDraw2D Developer GuideEMF Programmer’s GuideEMF Service Data Objects(SDO) Programmer’s GuideXSD Programmer’s Guide以上这些文档是非常重要的,时刻是要查询的,必备手册.1.4 插件开发中的一些重要概念:图表 1 7 一些插件中的重要概念从上图中我们熟悉了一些什么是workbench, workbench window, workbenchpage, view.现在来讲述一下eclipse的构成. Platform PlatformUI 类 WorkbenchIWorkbench接口,分为host与target两种类型Host 为插件开发的workbench,Target为对开发出来的插件进行debug,run时的workbench. WorkbenchWindow IWorkbenchWindow接口 PagesIWorkbenchPage接口 ,类似perspective概念 PartsIWorkbenchPart接口, 包括了viewpart,editorpart ViewsIViewPart接口 EditorsIEditorPart ,常常与IEditorInput关联Platform启动/访问workbench;workbench下面包含1..*个workbenchwindow(可曾记得eclipse的window菜单下new window);workbenchwindow下面包含menu bar, toolbar, 1..*个workbenchpage.Workbenchpage 下面包括1..* partsParts里面包含了0..*个viewpart,0..*editorpart. Display: SWT与底层OS交互的一个纽带,用来负责SWT和OS的通信 Shell: 一个开发出来的可视化的window IAction: IActionDelegate: IWorkbenchAction: IWorkbenchActionDelegate: ISelection: IAdaptable: IPageService: IPartService: ISelectionService: IWorkbenchSite: IWorkbenchPartSite: IEditorSite:XXXService接口主要用来跟踪信息用的XXXSite 接口用来获取周围的环境还有其他的一些重要接口可以通过Platform Plug-in Developer Guide来获得帮助.下面再简要的展现一些概念.图表 1 8 一些其他的概念2 GEF开发教程 学习GEF的一些参考资料:http://bjzhanghao.cnblogs.com/ ---该blog中有很多关于GEF&EMF入门的教程.http://javaspider.sourceforge.net/updatesite ---一个记载当前workbench下的各种类,及其相关的方法和调用流程. 初级学者适合的例子:http://jtauber.com/2004/gef/gef.ziphttp://bjzhanghao.cnblogs.com/Files/bjzhanghao/Six GEF snapshots from James Tauber.zip上面两个包就是一个东西,非常适合入门者,一步一步的提高技术水平.http://www.cnblogs.com/Files/bjzhanghao/gefpractice.zip 一些经典的例子程序(比较难,不适合入门)GEF SDK Examples自带的四个case:1. org.eclipse.gef.examples.flow2. org.eclipse.gef.examples.logic3. org.eclipse.gef.examples.shapes4. org.eclipse.gef.examples.text 初步学习GEF和Draw2D必须要看的资料:1. GEF Developer Guide里面的一篇整体概括文章,包括: Introduction,EditPartViewers,Model View Controller Architecture, EditParts, EditPolicies Requests, and Roles, Tools and the Palette, The Steps to Building a GEF application.2. Draw2D Developer Guide 里面的一篇整体概括文章,包括: Introduction, Visual Overview, LayoutManager Demo, Clicking and Scrolling Demo, Connections and Anchors Demo.2.1 Draw2D知识图表 2 1 Draw2D体系结构Draw2D是基于SWT的图形处理包,它适合用作GEF的View层: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.2 GEF框架GEF框架中很多东西,主要得关注它的流程和结构.2.2.1 GEF结构图:图表 2 2 GEF结构图这个图非常重要,体现了GEF的全部框架,必须牢记.注意: EditorPart 与EditPart 不是一个概念. 从上图中我们可以看到WorkbenchPage, EditorPart, OutlineView三者互相作用. 代表他们都可以触发对方发生响应. EditorPart的产生必然会导致IEditorInput的出现,因为两者有着紧密的关联. EditorPart的控件中包含了PaletteViewer 控件和EditPartViewers[]控件. PaletteViewer表示是一个工具板,里面包含了各种各样的Tool, 但是用户做操作时只有一个Tool为Active Tool. EditPartViewers[] 代表editorPart中多个可视Unit. 因为一个可视Unit包括: 一个editPart,一个ViewPart,一个Application Model . 其中editPart 为可视Unit的Controller, ViewPart为可视Unit的View(在EditorPart中可以看到的一些控件), Application Model 为可视Unit的Model. PaletteViewer 与EditPartViewer进行交互中包括一个EditDomain,这个EditDomain代表一次edit session. EditDomain中记载了Active Tool, Command Stack, EditPartViewer[],PaletteViewer, PaletteModel. 使用EditDomain来进行各种交互.2.2.2 EditPartViewer结构图:图表 2 3 EditorPartViewer结构图此图代表了EditorViewer的具体组成:从上面途中我们可以看到ViewPart与Application Model不发生关系,他们要发生关系必须通过EditPart这个控制器. EditPartController这个控制器发出命令对viewpart的创建,更改 VisualPartView一般由Draw2D中的控件来表现,是一种可视控件. Application Model Model针对visualPart有对应的模型, 模型代表了visualPart中的一种具体数据.控制流程:EditPart 来控制VisualPart 的创建修改, Application Model的创建修改.同时由于在启动editorPartViewer时,将每一个Application Model和VisualPart一一绑定在一起, 同时application Model中有propertyListener, 所以Application Model发生改变时, 通过PropertyListener告诉editPart, 然后editPart来控制visualPart的改变.图表 2 4 EditorPartViewer的MVC图注意: Visual Part 与Application Model之间没有任何关系,他们之间的沟通全部通过EditPart进行. 所以: EditPartController VisualPartView Application Model Model图表 2 5 EditPart 与Role,EditPolicies关系EditPart调整模型是如下来进行的.EditPart将更改的request转换为EditPolicy, 然后在EditPolicy制定详细的操作, EditPolicy进一步转换为Command, 然后由Command来完成具体的操作.2.2.3 GEF一个大致的流程:(对照参考GEF Developer Guide中的The Steps to Building a GEF Application)本流程针对http://jtauber.com/2004/gef/gef.zip中的pt1来说:1. 系统首先打开一个EditorPart, 然后开始一些初始化操作:2. EditorPart初始化一个模型Diagram;3. 在Diagram这个model中PropertyChangeListener, PropertyChangeSupport这些类的存在就是为了监听模型的改变,如果模型改变了,那么要告知模型对应的editPart,让editPart执行相应的操作. 我们可以注意到在editPart类的代码中有PropertyChangeEvent, PropertyChangeListener类的存在,这些代码的存在就是对侦听到的事件进行处理;4. EditorPart初始化一个setEditDomain(),将EditDomain联系起来;5. EditorPart通过SetInput() 将IEditorInput联系起来, 可以将生成的Diagram模型放入到IEditorInput中来;6. EditorPart要负责生成一个editPartViewer. editPartViewer的主要作用是:要知道他周围的所有的editParts, 所有的viewPart, 同时将用户点击的热点区域映射到editPart, 由editPart 创建viewPart.下面开始讲解editPartViewer的生成过程;7. EditorPart的configureGraphicalViewer()方法中首先得到EditPartViewer,然后做下面的一些设置:getGraphicalViewer().setRootEditPart(new ScalableFreeformRootEditPart()) ----设置顶级别的EditPart,getGraphicalViewer().setEditPartFactory(new PartFactory())----针对每一个模型制定一个editPart,PartFactory这个类的作用是 针对不同的model给不同的editPart.到此就达到了一个目的: 每一个model 一一对应起一个edtipart. 于是editpart就可以操作每一个model, 每一个model的改变首先告知对应的editPart, 由editpart来负责通知viewPart的更改;8. EditorPart的initializeGraphicalViewer()方法的getGraphicalViewer().setContents(this.diagram);----含义:根据前面的configureGraphicalViewer()中的setEditPartFactory()方法,不同的model得到不同的editPart, editorPart将diagram模型植入到editPartViewer中的同时,将diagram模型对应的editpart(DiagramEditPart)置为顶级别的editPart, 然后 根据DiagramEditPart中的一些方法getModelChildren()得到整个模型,再根据各自的模型得到对应的editPart(例如NodePart),这些editPart中有createFigure(),createEditPolicies(), 完成各个viewPart的创建.到此时为止editPartViewer构造完成.9. 总体观察: 通过editorPart完成了editPartViewer的整体构造.图表 2 6 流程图下面开始讲解针对一个特定事件触发的流程:1. 一个模型发生改变,例如Node发生移动. PropertyChangeListener, PropertyChangeSupport,用来监听model的改变.addPropertyChangeListener(PropertyChangeListener listener)方法用来将侦听器加入到model中.removePropertyChangeListener(PropertyChangeListener listener)方法用来删除model中的侦听器.在NodePart的activate(),deactive()方法中((Node) getModel()).addPropertyChangeListener(this);((Node) getModel()).removePropertyChangeListener(this);上面两个方法把侦听器加入到model中.因为NodePart implements PropertyChangeListener,所以NodePart本身也是一个侦听器.2. 然后模型对应的NodePart中的PropertyChangeEvent, PropertyChangeListener, 可以得到侦听到的事件,开始做事件处理. propertyChange()方法中开始调用refreshVisuals()方法,这个方法首先对本model做更改,然后通过((GraphicalEditPart) getParent()).setLayoutConstraint(this, getFigure(), rectangle);方法来告知父模型Diagram来做相应的处理.3. 在每一个editPart中有createEditPolicies()方法来安装editpolicies,例如这个策略为CustomXYLayoutEditPolicy,在这个策略中有createAddCommand(),createChangeConstraintCommand()执行一些具体的Commmand(例如SetConstraintCommand), 这个command如何执行又在SetConstraintCommand extends Command类中execute()方法中得到真正的执行.2.2.4 事件流:图表 2 7 事件流图Tools allow EditParts and their EditPolicies to focus on high-level operations rather than dealing with raw mouse and keyboard event data.Eventflow是一个event chain, 可以在中间处理掉后,不让他继续传递下去,也可以继续将event传递下去.SWT Control 获得event, 然后event 继续下传,可以被EditPartViewer截获和处理,接着,还可以继续下传给EditDomain,EditDomain来决定是否将event继续下传给Current tool.详细的事件流程:1. 用户点击相关可视化控件,发出鼠标或者键盘的事件.2. SWT Control 捕获到键盘或者鼠标的事件参考SWT的Canvas接口(SWT Events).3. 然后将事件传递到EditPartViewer中进行处理参考GraphicalViewer和IFigure接口.(实现类为GraphicalViewerImpl,Figure类) Draw2D系统中的LightWeightSystem,Events.4. 在EditPartViewer中处理完后,然后继续将事件传递到EditDomain中处理参考EditDomain类,5. 在EditDomain类处理完成后,继续将事件传递到Active Tool来处理参考SelectionTool,SelectEditPartTracker类 (他们superClass为TargetingTool类)6. 至此事件的传递完成.接着由Tool产生Request接口类型的request参考SelectionRequest类.7. EditPart来处理产生的request参考AbstractEditPart中的performRequest()方法, AbstractGraphicalEditPart类.8. 在EditPart中安装了EditPolicy参考GraphicalNodeEditPolicy类9. 在EditPolicy类中创建若干Command, 其中关于redo,undo操作的command 形成CommandStack(实际上就是一个ArrayList),参考CompoundCommand类.10. 到一定的时候执行Command中的execute方法.

原创粉丝点击