一、Eclipse簡介
Eclipse最初是由IBM捐獻給開源社區(qū)的,目前已經發(fā)展成為人氣最旺的Java IDE。Eclipse插件化的功能模塊吸引了無數(shù)開發(fā)者開發(fā)基于Eclipse的功能插件。事實上,Eclipse已經超越了一般Java IDE的概念。Eclipse是一個平臺,一個開放的平臺,你可以為Eclipse添加任何你想要的功能,比如播放音樂,觀看電影,聊天……這些不是天方夜譚,而是已經實現(xiàn)的事實。雖然Eclipse可以添加很多附加功能,可以編輯C/C++,可以編輯Word文件,可以開發(fā)UML等等,但是Eclipse最基本,也是最強大的功能還是Java IDE。
二、RCP簡介
RCP的全稱是Rich Client Platform,可以把它看成是Eclipse的骨架,其他的插件是器官與血肉。我們可以把這個骨架拿過來填入自己的器官和血肉,這樣就創(chuàng)造了我們自己的“Eclipse”!
使用RCP來開發(fā)Java桌面應用可以把開發(fā)的焦點轉移到系統(tǒng)的邏輯功能上,而不是界面上。我們自己的程序可以繼承Eclipse的風格與功能,而不用自己去編寫諸如菜單,工具條,子窗口等等的界面元素。甚至我們可以把Eclipse本身的功能插件,比如Console拿來放在自己的程序里,這樣就避免了很多重復開發(fā)。
三、知識準備
我寫這篇文章并不是面向Java的初學者,而是面向有一定Eclipse使用基礎的開發(fā)者。所以我假設你已經具備一下基本知識:
1、 Java基礎
2、 用過Eclipse進行開發(fā)
3、 SWT/JFace開發(fā)基礎(可選)
如果你還不具備上述條件,那么看我的文章你會看的很郁悶,建議你先去學習這些基本知識。
四、Eclipse組件
在開發(fā)Eclipse插件(RCP可以看成是Eclipse的插件,只不過是脫離Eclipse運行的)之前,得先對Eclipse的結構有個了解。這里我簡單介紹一下Eclipse的基本組件,這些名詞可能比較陌生,但這都是開發(fā)Eclipse插件必須了解的。
如上圖所示,我逐一介紹一個各個組件:
1、 Menu bar:這個東西你一定不陌生,每個軟件都有的。不過Eclipse的菜單欄是動態(tài)的,也就是說,根據(jù)所編輯的內容不同,顯示的菜單也可以不一樣。
2、 Tool bar:這個東西也是每個軟件都有的,和菜單欄一樣,工具欄也是可以根據(jù)所編輯的內容不同而不同。
3、 Editor:編輯器,Eclipse的主要編輯工作是在Editor里面完成的。
4、 View:視圖,視圖是為了方便用戶編輯提供一些輔助功能或編輯一些屬性。比如最常見的Outline視圖往往用來提供當前編輯的文檔的結構。
5、 Page:頁,一個頁表示了當前用戶的工作狀態(tài),包括View和Editor。
6、 Workbench Window:涵蓋所有上述組件的組件叫做工作臺窗口(這個名詞的翻譯我沒見到過,我這里純粹是直譯,感覺有些詞不達意)。Eclipse是允許創(chuàng)建多個工作臺的。通過Window->New window菜單可以創(chuàng)建當前工作臺的副本。
除了這些組件以外我還要介紹另外兩個概念,一個是“Work Space”,在Eclipse啟動的時候都要求指定一個Work Space,而且Work Space是不能被共用的。也就是說在同一時間,同一個Work Space只可以被一個Eclipse使用。但是一個Work Space是可以被多個Workbench Window共享的。很容易聯(lián)想到,Workbench Window上面還有一層Workbench。事實上Workbench才是Eclipse的UI的最高管理者。另外一個概念是“Perspective”,中文翻譯是“透視圖(或者觀察點)”。所謂Perspective是指當前Page的布局。最常見的是Java透視圖和Debug透視圖,可以看到這兩個透視圖的Page排布完全不一樣。通過切換透視圖可以很方便的切換開發(fā)環(huán)境以完成不同功能的開發(fā)。這里可以看出View和Editor的區(qū)別,Editor是在不同的透視圖中共享的,而View不是。
五、開發(fā)前的準備
Eclipse是自帶插件開發(fā)環(huán)境PDE(Plug-in Develop Environment)的,所以要開發(fā)Eclipse插件只需要下載一個標準的Eclipse即可。我現(xiàn)在用的Eclipse版本是3.3.0,是最新的穩(wěn)定版,建議下載這個版本進行開發(fā)(我用的是英文版,所以下文提到的Eclipse相關的選項都是英文描述)。
雖然Eclipse生來就是開放的插件平臺,但是Eclipse插件,特別是RCP是從3.0開始才走紅的。Eclipse 3.0是一個具有里程碑意義的版本,它對Eclipse以前的結構做了一定的改進,并且升級了PDE,極大的簡化了插件開發(fā)的配置,基本上實現(xiàn)了插件開發(fā)全圖形的化操作,使得插件開發(fā)人員可以專注于插件功能的開發(fā),而不用去管瑣碎的配置文件。
六、第一個RCP程序
Eclipse提供了一些RCP程序的模板,通過PDE的插件創(chuàng)建向導能直接生成一個可用的RCP程序。
首先要新建一個Plug-in Project
然后輸入Project名字,其他都用默認選項就行,點擊“next”
在Rich Client Application部分選擇“Yes”,點擊“Next”
模板選擇Hello RCP,點擊“Next”
點擊“Finish”將提示轉換到Plug-in development perspective,選擇“Yes”。
我們先看一下剛才新建的RCP的運行結果,右鍵點擊“Demo”project,選擇Run As,選擇Eclipse Application,就可以看到一個最簡單的RCP程序窗口。
接下來我先分析一下這個應用程序的結構。在Demo包下面有六個類和三個配置文件,下面我解釋一下這些元素:
六個類
三個配置文件
1、 Application:這個類是程序的入口,雖然沒有Main函數(shù),但是這個類實現(xiàn)了IPlatformRunnable接口,當JVM完畢,初始化RCP框架以后會調用這個類的run函數(shù)來完成UI設置和開始執(zhí)行我們指定的程序功能。在絕大多數(shù)RCP程序中,這個類不用更改。
2、 ApplicationActionBarAdvisor:簡單的說這個類是用來配置程序的菜單欄和工具欄的,具體的應用在后面會講到。
3、 ApplicationWorkbenchAdvisor:這個類是RCP程序的Workbench,RCP是Eclipse的簡化,但是所有的組件都是和Eclipse一樣的。一個RCP程序也只能有一個Workbench。
4、 ApplicationWorkbenchWindowAdvisor:這個類是RCP的WorkbenchWindow,隸屬于當前的Workbench。可以有多個WorkbenchWindow。
5、 DemoPlugin:這個類代表了我們的插件,因為RCP程序也是一個插件,Eclipse中所有的插件都必須繼承AbstractUIPlugin。這個類為我們提供了很多和插件相關的信息,比如插件的資源,配置等等。
6、 Perspective:是我們新建的RCP的默認透視圖。可以在這個類中指定View和Editor的排布。
7、 plugin.xml:這個文件是我們插件的配置文件,包括我們的插件用了哪些其他的插件,具體是怎么配置這些插件的等等。
8、 build.properties:這個文件是用來配置我們插件的編譯信息的,用來指定如何編譯我們的插件。
9、 MANIFEST.MF:這個文件用來指定我們插件的元數(shù)據(jù),比如插件的版本信息。一般來說,這個文件不用手動的去更改。
七、添加菜單和工具欄
這一節(jié)我演示以下如何為程序創(chuàng)建菜單和工具欄。在創(chuàng)建菜單和工具欄之前我想先介紹一個概念“Action”。開發(fā)Eclipse插件會經常看到這個東西,它和事件處理有點相似,如果你了解JFace的話,這里的Action你應該很熟悉,兩者是一樣的,我們自己定義的Action必須繼承org.eclipse.jface.action.Action。程序可以定義當用戶執(zhí)行某項操作時觸發(fā)某個Action。比如用戶點擊工具欄的一個按鈕,或者選中了某個菜單項。
下面我們創(chuàng)建一個類HelloAction
package firstrcp;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
import org.eclipse.ui.internal.WorkbenchImages;
public class HelloAction extends Action {
private IWorkbenchWindow window;
public HelloAction(IWorkbenchWindow window) {
this.window = window;
this.setText("Hello");
ImageDescriptor imgDes = WorkbenchImages.getImageDescriptor(IWorkbenchGraphicConstants.IMG_ETOOL_HOME_NAV);
this.setImageDescriptor(imgDes);
}
}
由于Action是一個UI元素,所以往往創(chuàng)建一個帶IWorkbenchWindow參數(shù)的構造函數(shù),以便在Action內部調用。setText()是設置Action對外顯示的名字。setImageDescriptor()是設置Action的圖標,這里我為了簡化,用的是Eclipse Workbench自帶的圖標。
下面增加一個run方法,功能是彈出一個對話框顯示“Hello World!”
public void run() {
MessageBox mb = new MessageBox(window.getShell(), SWT.OK);
mb.setMessage("Hello world!");
mb.setText("Demo");
mb.open();
}
這里你可以看到構造函數(shù)傳入window的好處了吧。
上述代碼都很簡單,我不多解釋,接下來我們把創(chuàng)建的Action關聯(lián)到菜單欄和工具欄上。我們可以把同一個Action同時關聯(lián)到多個菜單項和工具欄按鈕,這和事件處理中的事件處理函數(shù)可以被多個事件共享一樣。
上文我已經提到過,ApplicationActionBarAdvisor是用來配置工具欄和菜單欄的,那么我們現(xiàn)在來看以下具體如何操作。修改ApplicationActionBarAdvisor如下:
package firstrcp;
import org.eclipse.jface.action.ICoolBarManager;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.ToolBarContributionItem;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.swt.SWT;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.application.ActionBarAdvisor;
import org.eclipse.ui.application.IActionBarConfigurer;
public class ApplicationActionBarAdvisor extends ActionBarAdvisor {
private HelloAction helloAction;
public ApplicationActionBarAdvisor(IActionBarConfigurer configurer) {
super(configurer);
}
//用來初始化action
protected void makeActions(IWorkbenchWindow window) {
super.makeActions(window);
helloAction = new HelloAction(window);
}
/* 用來設置菜單欄.創(chuàng)建一個MenuManager,然后把helloAction加入到這個菜單下面,
* 如果有多個action的話,可以加入同一個MenuManager,
* 這樣demoMenu相當于一個下拉菜單,
* 而加入的action就是菜單項。最后把demoMenu加入到菜單欄。
*/
protected void fillMenuBar(IMenuManager menuBar) {
super.fillMenuBar(menuBar);
MenuManager demoMenu = new MenuManager("&Demo", "");
demoMenu.add(helloAction);
menuBar.add(demoMenu);
}
/*
* 用來設置工具欄的,原理和菜單欄是一樣的,coolBar也有分組的,
* 每個toolbar就是一組。這里的toolbar相當于demoMenu。
*/
protected void fillCoolBar(ICoolBarManager coolBar) {
IToolBarManager toolbar = new ToolBarManager(SWT.FLAT | SWT.RIGHT);
coolBar.add(new ToolBarContributionItem(toolbar, "main"));
toolbar.add(helloAction);
}
}
代碼看起來有點暈,我來一一解釋。首先是makeActions()方法,這個方法是用來初始化action的,所有要用到的action可以都在這里初始化,但是這一步與界面無關。fillMenuBar()是用來設置菜單欄的。先創(chuàng)建一個MenuManager,然后把helloAction加入到這個菜單下面,如果有多個action的話,可以加入同一個MenuManager,這樣demoMenu相當于一個下拉菜單,而加入的action就是菜單項。最后把demoMenu加入到菜單欄。當然,一個菜單欄可以加入多個下拉菜單。多級菜單也是可以做的,有興趣的可以自行研究。fillCoolBar()是用來設置工具欄的,原理和菜單欄是一樣的,coolBar也有分組的,每個toolbar就是一組。這里的toolbar相當于demoMenu。
運行一下程序你會發(fā)現(xiàn)菜單欄出來了,但是工具欄沒有出現(xiàn)。原因是Hello RCP默認是不顯示工具欄的,我們得改一下設置。打開ApplicationWorkbenchWindowAdvisor類,更改preWindowOpen方法:
public void preWindowOpen() {
IWorkbenchWindowConfigurer configurer = getWindowConfigurer();
configurer.setInitialSize(new Point(400, 300));
//configurer.setShowCoolBar(false);
configurer.setShowStatusLine(false);
configurer.setTitle("Hello RCP");
}
以上代碼也很簡單,從字面就能看出什么意思,我也不多解釋,注意看注釋掉的那行。preWindowOpen()這個函數(shù)在程序的窗口打開之前被調用,可以在這個函數(shù)里設置一些初始化的內容。類似的還有postWindowClose()等等,你可以查閱API來了解這些函數(shù)的用途。
現(xiàn)在我們的程序可以正確的運行了,看一下運行結果:
八、創(chuàng)建View和Editor
我用Designer來編輯View和Editor。我用的版本是WindowBuilder Pro 4.1.0,建議你也去下載一個,因為這個插件能夠支持SWT,JFace,RCP,Swing的可視化編輯,極大的縮短了界面開發(fā)的時間。不過這個是商業(yè)軟件,要破解了才能用,網上有很多破解的方法,google一下就行了。
下面開始創(chuàng)建第一個View。
右鍵點擊demo包,選擇“New”,“Other” 然后選擇Designer->RCP->ViewPart,點擊“Next”
輸入“HelloView”,點擊“Finish”
你可以在Source和Design之間切換。View相當于一個窗口,在View的界面上可以放任何組件。我拖了一個button上去,名字就叫button。HelloView類中要添加一個屬性ID,我稍后解釋這個屬性。
你可以用同樣的方法創(chuàng)建一個EditorPart,名字就叫HelloEditor。在editor上面放一個text組件吧,這樣看起來像個editor,然后把HelloEditor的layout改成FillLayout。當然也要為HelloEditor添加一個ID屬性。這里需要改一下Editor的init方法,否則editor無法正常運行。
setSite是讓editor能夠使用workbench所提供的一些功能,EditorSite可以看成是一個代理,EditorPart通過EditorSite來訪問workbench。EditorSite是editor part和workbench之間的一層接口,詳細情況你可以去google一下或者參考API。setInput的意思就很明了,就是讓editor知道顯示什么東西。這樣我們就創(chuàng)建好了基本的View和Editor,下面來看怎么把它們加到我們的程序中去。
打開plugin.xml,選擇Extensions標簽頁,在All Extensions部分點擊“Add”按鈕,選擇org.eclipse.ui.views, org.eclipse.ui.editors, 兩個extension,結果如下:
右鍵org.eclipse.ui.view,選擇New->view
在Extension Element Details部分設置View的屬性。ID可以隨意設置,但是不能重復,我這里設置為Demo.helloView(雖說是隨意設置,但是程序是通過這個ID來獲得View的,所以最好與HelloView中的ID屬性一致,我在HelloView中加入這個ID屬性也是為了方便程序獲得HelloView),Name也可以隨意設置,我這里設置為Hello View,這個屬性會顯示在View的頂端,就像Outline View頂部顯示的名稱是“Outline”。class選擇剛才創(chuàng)建的demo.HelloView。icon是顯示在View頂部的圖標,沒有可以不設置。
類似的創(chuàng)建Hello Editor,設置Hello Editor的詳細屬性,設置id, name, class三個屬性以外,還要設置icon屬性(Editor的Icon屬性是必須的!),隨便給個圖片文件就行,其他的屬性可以不填。這里屬性比較多,有興趣可以去看Eclipse的插件開發(fā)幫助,里面對每個屬性都有解釋。
到目前為止,我們的配置工作已經完成,但是要讓我們的程序正確的顯示View和Editor,我們還要更改默認的Perspective。打開Perspective.java,修改createInitialLayout()方法(默認這個方法是空的)
public
這個方法實際上就是修改layout,在這個方法中安排每個view的位置和大小。addStandaloneView()是為當前的Perspective添加一個獨立的View,所謂獨立的View就是View所占的位置不能和其他View共享,你在Eclipse里應該看到過幾個View疊在一起的情況。接下來一行設置是去除了關閉View的功能,就是這個View的頂部沒有關閉按鈕。我們來看一下運行結果
void createInitialLayout(IPageLayout layout)
{
layout.addStandaloneView(HelloView.ID, true,
IPageLayout.LEFT, .50f, layout.getEditorArea());
layout.getViewLayout(HelloView.ID).setCloseable(false);
}
也許你正在想怎么打開Editor,IPageLayout并不能直接把一個Editor加入顯示,但是它會預留一塊空間給Editor。如果你仔細觀察上面那段代碼,你會發(fā)現(xiàn),事實上整個空間都是Editor的,View是在瓜分Editor的空間。接下來我將介紹如何打開Editor。
九、設置并打開Editor
相對View來說,Editor有點麻煩。因為要打開Editor的話必須給Editor內容,因為Editor是個編輯器,你得讓它知道要編輯什么東西它才能打開。這里的內容就是Eclipse里面的EditorInput。沒有現(xiàn)成合適的EditorInput用(一般情況下可以用FileEditorInput,把某個文件作為Input讓Editor打開,在Eclipse里面雙擊打開某個文件就是這個過程),我這里創(chuàng)建一個HelloEditorInput繼承IEditorInput接口。用Eclipse向導創(chuàng)建類的時候,先選擇Interface,然后記得選中“Inherited abstract methods”,這樣會自動繼承所有abstract的方法,不用再去手工創(chuàng)建了。
HelloEditorInput的代碼比較長,我不全部貼出來了,我貼一部分。我貼的兩個方法是必須要修改的,這個類的其他代碼用Eclipse自動生成的就好(做實際開發(fā)的時候肯定是要改的,我這里只是演示一個過程,所以盡量簡化了)。
public
這里的getName是返回當前input的名字,比如文件名,getToolTipText是返回當前input的提示,當鼠標移動到editor的頂部標簽上時就會顯示。這兩個方法都不能返回null。
好了現(xiàn)在一切準備工作已經就緒,就等打開Editor了。我們通過HelloView上面的那個按鈕來打開HelloEditor,每按一次按鈕打開一個Editor。首先更改按鈕的Text屬性為“Open Editor”,然后為按鈕添加事件,事件代碼如下:
關鍵代碼就一行,就是那個openEditor方法,這個函數(shù)的兩個參數(shù),前面的代表資源,后面的代表工具,就是用后面的Editor去打開前面的內容。提醒一下,這里的Editor ID必須和plugin.xml文件里面的一樣,否則會找不到合適的Editor。可以看到openEditor是Page的方法,這也和我前面介紹的Eclipse的組件結構一致,View和Editor是屬于某個page的。其實在配置Perspective的時候也能看出這個問題,我們都是用IPageLayout
String getName()
{
return "Hello";
}
public String getToolTipText()
{
return "Demo";
}
openEditorButton.addSelectionListener(new SelectionAdapter()
{
public void widgetSelected(SelectionEvent e)
{
try
{
getViewSite().getWorkbenchWindow().getActivePage()
.openEditor(new HelloEditorInput(), HelloEditor.ID);
}
catch (Exception ex)
{
System.out.println(ex);
}
}
});
來布置界面。下面運行一下程序,看一下運行結果。
可能你會感覺不太協(xié)調,那么我們把窗口默認最大化(似乎能好看點),這就需要修改ApplicationWorkbenchWindowAdvisor類中的postWindowOpen函數(shù):
如果你以前接觸過SWT/JFace的話這段代碼應該很熟悉吧,就算沒接觸過,也應該能大概明白什么意思,所以我不解釋了。這句話一定要放在postWindowOpen里面,因為在preWindowOpen的時候還沒有Window存在,所以沒法設置。我們來看一下最終的運行結果:
下面我介紹一下如何導出/發(fā)布RCP程序,使程序能夠獨立運行。
public void postWindowOpen()
{
this.getWindowConfigurer().getWindow().getShell().setMaximized(true);
}
十、導出RCP程序
從Eclipse 3.0開始,RCP程序的配置和導出就變得相當方便。RCP程序又稱為Eclipse Product,我們先為Demo Project新建一個Product配置文件。右鍵Demo Project,選擇New->Other->Product Configuration,然后選擇Demo文件夾,File name輸入demo.product,點擊Finish
接下來我們要新建一個Product Id,點擊New
然后點擊Browse選擇Demo,并輸入Product ID為hello,點擊Finish
Overview標簽頁的Product Definition部分,輸入Product Name為Hello Demo。在Testing部分點擊一下“Synchronize”(最好點一下,有時候不點也沒問題),這是為了讓我們的Product配置和插件的配置保持一致。然后切換到Configuration標簽頁,點擊Add,輸入Demo,點擊OK
然后點擊“Add Required Plug-ins”,這一步是添加我們的Product所用到的其他插件,這樣才可以脫離Eclipse運行。
然后進入Branding標簽頁,這一頁是設置Product的圖標,程序名字等等,可以不設置,系統(tǒng)會自動使用默認值,我這里輸入一個Launcher Name為HelloDemo。
現(xiàn)在我們已經完成了導出的配置工作,現(xiàn)在來導出我們的RCP程序。進入Demo.product的Overview標簽頁,在右下角Exporting部分點擊“Eclipse Product export wizard”,輸入Root Directory和Export Destination,點擊Finish。