在使用Eclipse RCP進(jìn)行桌面程序開(kāi)發(fā)(一):快速起步中,我們通過(guò)Eclipse的插件開(kāi)發(fā)向?qū)В鸩浇⒘艘粋€(gè)RCP應(yīng)用程序,但是,這個(gè)程序沒(méi)有任何功能,難以激起我們學(xué)習(xí)的興趣。在這一節(jié),我們將一起探索怎樣在程序中添加菜單和工具條。先看一下成果:
圖一、圖二:帶有菜單和工具條的RCP程序


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

圖四:點(diǎn)擊菜單項(xiàng)或者工具欄按鈕后,彈出一個(gè)簡(jiǎn)單的對(duì)話框。

這里需要說(shuō)明一點(diǎn),為什么要在講菜單和工具欄的時(shí)候一起講對(duì)話框,這是因?yàn)閷?duì)話框是我們所能想到的最簡(jiǎn)單最直接的用戶交互方式,在對(duì)話框上可以添加各種各樣的控件來(lái)實(shí)現(xiàn)復(fù)雜的功能,為了讓我們點(diǎn)擊菜單項(xiàng)的時(shí)候能夠看到效果,這里就用了一個(gè)簡(jiǎn)單的對(duì)話框。當(dāng)然,當(dāng)我們以后接觸到視圖、編輯器和透視圖這樣的概念之后,我們能使用的用戶交互方式就不僅僅只是對(duì)話框了。
打開(kāi)我們上一節(jié)使用向?qū)Ы⒌墓こ蹋梢园l(fā)現(xiàn)工程下面自動(dòng)生成了如下文件:
Application.java
ApplicationWorkbenchAdvisor.java
ApplicationWorkbenchWindowAdvisor.java
ApplicationActionBarAdvisor.java
Perspective.java
plugin.xml
這里的Application.java是我們整個(gè)程序的入口點(diǎn),我們的程序運(yùn)行的時(shí)候,會(huì)先執(zhí)行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行我們可以看出,該入口函數(shù)將創(chuàng)建用戶界面的工作交給了ApplicationWorkbenchAdvisor類。接著,我們打開(kāi)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
}
可以看出,這個(gè)類的工作就是為我們的程序指定默認(rèn)的透視圖,然后把創(chuàng)建窗口的工作交給了ApplicationWorkbenchWindowAdvisor類。接著,我們打開(kāi)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(
"
第一個(gè)RCP程序
"
);
17
????????
18
????}
19
???????
20
}
這個(gè)類的功能很強(qiáng)大,我們可以重載它的preWindowCreate、postWindowCreate、preWindowOpen、postWindowOpen等方法,以便修改我們窗口的外觀。在這里可以看出,我們重載了preWindowOpen方法來(lái)設(shè)置窗口的大小和讓工具欄可見(jiàn)。很顯然,這個(gè)類的另外一個(gè)功能,就是把創(chuàng)建菜單和工具欄的任務(wù)交給了ApplicationActionBarAdvisor類。
到這里,謎底已經(jīng)揭曉,要?jiǎng)?chuàng)建我們自己的菜單和工具條,就一定是在ApplicationActionBarAdvisor.java中做文章了。不錯(cuò),打開(kāi)這個(gè)文件,我們可以看到這個(gè)類有兩個(gè)重要的方法:
protected void makeActions(IWorkbenchWindow window);
protected void fillMenuBar(IMenuManager menuBar);
我們可以在makeActions方法中創(chuàng)建我們的Action,什么是Action呢?Action是jface中的一個(gè)概念,在jface中通過(guò)org.eclipse.jface.action中的Action和ActionContributionItem類實(shí)現(xiàn)了視圖和處理代碼的分離,這樣無(wú)論何時(shí)用戶觸發(fā)了一個(gè)控件的事件,都會(huì)激活一個(gè)相應(yīng)的Action類實(shí)例來(lái)進(jìn)行時(shí)間處理。毫無(wú)疑問(wèn),我們的菜單項(xiàng)是一個(gè)Action類的子類了。
下面請(qǐng)看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(
"
第一個(gè)菜單項(xiàng)
"
);
22
????????action1.setId(
"
cn.blogjava.youxia.actions.action1
"
);
23
????????register(action1);
24
????}
25
26
????
protected
?
void
?fillMenuBar(IMenuManager?menuBar)?
{
27
????????MenuManager?newMenu?
=
?
new
?MenuManager(
"
第一個(gè)菜單
"
,
"
cn.blogjava.youxia.firstmenu
"
);
28
????????menuBar.add(newMenu);
29
????????newMenu.add(action1);
30
????}
31
???
32
}
可以看出,我們通過(guò)創(chuàng)建cn.blogjava.youxia.actions.Action1類的實(shí)例來(lái)創(chuàng)建一個(gè)菜單項(xiàng),然后把它加入到菜單newMenu中,然后再把newMenu加入menuBar中,整個(gè)過(guò)程很容易理解。那么register(action1)是做什么的呢?這是為了把我們的Action的實(shí)例注冊(cè)到工作臺(tái)中,這樣當(dāng)我們的工作臺(tái)銷毀的時(shí)候,我們的Action也可以被銷毀。
下面請(qǐng)看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
}
在構(gòu)造函數(shù)中保存我們工作臺(tái)窗口的引用,在run方法中執(zhí)行功能,是不是很簡(jiǎn)單?在這里,我們用到了一個(gè)對(duì)話框類cn.blogjava.youxia.rcp_start.FirstDialog,這個(gè)類從org.eclipse.swt.widgets.Dialog類繼承,熟悉swt的朋友一定不會(huì)陌生。我建議大家可以使用Designer插件,這個(gè)插件對(duì)swt/jface提供非常好的可視化支持,在這個(gè)對(duì)話框中,我們只簡(jiǎn)單的添加了兩個(gè)按鈕。
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(
"
第一個(gè)對(duì)話框
"
);
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
上面所講的,只是添加菜單和工具欄的第一種方法,這種方法把構(gòu)建菜單的工作以靜態(tài)代碼的方式加入到了ApplicationActionBarAdvisor類中,如果需要修改用戶界面,則需要修改代碼并重新編譯。
添加菜單項(xiàng)的第二種方法就要簡(jiǎn)單得多,而且修改起來(lái)也方便,還可以對(duì)菜單項(xiàng)實(shí)現(xiàn)更加靈活的控制,但是,需要對(duì)Eclipse的插件基礎(chǔ)有比較好的了解。那這第二種方法就是通過(guò)擴(kuò)展actionSets擴(kuò)展點(diǎn)來(lái)添加菜單。
對(duì)擴(kuò)展點(diǎn)的擴(kuò)展,可以通過(guò)編輯plugin.xml文件了實(shí)現(xiàn),比如我們添加的第二個(gè)菜單項(xiàng),其配置文件如下:
?1
<
extension
?2
?????????
id
="cn.blogjava.youxia.actionset"
?3
?????????name
="我的菜單擴(kuò)展"
?4
?????????point
="org.eclipse.ui.actionSets"
>
?5
??????
<
actionSet
?6
????????????
description
="第一個(gè)擴(kuò)展"
?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
="第二個(gè)菜單項(xiàng)"
15
???????????????menubarPath
="cn.blogjava.youxia.firstmenu/additions"
16
???????????????style
="push"
17
???????????????toolbarPath
="additions"
18
???????????????tooltip
="第二個(gè)菜單項(xiàng)的按鈕"
/>
19
??????
</
actionSet
>
20
???
</
extension
>
其實(shí)Eclipse為我們提供了很好的可視化plugin.xml的編輯器,如下圖,我們可以對(duì)菜單的外觀進(jìn)行和行為進(jìn)行靈活的控制:
從配置文件中我們可以看到,我們?yōu)檫@第二個(gè)菜單項(xiàng)指定的Action是cn.blogjava.youxia.actions.Action2類,這個(gè)類我們必須實(shí)現(xiàn)org.eclipse.ui.IWorkbenchWindowActionDelegate接口,這個(gè)接口中比org.eclipse.jface.actions.Action中多定義了一個(gè)方法public void selectionChanged(IAction action, ISelection selection),這個(gè)方法是必須的,以便工作臺(tái)窗口在用戶選定哪一項(xiàng)資源的時(shí)候通知我們的Action類的實(shí)例。其代碼如下:
?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
}
總結(jié):通過(guò)向工作臺(tái)中添加菜單和工具欄,并使用對(duì)話框作為與用戶交互的基礎(chǔ),我們已經(jīng)基本上可以構(gòu)建功能比較復(fù)雜的程序了。但這僅僅只是RCP編程的開(kāi)端。下一節(jié),我們將一起探索Eclipse的透視圖和視圖。