快速掌握Eclipse Plugin / RCP开发思想
本文转载:https://my.oschina.net/drjones/blog/280337
引言
本文不是快速入门的文章,只面向有一定基础的开发人员,至少看这篇文章之前你应该了解什么是Eclipse,什么是RCP,什么是Plugin,什么是架构,什么是软件框架等等概念。否则的话这篇文章也帮不了你什么。另外,本人对RCP的理解也是处于一知半解的程度,如有错误还请指出。
Eclipse是一种面向开发人员的编程环境(IDE),同时它也是一个很好的平台,它提供了一种架构,或者说一种软件框架,可以让开发人员相对比较容易的开发出功能比较强大的,带有人机交互功能的应用程序。
Eclipse这种强大的功能是通过其插件(Plugin)来实现的,RCP也是如此。RCP的全称是Rich Client Platform,其根本就是把Eclipse的应用平台剥离了其他的插件之后剩下的东西,自然其架构和原理与eclipse本身是一样的。RCP也可以通过插件来进行扩展,但RCP往往是用来开发一些像Eclipse一样独立的应用程序。
本文帮助对RCP不是很清楚的人快速的理解Eclipse RCP和Plugin的工作原理与开发方法。
基本知识
让我们闭上眼睛静下心来冥想一下,我们可以想象,如果要开发一个带有人机交互的应用程序,必备的几个部分是什么?
1 人机界面。人机界面在某些应用程序中基本上就可以当成是软件的核心了,特别是一些轻量级的应用中。VB这方面做的就很好,它基本上就是一个以界面为核心的开发环境,我曾经在上课的时候讲过,VB编程基本上就两步,第一步画好界面,第二步写界面的响应代码(事件处理程序)。这个思路基本上可以解决百分之八十的Vb编程应用。人机界面实际上是人机交互的一部分,它可以将各种数据用图形化的方法呈现给操作者。虽然有人会认为人机界面还应当包括用户对界面操作所作出的响应,例如用户在用鼠标点击按钮时按钮的按下效果等,但这本质上还是属于可视界面的范畴,而且是提前预定好的,并不是一种真正的交互。
2 数据模型。这在应用程序中是至关重要的,因为界面所显示的内容主要是从数据模型中获取的,另外用户通过界面录入的数据也是要存储到数据模型中去的。这也是软件存在目的之一,获取数据,管理数据和修改数据等。对于数据和数据模型,一般的程序员都有着深刻的理解,这里就不赘述了。不是一度计算机软件被宣称等于数据加算法的吗?
3 用户命令输入。人机交互的另一部分,即用户可以通过人机界面输入(或者释放)相应的命令。在目前的人机交互模型中,用户命令的输入通常是通过一些控件来实现的,例如按钮,文本框,快捷键,菜单等。在触摸界面中还包括手势,在智能系统中甚至包括语音等。
4 业务逻辑。这是软件的主要功能,也是用户需求的集中体现。业务逻辑通常是用户命令激发的,包括对数据进行分析和处理,并获得新的可供展示的数据的过程。当然也有一些业务逻辑是在后台执行的。
用图形的方式来展示这四个部分的功能:
大家都是做软件开发的,不知道大家有没有想过,这四个部分其实是可以做到相互之间是独立的。其实大家都知道有一个著名的MVC模型(Model-View-Control)模型和这个基本上是一样的。但是MVC我一直以来也没有搞明白其中的Control是什么功能,所以我认为我上面提出的四个部分的功能分解是比较好理解的。
在Eclipse的框架里,由于Eclipse是面向人机交互的,所以在框架里是不包含数据模型这一块的,业务逻辑这块也只包括用户命令处理这一部分,其框架的大部分功能都集中在人交互这块。用图形表述一下是这样的:
Eclipse Platform的名词介绍
接下来介绍一下Eclipse里的常用到的术语。
界面
首先看一下界面部分。下图是Eclipse应用程序的界面。
界面最外面的叫做Workbench Window。也是应用程序最顶层的界面模块。一般来说一个应用会有一个Workbench Window,不过根据Eclipse的手册说明,其实也可以有多个Workbench Window,但是怎么实现还不清楚,目前接触的例子都是单窗口的。
Workbench Window包含了主菜单(Menu Bar),工具条(Tool Bar),状态条(Status Bar)和一个页面Page。这些都是典型的GUI程序锁必备的。
页面Page是应用程序窗口的主界面,也是工作区界面。Page里包括各种的View和Editor,View,Editor都称为Part。所以View也称为ViewPart,Editor也称为EditorPart。View和Editor的区别在于:View通常是用来显示目录树,属性窗口,文档结构图等类似内容,可以把View看成是数据在某个功能界面上的反映,而且View所做的修改会立刻生效。Editor顾名思义是用来编辑文档的,或者修改文档内容的,Editor所做的修改必需通过专门的保存命令进行存储生效。在Editor界面关闭的时候会检查文档内容是否为“脏”,并提示用户保存为“脏”的文档。除此之外,两者太大的区别。
在编程行为上看,editor和View最大区别就是:同一类(来自同一个类)的View在界面中只能有一个,而同一类的Editor可以有多个,但是同一个文档只能打开一个对应的Editor。
扩展点(Extension Point)
Eclipse的插件开发全靠扩展点这个玩意了。扩展点顾名思义就是开发者可以对原程序进行功能和界面扩展的地方。
我的理解,扩展点就是应用程序留下来的插座,扩展程序通过使用扩展点,可以把自己编写的代码接入到原有程序中。但是不同的扩展点,可以接入的东西是不一样的,需要程序员仔细体会。从Java程序开发的角度来看,只要写的类使用了约定的接口,就可以被平台类加载和调用。从这个意义上来讲,扩展点接入的实际上不是代码,而是对接入代码的描述。通过扩展点接入的声明,可以告诉Eclipse平台,使用什么功能的时候调用什么类,新的插件提供了哪些功能,或者扩展了原有的哪些功能等。从这个意义上将,扩展点本质上是配置信息。
RCP中的扩展点非常多,而且RCP甚至还允许开发者创建新的扩展点!所以,这里我们只给大家介绍一下RCP中的基本的扩展点。
需要说明的是,RCP中强调的是尽量的少写代码。特别是界面这块,因此,大部分的界面相关的东西都是可以通过扩展点实现的。当然有很多功能用代码也可以实现,但是简单的用XML配置文件就可以实现一个界面岂不是更好吗?
扩展点使用方法
org.eclipse.ui.views
这个扩展点定义了系统当中的所有的View。
<extension point = "org.eclipse.ui.editors"> <editor class="org.eclipse.ui.examples.contributions.editor.InfoEditor" icon="icons/editor.gif" id="org.eclipse.ui.examples.contributions.editor" name="%contributions.editor.name"> </editor> </extension>
Category主要用于分类参数配置。Eclipse有自己专门的参数设置界面,属于同一个Category的类会出现在同一个设置面板中,其他没有什么作用。
这里可以用自己写的View,也可以用别人已经写好的View,class这个选项的值指向的是具体运行这个视图的类。这个View的代码需要自己写,必需继承ViewPart这个虚拟类或者实现IViewPart这个接口。
org.eclipse.ui.editors
这个扩展点下面要给出软件系统中所有的Editor。
<extension point = "org.eclipse.ui.editors"> <editor class="org.eclipse.ui.examples.contributions.editor.InfoEditor" icon="icons/editor.gif" id="org.eclipse.ui.examples.contributions.editor" name="%contributions.editor.name"> </editor> </extension>
Editor有自己特有的一些属性,例如extension属性,可以指定editor能够打开的文件类型等。对于某些不需要编辑器的应用,可以忽略这部分内容,因为大部分的不需要编辑器的应用实际上不需要Editor,只需要View。
org.eclipse.ui.commands
这个扩展点里面收集了大量的命令。之前一节讲到了命令这个概念,大家千万不要误会这里的命令。这里的命令指的是用户可以通过界面产生的命令,但是这里的命令是没有实现的。也就是说,你可以在这里自己定义大量的命令,但可以自己不实现,等待后续有人写新的扩展来实现你制定的命令。当然,绝大多数我们写的程序不会期望别人来帮我们写代码,自己还是要写代码来实现这里的命令的,但是我们写的代码不会在这里有体现,而是体现在后面要讲的handler里。
<extension point="org.eclipse.ui.commands"> <command categoryId="org.eclipse.ui.examples.contributions.commands.category" id="org.eclipse.ui.examples.contributions.view.count" description="%contributions.view.count.desc" name="%contributions.view.count.name"> </command> <category name="%contributions.commands.category.name" description="%contributions.commands.category.desc" id="org.eclipse.ui.examples.contributions.commands.category"> </category> </extension>
org.eclipse.ui.menus
这个扩展点对于咱们编程序的人来说太重要了。前面我们刚看到了command,会疑惑说,command实际上就是一个花架子,其实什么都不做,这样子弄个command什么用处呢?用处太大了。Command好比定义了用户的一条指令,比方说在View上弄个曲线什么的。但是这个指令怎么发出的呢?Command这个扩展点并没有说明,原因就是要留到这里说。Menus这个扩展点里要定义的,就是用户的Command如何发出的问题。
一般情况下,用户的command主要通过人机界面发出,常用到的控件为菜单,工具条,快捷键等。快捷键暂且不表,这里主要定义了菜单(各种类型)以及工具条。
<extension point="org.eclipse.ui.menus"> <menuContribution locationURI="menu:org.eclipse.ui.examples.contributions.view?after=additions"> <command commandId="org.eclipse.ui.examples.contributions.view.count" mnemonic="%contributions.view.count.mnemonic"> </command> <command commandId="org.eclipse.ui.examples.contributions.view.edit" mnemonic="%contributions.view.edit.mnemonic"> </command> <command commandId="org.eclipse.ui.file.refresh" mnemonic="%contributions.view.refresh.mnemonic"> </command> </menuContribution> ...
一个MenuContribution就定义了一个菜单。Command标签定义了菜单对应的命令。通过这些文本,就将菜单与命令结合了起来。Command里的label属性定义了菜单的标签,自然也可以定义图标,菜单的属性(push,还是radio),以及tooltip等。
其中一个很重要的属性是locationURI。它定义了菜单在什么地方显示。下面几个例子有所说明:
menu:org.eclipse.ui.main.menu?after=window
在主菜单中插入菜单
menu:file?after=additions
同上
menu:org.eclipse.ui.views.ContentOutline?after=additions
在View上显示菜单(又叫做快捷菜单)
toolbar:org.eclipse.ui.views.ContentOutline?after=additions
在View上的工具条位置上显示菜单(实际上是工具按钮)
popup:org.eclipse.ui.examples.propertysheet.outline?after=additions
在某个View上显示弹出菜单(右键菜单)
可见,通过上述方法,可以定义任意地方上的菜单,工具条等。关键的一点是,你不需要写任何代码,非常的爽。
org.eclipse.ui.handlers
尽管在界面上放置菜单是不需要写任何代码的,但是对命令的处理时必须要写代码的,这个时候就需要handler扩展了。
Handler是对命令的实现。可以放在这里:
<command categoryId="org.eclipse.ui.examples.contributions.commands.category" defaultHandler="org.eclipse.ui.examples.contributions.handlers.GlobalMenuHandler" id="org.eclipse.ui.examples.contributions.commands.globalCommand" name="%contributions.commands.globalCommand.name"> </command>
也可以放在这里:
<handler class="org.eclipse.ui.examples.contributions.handlers.GlobalMenuHandler" commandId="org.eclipse.ui.examples.contributions.commands.globalCommand"> </handler>
无非就是将实现类与commandid关联起来。这个实现类必须要继承AbstractHandler或者实现IHandler接口。
需要说明的是,一个命令可以有多个Handler,因为每个handler有自己的scope(作用域),一般说来,越具体的UI组件所实现的Handler具有越高的优先级。不过这个属于比较高级的话题,感兴趣的可以去研究一下Eclipse的帮助文档。(注:此段可能有误)
RCP程序的开发方法
这里简明扼要的介绍一个RCP应用程序的开发方法,类似介绍网上较多,可以去搜索学习。
一般情况下利用向导得到的应用程序,代码里包括这么几个文件:
Application.java这个文件里包括了应用程序的一些信息,包括启动界面和关闭界面。如果你需要在打开界面的时候做一些事情(例如让用户输入验证密码等),可以在这个文件里进行处理。
ApplicationWorkbenchAdvisor.java这个文件用来配置平台的一些信息。这个里面一个重要的方法是返回默认的Perspective。
ApplicationWorkbenchWindowAdvisor.java这个文件用来配置窗口的一些属性的。
ApplicationActionBarAdvisor.java是用来配置工具栏的。
最重要的是配置plugin.xml这个文件。Eclipse提供了各种的辅助工具来编辑这个文件,里面最重要的是这个extensions标签。这个可以用右键添加各种item。最重要的是用来编辑menus,views,commands和handlers。其属性在前面已经介绍过了,如果有不明白的可以查阅帮助。