《Eclipse SWT/JFACE 核心应用》 清华大学出版社 22 富客户端平台(RCP)应用
RCP(Rich Client Platform)富客户端平台是基于Eclipse插件开发的一种应用。它是Eclipse 3.0 版本后新增的一项功能。通过RCP可以快速构建应用程序。
(源文件出处http://hi.baidu.com/sonmeika/blog/item/30759d0e1903a5ea37d12223.html)
22.1 RCP概述
RCP系统本质上是Eclipse的插件,但运行时却能脱离Eclipse平台而独立运行。这就使得RCP的应用更加灵活和广泛。
◆ 什么是RCP
RCP本质上是Eclipse的插件,所以当开发RCP应用程序时,可以利用Eclipse平台UI外观和框架来快速进行开发。例如创建一个菜单栏、工具栏,在RCP开发中很容易,只需要做一定的配置后,编写简单的代码就可以实现复杂的功能,这样就避免了许多重复性的工作。
RCP的系统可以脱离Eclipse平台独立运行,这样大大减少了打包程序后文件的体积,使系统更加小巧和雅观。
另外,最重要的是Eclipse是一个开源平台,所以采用RCP也可以极大的降低系统的成本。
◆ RCP应用的现状
RCP在Java桌面应用有很广阔的前景,就目前来说,已经进行了广泛的应用。主要分两大阵营,开源的和商业的。
1.开源的应用
● Azureus:http://azureus.sourceforge.net/,BitTorrent下载客户端软件,以支持40种语言,功能强大,已经被上百万的用户下载使用,并且获得了2006年Sourceforge.net的Best Overall Winner大奖。
● Bioclipse:http://www.bioclipse.net/index.php,生物信息学的一个绘图软件,可以绘制出DNA的3D图形,有兴趣的读者可以下载下来具体看一下。
● BrainBox:http://eclipsetrader.sourceforge.net/,基于RCP的股票交易软件,可以实时地查看股票信息和股票的历史走势图等。
● jCommander:http://jcommander.sourceforge.net/,基于选项卡界面效果的文件系统管理软件,可轻松地实现文件的管理。
● jFire:http://jfire.org/,基于J2EE的ERP软件,包括产品管理、客户管理、用户管理等模块,具有很灵活的自定义功能。另外,还使用了GEF和BIRT构建丰富的报表图形系统。还提供了扩展点,允许用户在此基础上进行开发。
● jLibrary:http://jlibrary.sourceforge.net/,开源的文档管理系统(DMS),可以将普通文件、视频文件和其他类型的文件进行分类,也可以进行查找和分类等。
● Zhongwen Development Tool(ZDT):http://zdt.sourceforge.net/,学习中文的一个软件,值得庆幸的是该软件是中国人开发的。
2.商业的应用
● Actuate BIRT Report Designer:http://www.actuate.com/birt,BIRT是Eclipse的一个报表开发引擎的插件,该软件是BIRT报表的设计可视化客户端软件。使用该软件可轻松地创建所需的报表。
● Bay Breeze Software - SQL Edge:http://www.baybreezesoft.com/,提供了可视化的执行SQL语句的工作环境,能够显示环境数据库中表的关系图,也能够浏览表中的数据。
● BSI CRM on Eclipse:http://www.bsiag.com/joomla/index.php,CRM客户关系管理软件,包括联系人管理、任务管理、项目管理和市场管理等。
● IBM Workplace Client Technology:http://www-128.ibm.com/developerworks/workplace/ products/clienttechnology/,IBM的客户管理软件。
注意:读者若想了解更多的RCP应用案例,可以访问网站http://www.eclipse.org/community/rcp.php。
从以上这些RCP的实现案例中可以看出,RCP的应用非常广阔,从系统的文件管理到J2EE的企业管理软件,从可视化的报表工具到3D绘图,都可以应用RCP。只要是开发桌面的应用就都可以采用RCP来进行开发。
22.2 第一个RCP项目
◆ 创建插件项目
RCP的开发是基于Eclipse插件的开发,所以创建RCP的项目也是从创建插件项目开始的。
(1)“文件”/“新建”/“项目”,在弹出的“新建项目”对话框中选择“插件项目”,如下图:
单击下一步,出现如下窗口:
(2)输入项目名称为“MyRCP”。单击“下一步”。弹出如下图所示的输入插件项目详细信息的对话框。
(3)在该对话框中设置一些插件的信息,例如输入插件标识为“com.testRCP.myrcp”,为了保存唯一性,不与其他插件混淆,一般使用网址加名称的形式。
一定要选中是否要创建富客户端应用程序选项。如果不选中,创建的只是普通的Eclipse插件项目,而不是RCP应用程序。单击“下一步”出现下图的对话框:
(4)在该对话框中,提供了创建RCP程序的几个常用的模板,这里选择Hello RCP模板。这是最简短的RCP程序,只有一个主界面。单击“下一步”出现如下对话框:
点击“完成”出现下面的提示框:
点击“Yes”完成。
◆ 运行RCP程序
创建完RCP项目后的Eclipse平台会出现如下界面:
在左侧的项目文件中,会看到自动生成了一些RCP所需要的文件,这些都是利用向导自动生成的,是RCP程序运行所必需的一些文件。右侧是该项目的描述信息。可以单击右侧的标签来查看设置具体的插件配置参数。
要运行RCP程序,有以下两种方法:
◇ 在右侧“测试”信息框中,单击“启动Eclipse应用程序”连接来运行。如果想要以调试方式运行,则单击“以调试方式启动Eclipse应用程序”链接。
◇ 用传统的方式运行RCP程序。在项目工程名称处右击,在弹出的快捷菜单中选择“运行方式”/“Eclipse应用程序”。
RCP程序运行后的界面效果如图:
点击窗口中的最小化按钮后的效果图:
◆ 插件的文件清单
(1)自动生成的各个文件如下图:
◇ src文件夹下为运行插件时的一些类文件。
◇ MANIFEST.MF为插件清单文件,是插件与外界沟通的桥梁。
◇ build.properties文件为构建RCP程序时所导入的类库设置。
◇ plugin.xml是插件的配置文件,集中管理插件内部的运行,在该文件中可以查找所有与该插件有关的信息。
(2)插件的配置信息。
◇ “概述”选项卡可以查看该插件项目所有定义配置信息。
◇ “依赖项”、“运行时”选项卡是设置MANIFEST.MF文件的,在这两个选项卡所做的修改将同步应用于MANIFEST.MF文件。在Eclipse之前的版本中,没有MANIFEST.MF文件时,是在plugin.xml文件中配置的。
◇ “扩展” 选项卡是插件开发最重要的内容,各个插件都是基于扩展点的。在该选项卡中可以设置插件所使用的扩展点,并且在选项卡中所做的配置将同步改变plugin.xml文件中的内容。
◇ “扩展点”选项卡用来设置该插件提供其他开发者的接口。如果想让其他开发人员对该插件进行开发,通常要提供这些开发人员一些接口,创建自定义的一些扩展点。
◇ “构建”选项卡可以可视化配置build.properties文件,“build.properties”选项卡可以查看该文件的源文件。
◆ MANIFEST.MF文件
MANIFEST.MF文件是保存OSGi的Bundle文件。OSGi开发服务网关协议(Open Services Gateway Initiative)是一个框架规范。OSGi规范为网络服务定义了一个标准的、面向组件的计算环境。Eclipse OSGi框架支持该规范。
通俗的讲,该文件也就是与其他平台的接口,通过该接口,外部平台可以使用该Eclipse的插件程序。
(1)MANIFEST.MF文件清单
这些信息都是以key和value值来描述的。以下是几个关键的key值所代表的意义:
◇ Bundle-Name:插件的名称。
◇ Bundle-SymbolicName:为插件的唯一标识。
◇ Bundle-Activator:为主程序启动的类的全名。
◇ Require-Bundle:系统编译和运行的依赖项,可以加入其他所必须的插件。
(2)添加依赖项
这样添加依赖项后,MANIFEST.MF文件会加入以下代码:
Require-Bundle: org.eclipse.ui,
org.eclipse.core.runtime,
org.eclipse.ant.core;bundle-version="3.2.200"
此时可以看到,刚导入的org.eclipse.ant.core自动添加到Require-Bundle的值中。
另外需要注意的是,这些类包加载是按照顺序进行的,所以可以使用“向上”和“向下”按钮进行调整。
◆ build.properties文件
该文件是保存构建、打包和导出插件所需的所有信息的文件。下图为配置构建文件的界面。在该界面上的设置会保存到build.properties文件中。此时该文件中的代码如下:
source.. = src/
output.. = bin/
bin.includes = plugin.xml,\
META-INF/,\
.
其中,source表示源文件的路径,output表示编译后的.class文件所在的路径,bin.includes表示打包后包中所包含的文件,jars.compile.order为编译的顺序。
◆ plugin.xml文件
该文件是插件开发中最重要的文件,包含声明插件的扩展和扩展点配置。
每个扩展点都是一个<extension>元素。以第一个扩展点为例,各属性意义如下:
◇ id="application",表示该扩展点的标识。
◇ point="org.eclipse.core.runtime.applications",表示扩展点的类型。这里表示该扩展点是系统扩展点,例如,另一个扩展点类型“org.eclipse.ui.perspectives”为透视图扩展点。
◇ <run>子项中定义了系统启动的class类,为com.testrcp.myrcp.Application,该文件内容如下:
无需手动输入这些配置文件,使用Eclipse自带的创建扩展点向导就可以轻松的完成创建扩展点的工作。
22.3 RCP运行的基本原理
1. 插件类MyRCPPlugin
系统运行后首先在MANIFEST.MF文件中找到Bundle-Activator所对应的插件类,本项目中是myrcp.Activator类,代码如下:
package myrcp;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
/**
* The activator class controls the plug-in life cycle
*/
public class Activator extends AbstractUIPlugin {
// The plug-in ID
public static final String PLUGIN_ID = "com.testRCP.MyRCP"; //$NON-NLS-1$
// 插件类对象,为静态对象
private static Activator plugin;
/**
* The constructor
*/
public Activator() {
}
/*
* 装载Bundle文件并启动插件
*/
public void start(BundleContext context) throws Exception {
super.start(context);
plugin = this;
}
/*
* 插件运行结束后执行该方法
*/
public void stop(BundleContext context) throws Exception {
plugin = null;
super.stop(context);
}
/**
* 返回该插件的对象
*/
public static Activator getDefault() {
return plugin;
}
/**
* 返回相对于插件包文件下的相对路径的图片文件
*
* @param path the path
* @return the image descriptor
*/
public static ImageDescriptor getImageDescriptor(String path) {
return imageDescriptorFromPlugin(PLUGIN_ID, path);
}
}
该类主要创建整个插件的对象,是插件的全局对象。可以通过该类的静态方法获得插件对象的引用,然后获得插件的各种信息,包括插件所对应的Bundle文件信息、log日志对象和工作台对象等。
MyRCPPlugin.getDefault().getBundle().getSymbolicName();
2. 应用程序类Application
创建了插件类后,程序自动查找plugin.xml文件,是否有对应的应用程序扩展点org.eclipse.core.runtime.applications。如果有,再找到该运行程序对应的class,然后创建对象。本例中为com.testrcp.myrcp.Application。代码如下:
package com.testrcp.myrcp;
import org.eclipse.equinox.app.IApplication;
/**
* This class controls all aspects of the application's execution
*/
public class Application implements IApplication {
/* (non-Javadoc)
* @see org.eclipse.equinox.app.IApplication#start(org.eclipse.equinox.app.IApplicationContext)
*/
public Object start(IApplicationContext context) throws Exception {
Display display = PlatformUI.createDisplay();
try {
int returnCode = PlatformUI.createAndRunWorkbench(display, new ApplicationWorkbenchAdvisor());
if (returnCode == PlatformUI.RETURN_RESTART)
return IApplication.EXIT_RESTART;
else
return IApplication.EXIT_OK;
} finally {
display.dispose();
}
}
/* (non-Javadoc)
* @see org.eclipse.equinox.app.IApplication#stop()
*/
public void stop() {
if (!PlatformUI.isWorkbenchRunning())
return;
final IWorkbench workbench = PlatformUI.getWorkbench();
final Display display = workbench.getDisplay();
display.syncExec(new Runnable() {
public void run() {
if (!display.isDisposed())
workbench.close();
}
});
}
}
首先创建Display对象,然后调用PlatformUI的静态方法createAndRunWorkbench创建了ApplicationWorkbenchAdvisor对象,该对象表示的是工作台对象,用于创建工作台对象。代码如下:
package com.testrcp.myrcp;
import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
import org.eclipse.ui.application.WorkbenchAdvisor;
import org.eclipse.ui.application.WorkbenchWindowAdvisor;
public class ApplicationWorkbenchAdvisor extends WorkbenchAdvisor {
// 定义默认的透视图id字符串常量
private static final String PERSPECTIVE_ID = "com.testRCP.MyRCP.perspective"; //$NON-NLS-1$
public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer) {
return new ApplicationWorkbenchWindowAdvisor(configurer);
}
public String getInitialWindowPerspectiveId() {
return PERSPECTIVE_ID;
}
}
该类继承自WorkbenchAdvisor类。由于RCP程序启动后必须指定一个默认的透视图,所以要实现getInitialWindowPerspectiveId方法,该方法返回一个透视图的ID。例如,本例中使用的是“com.testRCP.MyRCP.perspective”,表示首先在plugin.xml文件中找到id为该字符的<perspective>元素,然后根据这个id找到对应的class类。本例中对应的透视图类是Perspective。
覆盖父类中的方法createWorkbenchWindowAdvisor中将创建一个工作台的窗口类,这里创建的是ApplicationWorkbenchWindowAdvisor对象。
3. 工作台窗口类
工作台窗口类ApplicationWorkbenchWindowAdvisor代码如下:
package com.testrcp.myrcp;
import org.eclipse.swt.graphics.Point;
public class ApplicationWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor {
public ApplicationWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer) {
super(configurer);
}
// 覆盖父类中的方法,创建操作集Action,也就是菜单栏、工具栏等对应的Action
public ActionBarAdvisor createActionBarAdvisor(IActionBarConfigurer configurer) {
return new ApplicationActionBarAdvisor(configurer);
}
// 打开窗口之前对窗口进行设置
public void preWindowOpen() {
IWorkbenchWindowConfigurer configurer = getWindowConfigurer();
configurer.setInitialSize(new Point(400, 300));
configurer.setShowCoolBar(false);
configurer.setShowStatusLine(false);
configurer.setTitle("Hello RCP"); //$NON-NLS-1$
}
}
该类创建时先对工作台进行设置,在preWindowOpen方法中实现。该方法会在窗口打开之前调用。另外,也可以通过覆盖父类中的方法来进行窗口打开之前的配置工作和窗口关闭的善后处理工作。以下列举了可覆盖的方法:
◇ preWindowOpen:在打开窗口前调用该方法。
◇ postWindowRestore:窗口还原后调用该方法。
◇ postWindowCreate:窗口创建后调用该方法。
◇ openIntro:打开介绍窗口时调用该方法。
◇ postWindowOpen:当窗口打开后调用该方法。
◇ preWindowShellClose:窗口关闭前调用该方法。
◇ createActionBarAdvisor:创建菜单和工具栏。
◇ createEmptyWindowContents:当窗口中没有页面时,可在该方法中设置自定义的控件。
◇ createWindowContents:可创建自定义的工作环境,一般不需要覆盖。
4. 操作类
创建窗口时,会创建菜单栏和工具栏,此时创建的是ApplicationActionBarAdvisor对象。代码如下:
package com.testrcp.myrcp;
import org.eclipse.jface.action.IMenuManager;
public class ApplicationActionBarAdvisor extends ActionBarAdvisor {
public ApplicationActionBarAdvisor(IActionBarConfigurer configurer) {
super(configurer);
}
protected void makeActions(IWorkbenchWindow window) {
}
protected void fillMenuBar(IMenuManager menuBar) {
}
}
在该类中,可以添加各种操作性来创建菜单栏、工具栏和状态栏等。
5. 透视图类
在创建工作台对象时,要指定一个默认的透视图对象。本例中是Perspective类:
package com.testrcp.myrcp;
import org.eclipse.ui.IPageLayout;
public class Perspective implements IPerspectiveFactory {
public void createInitialLayout(IPageLayout layout) {
}
}
22.4 创建扩展的基本方法
Eclipse已经提供了很好的配置扩展的工具,不用输入代码去配置,而是通过UI界面就可以完成。
1. 使用扩展向导创建
Eclipse内置了一些常用的扩展点扩展的模板。使用向导扩展的步骤如下:
(1)在“扩展”选项卡中单击“添加”按钮,如下图:
(2)在弹出的“新建扩展”对话框中选择“扩展向导”选项卡,在右侧的列表框中显示了一些已有的扩展模板,这里选择第一项,创建操作的扩展模板,如下图:
(3)单击“下一步”,按照选择的模块进行进一步的设置。这里使用默认值,然后单击“完成”按钮。这样一个扩展自org.eclipse.ui.actionSets的扩展就完成了。
左侧列表中显示的是所有已扩展的元素。当单击左侧的一个扩展时,右侧会出现该扩展元素的详细信息,然后可以在这里进行扩展的配置。配置完成后,plugin.xml文件中将会自动生成想要的源代码。如下:
<extension
point="org.eclipse.ui.actionSets">
<actionSet
id="com.testRCP.MyRCP.actionSet"
label="Sample Action Set"
visible="true">
<menu
id="sampleMenu"
label="Sample &Menu">
<separator
name="sampleGroup">
</separator>
</menu>
<action
class="com.testrcp.myrcp.actions.SampleAction"
icon="icons/sample.gif"
id="com.testrcp.myrcp.actions.SampleAction"
label="&Sample Action"
menubarPath="sampleMenu/sampleGroup"
toolbarPath="sampleGroup"
tooltip="Hello, Eclipse world">
</action>
</actionSet>
</extension>
Eclipse提供的模板是有限的,若所要创建的扩展没有提供的模板,就需要手工创建了。
2. 手工创建
手工创建扩展步骤如下:
(1)与向导创建扩展的第一步相同,在“扩展”选项卡中单击“添加”按钮,然后在弹出的“新建扩展”对话框中选择“扩展点”选项卡,如下图:
(2)在列表中显示了所有可用的扩展点。若选择下方的“中显示必需插件中的扩展点”复选框,列表中显示的是必要的扩展点。取消选中该复选框则会显示更多扩展点。这里选中org.eclipse.ui.views扩展点,单击“完成”按钮。
(3)这样就创建了简单的扩展点。在“扩展”选项卡界面上选中刚才创建的扩展,单击鼠标右键,出现下图的快捷菜单:
NEW菜单中只有Geniric,需要下载 Eclipse for RCP/Plug-in Developers,网址是:http://www.eclipse.org/downloads/moreinfo/rcp.php
使用Eclipse for RCP/Plug-in Developers后,上述图片变为下图的样子:
(4)选择“新建”命令后会弹出子菜单,子菜单中可以创建的元素为当前扩展点可用的元素。可创建的元素也会根据所选的扩展点而异。创建完后,plugin.xml文件中自动增加了以下扩展点配置信息:
<extension
point="org.eclipse.ui.views">
<view
class="myrcp.ViewPart1"
id="myrcp.view1"
name="name">
</view>
</extension>
在class的一行出现警告,点击后就可以创建对应的类了。
当然,手工配置的方式只是自动添加了配置文件,而扩展点所对应的类并没有自动创建,这些类需要手工去创建。
3. 获取扩展点的帮助
Eclipse为扩展提供了很边界的查看帮助的方式。
(1)在每个扩展点详细信息的下方都有两个工具链接,如下图:
(2)单击下方的“打开扩展点描述”链接,将会弹出该扩展点所对应的扩展点描述视图。如下图:
在扩展点的描述信息中一般会有以下内容:
◇ Identifier:扩展点的标识,也就是扩展点的类型。例如,透视图的扩展点为org.eclipse.ui.perspective。
◇ Description:扩展点的描述信息,包括该扩展点的用途等。
◇ Configuration Markup:xml标记的Schema,也就是说哪些元素是必需的,哪些元素是可选的,以及每个元素所表示的意义。
◇ Examples:该扩展点配置的一个具体示例。
◇ API Information:该扩展点所使用的类需要实现的一些接口。
◇ Supplied Implementation:Eclipse平台中已经实现该扩展点的类。例如,在操作扩展点,Eclipse已经实现了一些“打开文件”、“退出”系统等常用的操作扩展,在开发是可以直接使用这些扩展。