在使用Eclipse RCP進行桌面程序開發(一):快速起步中,我們通過Eclipse的插件開發向導,逐步建立了一個RCP應用程序,但是,這個程序沒有任何功能,難以激起我們學習的興趣。在這一節,我們將一起探索怎樣在程序中添加菜單和工具條。先看一下成果:
圖一、圖二:帶有菜單和工具條的RCP程序


圖三:工具欄上的按鈕的提示文本

圖四:點擊菜單項或者工具欄按鈕后,彈出一個簡單的對話框。

這里需要說明一點,為什么要在講菜單和工具欄的時候一起講對話框,這是因為對話框是我們所能想到的最簡單最直接的用戶交互方式,在對話框上可以添加各種各樣的控件來實現復雜的功能,為了讓我們點擊菜單項的時候能夠看到效果,這里就用了一個簡單的對話框。當然,當我們以后接觸到視圖、編輯器和透視圖這樣的概念之后,我們能使用的用戶交互方式就不僅僅只是對話框了。
打開我們上一節使用向導建立的工程,可以發現工程下面自動生成了如下文件:
Application.java
ApplicationWorkbenchAdvisor.java
ApplicationWorkbenchWindowAdvisor.java
ApplicationActionBarAdvisor.java
Perspective.java
plugin.xml
這里的Application.java是我們整個程序的入口點,我們的程序運行的時候,會先執行Application的run方法,run方法的代碼如下:
?1
public
?Object?run(Object?args)?
throws
?Exception?
{
?2
????????Display?display?
=
?PlatformUI.createDisplay();
?3
????????
try
?
{
?4
????????????
int
?returnCode?
=
?PlatformUI.createAndRunWorkbench(display,?
new
?ApplicationWorkbenchAdvisor());
?5
????????????
if
?(returnCode?
==
?PlatformUI.RETURN_RESTART)?
{
?6
????????????????
return
?IPlatformRunnable.EXIT_RESTART;
?7
????????????}
?8
????????????
return
?IPlatformRunnable.EXIT_OK;
?9
????????}
?
finally
?
{
10
????????????display.dispose();
11
????????}
12
????}
在第4行我們可以看出,該入口函數將創建用戶界面的工作交給了ApplicationWorkbenchAdvisor類。接著,我們打開ApplicationWorkbenchAdvisor.java,代碼如下:
?1
public
?
class
?ApplicationWorkbenchAdvisor?
extends
?WorkbenchAdvisor?
{
?2
?3
????
private
?
static
?
final
?String?PERSPECTIVE_ID?
=
?
"
cn.blogjava.youxia.rcp_start.perspective
"
;
?4
?5
????
public
?WorkbenchWindowAdvisor?createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer?configurer)?
{
?6
????????
return
?
new
?ApplicationWorkbenchWindowAdvisor(configurer);
?7
????}
?8
?9
????
public
?String?getInitialWindowPerspectiveId()?
{
10
????????
return
?PERSPECTIVE_ID;
11
????}
12
}
可以看出,這個類的工作就是為我們的程序指定默認的透視圖,然后把創建窗口的工作交給了ApplicationWorkbenchWindowAdvisor類。接著,我們打開ApplicationWorkbenchWindowAdvisor.java文件,看到代碼如下:
?1
public
?
class
?ApplicationWorkbenchWindowAdvisor?
extends
?WorkbenchWindowAdvisor?
{
?2
?3
????
public
?ApplicationWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer?configurer)?
{
?4
????????
super
(configurer);
?5
????}
?6
?7
????
public
?ActionBarAdvisor?createActionBarAdvisor(IActionBarConfigurer?configurer)?
{
?8
????????
return
?
new
?ApplicationActionBarAdvisor(configurer);
?9
????}
10
????
11
????
public
?
void
?preWindowOpen()?
{
12
????????IWorkbenchWindowConfigurer?configurer?
=
?getWindowConfigurer();
13
????????configurer.setInitialSize(
new
?Point(
600
,?
450
));
14
????????configurer.setShowCoolBar(
true
);
15
????????configurer.setShowStatusLine(
false
);
16
????????configurer.setTitle(
"
第一個RCP程序
"
);
17
????????
18
????}
19
???????
20
}
這個類的功能很強大,我們可以重載它的preWindowCreate、postWindowCreate、preWindowOpen、postWindowOpen等方法,以便修改我們窗口的外觀。在這里可以看出,我們重載了preWindowOpen方法來設置窗口的大小和讓工具欄可見。很顯然,這個類的另外一個功能,就是把創建菜單和工具欄的任務交給了ApplicationActionBarAdvisor類。
到這里,謎底已經揭曉,要創建我們自己的菜單和工具條,就一定是在ApplicationActionBarAdvisor.java中做文章了。不錯,打開這個文件,我們可以看到這個類有兩個重要的方法:
protected void makeActions(IWorkbenchWindow window);
protected void fillMenuBar(IMenuManager menuBar);
我們可以在makeActions方法中創建我們的Action,什么是Action呢?Action是jface中的一個概念,在jface中通過org.eclipse.jface.action中的Action和ActionContributionItem類實現了視圖和處理代碼的分離,這樣無論何時用戶觸發了一個控件的事件,都會激活一個相應的Action類實例來進行時間處理。毫無疑問,我們的菜單項是一個Action類的子類了。
下面請看ApplicationActionBarAdvisor.java的源代碼:
?1
package
?cn.blogjava.youxia.rcp_start;
?2
?3
import
?org.eclipse.jface.action.IMenuManager;
?4
import
?org.eclipse.jface.action.MenuManager;
?5
import
?org.eclipse.ui.IWorkbenchWindow;
?6
import
?org.eclipse.ui.application.ActionBarAdvisor;
?7
import
?org.eclipse.ui.application.IActionBarConfigurer;
?8
import
?org.eclipse.ui.actions.ActionFactory.IWorkbenchAction;
?9
import
?cn.blogjava.youxia.actions.Action1;
10
11
public
?
class
?ApplicationActionBarAdvisor?
extends
?ActionBarAdvisor?
{
12
????
13
????
private
?IWorkbenchAction?action1;
14
15
????
public
?ApplicationActionBarAdvisor(IActionBarConfigurer?configurer)?
{
16
????????
super
(configurer);
17
????}
18
19
????
protected
?
void
?makeActions(IWorkbenchWindow?window)?
{
20
????????action1?
=
?
new
?Action1(window);
21
????????action1.setText(
"
第一個菜單項
"
);
22
????????action1.setId(
"
cn.blogjava.youxia.actions.action1
"
);
23
????????register(action1);
24
????}
25
26
????
protected
?
void
?fillMenuBar(IMenuManager?menuBar)?
{
27
????????MenuManager?newMenu?
=
?
new
?MenuManager(
"
第一個菜單
"
,
"
cn.blogjava.youxia.firstmenu
"
);
28
????????menuBar.add(newMenu);
29
????????newMenu.add(action1);
30
????}
31
???
32
}
可以看出,我們通過創建cn.blogjava.youxia.actions.Action1類的實例來創建一個菜單項,然后把它加入到菜單newMenu中,然后再把newMenu加入menuBar中,整個過程很容易理解。那么register(action1)是做什么的呢?這是為了把我們的Action的實例注冊到工作臺中,這樣當我們的工作臺銷毀的時候,我們的Action也可以被銷毀。
下面請看Action1類的源代碼:
?1
package
?cn.blogjava.youxia.actions;
?2
?3
import
?org.eclipse.jface.action.Action;
?4
import
?org.eclipse.ui.IWorkbenchWindow;
?5
import
?org.eclipse.ui.actions.ActionFactory.IWorkbenchAction;
?6
import
?cn.blogjava.youxia.rcp_start.FirstDialog;
?7
?8
?9
public
?
class
?Action1?
extends
?Action?
implements
?IWorkbenchAction?
{
10
????
11
????
private
?IWorkbenchWindow?workbenchWindow;
12
13
????
public
?Action1(IWorkbenchWindow?window)?
{
14
????????
if
?(window?
==
?
null
)?
{
15
????????????
throw
?
new
?IllegalArgumentException();
16
????????}
17
18
????????
this
.workbenchWindow?
=
?window;
19
????}
20
????
21
????
public
?
void
?run()?
{
22
????????
//
?make?sure?action?is?not?disposed
23
????????
if
?(workbenchWindow?
!=
?
null
)?
{
24
????????????
//
在這里添加功能
25
????????????FirstDialog?dg?
=
?
new
?FirstDialog(workbenchWindow.getShell());
26
????????????dg.open();
27
????????????
28
????????}
29
????}
30
31
????
public
?
void
?dispose()?
{
32
????????workbenchWindow?
=
?
null
;
33
34
????}
35
36
}
在構造函數中保存我們工作臺窗口的引用,在run方法中執行功能,是不是很簡單?在這里,我們用到了一個對話框類cn.blogjava.youxia.rcp_start.FirstDialog,這個類從org.eclipse.swt.widgets.Dialog類繼承,熟悉swt的朋友一定不會陌生。我建議大家可以使用Designer插件,這個插件對swt/jface提供非常好的可視化支持,在這個對話框中,我們只簡單的添加了兩個按鈕。
FirstDialog.java源文件如下:
?1
package
?cn.blogjava.youxia.rcp_start;
?2
?3
import
?org.eclipse.swt.SWT;
?4
import
?org.eclipse.swt.events.SelectionAdapter;
?5
import
?org.eclipse.swt.events.SelectionEvent;
?6
import
?org.eclipse.swt.widgets.Button;
?7
import
?org.eclipse.swt.widgets.Dialog;
?8
import
?org.eclipse.swt.widgets.Display;
?9
import
?org.eclipse.swt.widgets.Shell;
10
11
12
public
?
class
?FirstDialog?
extends
?Dialog?
{
13
14
????
protected
?Shell?shell;
15
????
16
????
private
?
int
?result;
17
18
????
public
?FirstDialog(Shell?parent,?
int
?style)?
{
19
????????
super
(parent,?style);
20
????}
21
22
????
public
?FirstDialog(Shell?parent)?
{
23
????????
this
(parent,?SWT.NONE);
24
????}
25
26
????
public
?
int
?open()?
{
27
????????createContents();
28
????????shell.open();
29
????????shell.layout();
30
????????Display?display?
=
?getParent().getDisplay();
31
????????
while
?(
!
shell.isDisposed())?
{
32
????????????
if
?(
!
display.readAndDispatch())
33
????????????????display.sleep();
34
????????}
35
????????
return
?result;
36
????}
37
38
????
protected
?
void
?createContents()?
{
39
????????shell?
=
?
new
?Shell(getParent(),?SWT.DIALOG_TRIM?
|
?SWT.APPLICATION_MODAL);
40
????????shell.setSize(
150
,?
70
);
41
????????shell.setText(
"
第一個對話框
"
);
42
43
????????
final
?Button?okButton?
=
?
new
?Button(shell,?SWT.NONE);
44
????????okButton.addSelectionListener(
new
?SelectionAdapter()?
{
45
????????????
public
?
void
?widgetSelected(SelectionEvent?e)?
{
46
????????????????result?
=
?
1
;
47
????????????????shell.dispose();
48
????????????}
49
????????}
);
50
????????okButton.setText(
"
OK
"
);
51
????????okButton.setBounds(
10
,?
10
,?
48
,?
22
);
52
53
????????
final
?Button?cancelButton?
=
?
new
?Button(shell,?SWT.NONE);
54
????????cancelButton.addSelectionListener(
new
?SelectionAdapter()?
{
55
????????????
public
?
void
?widgetSelected(SelectionEvent?e)?
{
56
????????????????result?
=
?
2
;
57
????????????????shell.dispose();
58
????????????}
59
????????}
);
60
????????cancelButton.setText(
"
Cancel
"
);
61
????????cancelButton.setBounds(
89
,?
10
,?
48
,?
22
);
62
????}
63
64
}
65
上面所講的,只是添加菜單和工具欄的第一種方法,這種方法把構建菜單的工作以靜態代碼的方式加入到了ApplicationActionBarAdvisor類中,如果需要修改用戶界面,則需要修改代碼并重新編譯。
添加菜單項的第二種方法就要簡單得多,而且修改起來也方便,還可以對菜單項實現更加靈活的控制,但是,需要對Eclipse的插件基礎有比較好的了解。那這第二種方法就是通過擴展actionSets擴展點來添加菜單。
對擴展點的擴展,可以通過編輯plugin.xml文件了實現,比如我們添加的第二個菜單項,其配置文件如下:
?1
<
extension
?2
?????????
id
="cn.blogjava.youxia.actionset"
?3
?????????name
="我的菜單擴展"
?4
?????????point
="org.eclipse.ui.actionSets"
>
?5
??????
<
actionSet
?6
????????????
description
="第一個擴展"
?7
????????????id
="RCP_Start.actionSet1"
?8
????????????label
="RCP_Start.actionSet1"
?9
????????????visible
="true"
>
10
?????????
<
action
11
???????????????
class
="cn.blogjava.youxia.actions.Action2"
12
???????????????icon
="icons/alt_window_16.gif"
13
???????????????id
="RCP_Start.action2"
14
???????????????label
="第二個菜單項"
15
???????????????menubarPath
="cn.blogjava.youxia.firstmenu/additions"
16
???????????????style
="push"
17
???????????????toolbarPath
="additions"
18
???????????????tooltip
="第二個菜單項的按鈕"
/>
19
??????
</
actionSet
>
20
???
</
extension
>
其實Eclipse為我們提供了很好的可視化plugin.xml的編輯器,如下圖,我們可以對菜單的外觀進行和行為進行靈活的控制:
從配置文件中我們可以看到,我們為這第二個菜單項指定的Action是cn.blogjava.youxia.actions.Action2類,這個類我們必須實現org.eclipse.ui.IWorkbenchWindowActionDelegate接口,這個接口中比org.eclipse.jface.actions.Action中多定義了一個方法public void selectionChanged(IAction action, ISelection selection),這個方法是必須的,以便工作臺窗口在用戶選定哪一項資源的時候通知我們的Action類的實例。其代碼如下:
?1
package
?cn.blogjava.youxia.actions;
?2
?3
import
?org.eclipse.jface.action.IAction;
?4
import
?org.eclipse.jface.viewers.ISelection;
?5
import
?org.eclipse.ui.IWorkbenchWindow;
?6
import
?org.eclipse.ui.IWorkbenchWindowActionDelegate;
?7
import
?cn.blogjava.youxia.rcp_start.FirstDialog;
?8
?9
public
?
class
?Action2?
implements
?IWorkbenchWindowActionDelegate?
{
10
????
11
????
private
?IWorkbenchWindow?window;
12
13
????
public
?
void
?dispose()?
{
14
????????
//
?TODO?
15
16
????}
17
18
????
public
?
void
?init(IWorkbenchWindow?window)?
{
19
????????
//
?TODO?
20
????????
this
.window?
=
?window;
21
22
????}
23
24
????
public
?
void
?run(IAction?action)?
{
25
????????
//
?TODO?
26
????????FirstDialog?dg?
=
?
new
?FirstDialog(window.getShell());
27
????????dg.open();
28
29
????}
30
31
????
public
?
void
?selectionChanged(IAction?action,?ISelection?selection)?
{
32
????????
//
?TODO?
33
34
????}
35
36
}
總結:通過向工作臺中添加菜單和工具欄,并使用對話框作為與用戶交互的基礎,我們已經基本上可以構建功能比較復雜的程序了。但這僅僅只是RCP編程的開端。下一節,我們將一起探索Eclipse的透視圖和視圖。