前面讲到了从eclipse平台下直接导出的rcp应用程序模板中核心类的功能。在项目的研发过程中,不同的窗体总体上代表了不同的功能。因此,我们有时需要调用另外一个工作台窗体窗体来表现另外一个系统模块的功能,而这个活动窗体也需要像需要像主窗体一样,要展示对应的导航树,鹰眼图等,需要在子窗体和主窗体中切换。怎么实现这个功能呢?
调用另外一个工作台窗体(活动的),实际上就是新生成一个新的工作台窗体,并给这个新的工作台窗体配置相关的菜单、工具栏。前面讲到,我们在Rcp的核心类Application里已经生成了一个工作台,我们需要打开在此基础上新打开一个工作台窗体,具体的方式如下:
PlatformUI.getWorkbench().openWorkbenchWindow(null);
然后,我们在为这个WorkbenchWindow来配置一些菜单,工具栏,就达到我们的要求了。
下面,我们详细的说明是如何实现这些功能的:
在3.1版本以后,前面讲到要生成一个工作台窗体,调用了Application,WorkbenchAdvisor,WorkbenchWindowAdvisor,ActionBarAdvisor。处了Application用来创建工作台,其他的类都用来配置工作台窗体,我们新打开一个工作台窗体时,也需要用这些类来配置工作台窗体。WorkbenchAdvisor,WorkbenchWindowAdvisor不用重新定义,用来配置新工作台窗体菜单、工具栏,我们则必须另外实现接口ActionBarAdvisor了。
于是,我们引入了一个新类,WorkbenchActionBuilder,通过这个类,我们来调用不同窗体actionbar生成器(即实现不同窗体的菜单、工具栏)。
package com.jdenght.rcpstudy.action;
import org.eclipse.ui.application.ActionBarAdvisor;
import org.eclipse.ui.application.IActionBarConfigurer;
import org.eclipse.ui.application.WorkbenchWindowAdvisor;
import com.jdenght.rcpstudy.MainActionBarAdvisor;
import com.jdenght.rcpstudy.Child_1_ActionBarAdvisor;
public final class WorkbenchActionBuilder {
private IActionBarConfigurer Ibarconfigurer;
private WorkbenchWindowAdvisor workbenchWindowAdvistor;
private ActionBarAdvisor actionBarAdvisor;
public WorkbenchActionBuilder(IActionBarConfigurer Ibarconfigurer) {
this.Ibarconfigurer = Ibarconfigurer;
}
public ActionBarAdvisor makeWinAction(){
switch(WorkbenchControler.flag){
case WorkbenchControler.main:
actionBarAdvisor = new MainActionBarAdvisor(Ibarconfigurer);
break;
case WorkbenchControler.child_1:
actionBarAdvisor = new Child_1_ActionBarAdvisor(Ibarconfigurer);
break;
case WorkbenchControler.child_2:
actionBarAdvisor = new MainActionBarAdvisor(Ibarconfigurer);
break;
}
return actionBarAdvisor;
}
public void dispose() {
workbenchWindowAdvistor.dispose();
}
}
如上所述,当当前打开的为主窗体时,调用MainActionBarAdvisor,为主窗体来配置菜单、工具栏等,当当前打开的为子窗体时,调用一个子窗体的菜单、工具栏生成类Child_1_ActionBarAdvisor。
于是,有人会提到,我们在哪里调用WorkbenchActionBuilder这个类呢,这个类怎样让它调用不同的工具栏生成器呢?WorkbenchControler有什么作用呢?
这个类是在WorkbenchWindowAdvisor的实现类中调用的,让我们来看看代码:
package com.jdenght.rcpstudy;
import org.eclipse.ui.application.ActionBarAdvisor;
import org.eclipse.ui.application.IActionBarConfigurer;
import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
import org.eclipse.ui.application.WorkbenchWindowAdvisor;
import com.jdenght.rcpstudy.action.WorkbenchActionBuilder;
public class ApplicationWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor {
private WorkbenchActionBuilder fActionBuilder;
public ApplicationWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer) {
super(configurer);
}
public ActionBarAdvisor createActionBarAdvisor(
IActionBarConfigurer configurer) {
if (fActionBuilder == null)
fActionBuilder = new WorkbenchActionBuilder(configurer);
return fActionBuilder.makeWinAction();
}
public void preWindowOpen() {
IWorkbenchWindowConfigurer configurer = getWindowConfigurer();
// configurer.setShowCoolBar(true);
// configurer.setShowStatusLine(true);
configurer.setTitle("网络资源管理系统");
}
}
在rcp应用程序学习一中,在createActionBarAdvisor()是这样定义的:
return new ApplicationActionBarAdvisor(configurer);
它直接返回了一个菜单栏,工具栏的生成器。现在,我们让fActionBuilder.makeWinAction()来返回对应的当前窗体需要的actionbar(菜单,工具栏)生成器了。
下面,我们在看看WorkbenchControler里有什么:
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
public class WorkbenchControler {
//不同的工作台窗体代表的值
public final static int main = 1;
public final static int child_1 = 2;
public final static int child_2 = 3;
//默认值为1,作为菜单的标示位,如当切换到child_2子系统是,flag的值则变为3了
public static int flag = 1;
//eclipse提供的窗口句柄
static public IWorkbenchWindow mainUI = null;
static public IWorkbenchWindow child_1_UI = null;
static public IWorkbenchWindow child_2_UI = null;
//初始化主窗体
static{
mainUI = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
}
}
这个类中定义了一下几个内容:
1) 工作台窗体的标识值(main、child_1、child_2)
2) 工作台窗体的标识为flag,默认值为1,即打开
3) 工作台窗体句柄:mainUI,child_1_UI,child_2_UI
4) 默认为主窗体赋值,得到当前的活动工作台窗体。
当我们系统初次启动的时候,工作台主窗体已经生成,但通过WorkbenchActionBuilder,我们为主窗体定义了菜单栏和工具栏(flag的默认值为1)。
那我们怎么打开子窗体的呢?
我们在主窗体中定义菜单,通过菜单来调用子窗体。Rcp应用程序种,菜单和工具栏实际上是一个action。关于菜单栏和工具栏的功能我们在下节讲述。现在我们来看看主窗体中是如何来调用子窗体的。在主窗体的菜单和工具栏生成器类MainActionBarAdvisor中,有这样一个方法:
//创建切换到子窗体菜单
private MenuManager createOpenWindowsMenu(){
MenuManager openWindows = new MenuManager("&Change",
IWorkbenchActionConstants.M_EDIT);
openWindows.add(new Separator());
openWindows.add(new OpenWindowsAction(WorkbenchControler.child_1));
openWindows.add(new Separator());
openWindows.add(new OpenWindowsAction(WorkbenchControler.child_2));
return openWindows;
}
如图所示,实际上打开的两个菜单是通过new OpenWindowsAction(WorkbenchControler.child_1)来实现的,而参数WorkbenchControler.child_1代表需要打开的活动子窗体的标示值。下面,我们看看这个OpenWindowsAction怎么实现:
package com.jdenght.rcpstudy.action;
import org.eclipse.jface.action.Action;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.WorkbenchException;
public class OpenWindowsAction extends Action {
IWorkbenchWindow window;
int flag = -1;
public OpenWindowsAction(int flag){
this.flag = flag;
String name="";
switch(flag){
case WorkbenchControler.main:
name = "公共资源管理";
break;
case WorkbenchControler.child_1:
name = "数据网资源管理";
break;
case WorkbenchControler.child_2:
name = "交换网资源管理";
break;
}
this.setText(name);
this.setToolTipText(name);
this.setEnabled(true);
}
public void run(){
WorkbenchControler.flag = flag;// 将目前打开的窗体菜单对应的标示值传递到控制器中
IWorkbenchWindow window = null;
try {
switch (WorkbenchControler.flag) {
case WorkbenchControler.main:
if (WorkbenchControler.mainUI == null
|| WorkbenchControler.mainUI.getShell() == null) {
WorkbenchControler.mainUI =PlatformUI.getWorkbench().openWorkbenchWindow(null);
}
window=WorkbenchControler.mainUI;
window.getShell().setText("网络资源管理系统——公共系统管理");
break;
case WorkbenchControler.child_1:
if (WorkbenchControler.child_1_UI == null
|| WorkbenchControler.child_1_UI.getShell() == null) {
WorkbenchControler.child_1_UI =PlatformUI.getWorkbench().openWorkbenchWindow(null);
}
window=WorkbenchControler.child_1_UI;
window.getShell().setText("网络资源管理系统——数据系统管理");
break;
case WorkbenchControler.child_2:
if (WorkbenchControler.child_2_UI == null
|| WorkbenchControler.child_2_UI.getShell() == null) {
WorkbenchControler.child_2_UI =PlatformUI.getWorkbench().openWorkbenchWindow(null);
}
window=WorkbenchControler.child_2_UI;
window.getShell().setText("网络资源管理系统——交换网资源管理");
break;
}
//接下来,可以在这个地方控制不同活动窗体的视图的显示
} catch (WorkbenchException e) {
e.printStackTrace();
}
}
}
如上代码所示:这个类分为两个部分,一个构造方法,一个run()方法。在构造方法中,我们定义了菜单名称、ToolTip等。在run方法中,我们打开了工作台活动窗体。我们在打开菜单时调用OpenWindowsAction(),传了一个参数WorkbenchControler.child_1,,在run()中,执行
case WorkbenchControler.child_1:
if (WorkbenchControler.child_1_UI == null
|| WorkbenchControler.child_1_UI.getShell() == null) {
WorkbenchControler.child_1_UI =PlatformUI.getWorkbench().openWorkbenchWindow(null);
}
window=WorkbenchControler.child_1_UI;
window.getShell().setText("网络资源管理系统——数据系统管理");
大家注意到,这个case域中最重要的就是:
WorkbenchControler.child_1_UI =PlatformUI.getWorkbench().openWorkbenchWindow(null);
openWorkbenchWindow()用来打开一个活动的工作台窗体。
注意:现在新建了一个工作台窗体之后,还需要对新建的活动窗体进行配置,这个时候,rcp应用程序重新的执行ApplicationWorkbenchAdvisor中的createWorkbenchWindowAdvisor()方法,然后配置菜单项,工具栏,然后打开一个活动窗体了。然后再执行下面的两句代码。下面的两句代码则是为新打开的窗体设置名称了。要不然,它会继续沿用ApplicationWorkbenchWindowAdvisor的preWindowOpen()里定义的主窗体的窗体名称了。
先在总结一下获得子窗体打开的过程:在菜单项的openWindowAction中新建一个工作台窗体,然后给这个工作台窗体创建菜单、工具栏,通过WorkbenchActionBuilder调用不同窗体的菜单,最后子窗体就打开了。生成子窗体最核心的类有:WorkbenchControler(工作台窗体的句柄控制器);一个OpenWindowsAction,打开子活动窗体的action;一个WorkbenchActionBuilder,工作台窗体的菜单项,工具栏构建器。
上述基本上完成了我们需要的功能,但我们还需要自定义一个退出菜单,exitaction,如果我们不做任何处理,还继续沿用以前的退出action,再针对子菜单进行退出时,主窗体也随之退出了(默认的退出菜单为单例模式的)。因此,我们需要针对退出做出相应的处理。当我们打开两个窗体时,使它满足:退出主窗体时,所有的子窗体也随之退出,退出子窗体时,主窗体可不用退出。
实现的方式如下:
import org.eclipse.jface.action.Action;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.ui.IWorkbenchWindow;
import com.jdenght.rcpstudy.util.ValidateOrTurnUtil;
import com.jdenght.rcpstudy.util.WorkbenchUtil;
public class ExitAction extends Action {
public ExitAction(){
this.setText("退出");
this.setToolTipText("退出");
this.setEnabled(true);
}
public void run(){
//做退出处理,首先判断是否为主窗体,如果为主窗体,则所有子窗体全部退出,
//如果为子窗体,则只单单的退出子窗体,而主窗体则不用退出
if(WorkbenchUtil.getActiveWorkbenchWindow()==WorkbenchControler.mainUI){
//所有的窗体都需要退出
doAllClose(true);
}else{
//退出子窗体
doSClose(true);
}
}
//退出所有窗体
private boolean doAllClose(boolean flag){
if(WorkbenchUtil.getActiveWorkbenchWindow()==WorkbenchControler.mainUI){
IWorkbenchWindow[] iWorkbenchWindows = WorkbenchUtil.getWorkbenchWindows();
if(ValidateOrTurnUtil.ifValid(iWorkbenchWindows)){
if(MessageDialog.openConfirm(null,"提示","确定要退出系统吗?")){
for(int i=0;i<iWorkbenchWindows.length;i++){
iWorkbenchWindows[i].close();
}
System.exit(0);
return true;
}
}
}
return false;
}
//退出当前的窗体
private boolean doSClose(boolean flag){
if(MessageDialog.openConfirm(null,"提示","确定要退出系统吗?")){
WorkbenchUtil.getActiveWorkbenchWindow().close();
if(WorkbenchUtil.getWorkbenchWindowCount()>=1){
WorkbenchControler.mainUI.getShell().setMaximized(true);
WorkbenchControler.mainUI.getShell().setFocus();
return true;
}
}
//MessageDialog.o
return false;
}
}
有两个主要的方法:doAllClose()关闭所有的窗体。doSClose()关闭当前选择的窗体。判断 件为:WorkbenchUtil.getActiveWorkbenchWindow()==WorkbenchControler.mainUI,如果当前选择的为主窗体,则调用doAllClose方法,如果不是,则调用doSClose关闭当前选择的窗体。