明輝手游網(wǎng)中心:是一個(gè)免費(fèi)提供流行視頻軟件教程、在線學(xué)習(xí)分享的學(xué)習(xí)平臺(tái)!

Eclipse基礎(chǔ)-- Eclipse的使用簡(jiǎn)介及插件開發(fā)(二)

[摘要]二.開發(fā)Eclipse插件(Plug-ins)Eclipse最有魅力的地方就是它的插件體系結(jié)構(gòu)。在這個(gè)體系中重要的概念是擴(kuò)展點(diǎn)(extension points),也就是為插件提供的接口。每一個(gè)插件都是在現(xiàn)有的擴(kuò)展點(diǎn)上開發(fā),并可能還留有自己的擴(kuò)展點(diǎn),以便在這個(gè)插件上繼續(xù)開發(fā)。由于有了插件,Ecli...
二.開發(fā)Eclipse插件(Plug-ins)

Eclipse最有魅力的地方就是它的插件體系結(jié)構(gòu)。在這個(gè)體系中重要的概念是擴(kuò)展點(diǎn)(extension points),也就是為插件提供的接口。每一個(gè)插件都是在現(xiàn)有的擴(kuò)展點(diǎn)上開發(fā),并可能還留有自己的擴(kuò)展點(diǎn),以便在這個(gè)插件上繼續(xù)開發(fā)。

由于有了插件,Eclipse系統(tǒng)的核心部分在啟動(dòng)的時(shí)候要完成的工作十分簡(jiǎn)單:?jiǎn)?dòng)平臺(tái)的基礎(chǔ)部分和查找系統(tǒng)的插件。在Eclipse中實(shí)現(xiàn)的絕大部分功能是由相應(yīng)的插件完成的,比如WrokBench UI插件完成界面的外觀顯示,Resource Management插件完成維護(hù)或生成項(xiàng)目或文件等資源管理工作(在下面的第二個(gè)例子就會(huì)用到這個(gè)插件),而Version and Configuration Management (VCM)插件則負(fù)責(zé)完成版本控制功能,等等。雖然以上提到的每一個(gè)功能都是絕大多數(shù)IDE環(huán)境所必備的功能,Eclipse卻也把它們都做成了插件模式,甚至用來開發(fā)Java程序的開發(fā)環(huán)境(Java development tooling,JDT)也只不過是Eclipse系統(tǒng)中的一個(gè)普通插件而已。整個(gè)Eclipse體系結(jié)構(gòu)就象一個(gè)大拼圖,可以不斷的向上加插件,同時(shí),現(xiàn)有插件上還可以再加插件。下面的插件開發(fā)示例就是在WorkBench UI插件中的觀察窗口擴(kuò)展點(diǎn)上開發(fā)的。

本文第一部分介紹過Eclipse的開發(fā)界面其中之一就是觀察窗口,它通常配合編輯窗口顯示一些有用的信息,在這里我們只簡(jiǎn)單生成一個(gè)顯示歡迎信息的觀察窗口,假設(shè)新插件的名子叫Welcome。

第一步,先用向?qū)陆ㄒ粋(gè)Java項(xiàng)目。我們可以在菜單欄選擇FileàNew,或用工具欄的向?qū)О存I,或是在資源窗口用鼠標(biāo)右鍵菜單中的New,打開向?qū)?duì)話框,然后用缺省方式創(chuàng)建項(xiàng)目。并在項(xiàng)目中建立一個(gè)Welcome.java文件,代碼如下:


package com.nidapeng.eclipse.plugin;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.SWT;
import org.eclipse.ui.part.ViewPart;
public class Welcome extends ViewPart {
Label label;
public Welcome() {
}
public void createPartControl(Composite parent) {
label = new Label(parent, SWT.WRAP);
label.setText("Welcome to Eclipse");
}
public void setFocus() {
}
}




為使這個(gè)程序能正常編譯,要配置它的編譯環(huán)境,即指定所需的CLASSPATH。在Eclipse中可以用幾種方法,常用的是兩種:第一是在資源窗口或Java包窗口選中該項(xiàng)目,點(diǎn)擊鼠標(biāo)右鍵,在打開的菜單中選擇屬性(Properties),之后在屬性對(duì)話框中選擇Java Build PathàLibraries,用Add External JARs功能添加三個(gè)包,它們都是Eclipse的現(xiàn)有插件的類包,可以在"你的Eclipse安裝路徑\plugins"下面的相應(yīng)路徑中找到。分別是org.eclipse.core.runtime插件中的runtime.jar,org.eclipse.swt中的swt.jar和org.eclipse.ui中的workbench.jar。第二種指定CLASSPATH的方法是先將以上提到的三個(gè)包直接導(dǎo)入到Eclipse中的某下一個(gè)項(xiàng)目中。如果導(dǎo)入到和Welcome.java相同的項(xiàng)目中,則無需進(jìn)一步指定CLASSPATH,否則需要在項(xiàng)目的屬性菜單中選擇Java Build PathàProjects,然后選中這三個(gè)包所在的項(xiàng)目。

在我們的項(xiàng)目中還要生成一個(gè)XML文件,它的名字必須plugin.xml。代碼如下:


<?xml version="1.0" encoding="UTF-8"?>
<plugin
 id="com.nidapeng.eclipse.plugin"
 name="Welcome to Eclipse"
 version="1.0"
 provider-name="Ni Dapeng">
<requires>
 <import plugin="org.eclipse.ui"/>
</requires>
<runtime>
 <library name="welcome.jar"/>
</runtime>
<extension
point="org.eclipse.ui.views">
 <category
 name="Welcome"
 id="com.nidapeng.eclipse.plugin.category1">
</category>
 <view
 name="Welcome to Eclipse"
 category="com.nidapeng.eclipse.plugin.category1"
 class="com.nidapeng.eclipse.plugin.Welcome"
 id="com.nidapeng.eclipse.plugin.view1">
</view>
</extension>
</plugin>




在plugin.xml中一共有四個(gè)主要的標(biāo)簽:plugin,requires,runtime,extension。其中plugin標(biāo)簽的屬性提供的是我們要開發(fā)的Welcome插件的基本信息,除了name,version,provider-name等,最重要的是id,它要求不能和現(xiàn)有的Eclipse插件id有沖突,因此我們用包名作為插件的id。requires標(biāo)簽中所列出的是需要的插件,這里我們要用到Eclipse Workbench和SWT API,因此導(dǎo)入了org.eclipse.ui插件。runtime標(biāo)簽指明的是我們開發(fā)的插件所在JAR包的文件名。extension標(biāo)簽是插件擴(kuò)展點(diǎn)的信息。org.eclipse.ui.views是Eclipse系統(tǒng)提供的觀察窗口擴(kuò)展點(diǎn),我們的例子是一個(gè)觀察窗口(View),這表明我們是要在 org.eclipse.ui.views擴(kuò)展點(diǎn)上進(jìn)一步開發(fā)。extension中還包括category和view兩個(gè)標(biāo)簽,在后續(xù)的啟動(dòng)Welcome插件步驟中,我們就會(huì)知道這兩個(gè)標(biāo)簽的含義。要注意的是category和view標(biāo)簽的id的唯一性,并且在view的屬性中聲明了Welcome插件的類名。

在Eclipse中為plugin.xml提供了缺省可視化的編輯器,在編寫plugin.xml過程中可以借助這個(gè)編輯器完成一些工作。如果你直接錄入了plugin.xml文件源代碼,還可以用這個(gè)編輯器校驗(yàn)?zāi)愕拇a:如果編輯器不能正確讀入,就表明你的plugin.xml有一些問題。

在確認(rèn)Weclome.java和plugin.xml都正確無誤之后,可以用Eclipse菜單欄中的Export命令將Weclome.java導(dǎo)出為JAR文件,它的名子應(yīng)該和plugin.xml中runtime聲明的JAR相一致。同時(shí)導(dǎo)出plugin.xml。安裝Welcome插件的方法和本文第一部分介紹的安裝Tomcat插件方法是一樣的:首先在"Eclipse的安裝路徑\plugins"路徑下面建立一個(gè)com.nidapeng.eclipse.plugin路徑,然后將Weclome.jar和plugin.xml拷到這個(gè)路徑下。之后必需重新啟動(dòng)Eclipse,在Eclipse啟動(dòng)的時(shí)候,它會(huì)搜索所有在插件路徑下的插件并注冊(cè)它們(僅僅是注冊(cè),只有在需要某個(gè)插件的時(shí)候,Eclipse才會(huì)啟動(dòng)它)。在重新啟動(dòng)的Eclipse的菜單欄中選擇PerspectiveàShow ViewàOthers,在打開的對(duì)話框中我們會(huì)找到在plugin.xml中extension的category標(biāo)簽中聲明的name屬性:Welcome。在Welcome的支結(jié)點(diǎn)中包含了view標(biāo)簽name屬性:Welcome to Eclipse。選中它并確認(rèn),Welcome窗口就會(huì)顯示在Eclipse Workbench上的某個(gè)位置 。如果在執(zhí)行了以上操作,但沒有顯示新窗口,可以再次打開Show View菜單,此時(shí)在菜單中應(yīng)該有新一頂選擇:Welcome to Eclipse,然后選中它。

上面我們完成了一個(gè)觀察窗口的插件,但這個(gè)操作過程對(duì)開發(fā)稍微復(fù)雜一些的插件就顯得不太方便了:每次測(cè)試都要將代碼打包,發(fā)布,再重新啟動(dòng)Eclipse系統(tǒng)!為此Eclipse提供了一個(gè)專門為開發(fā)插件而做插件(有點(diǎn)繞嘴):Plug-in Development Environment(PDE)。本文前面曾提到,目前Eclipse的Release或Stable版本缺省提供了這個(gè)插件,因此如果安裝的Eclipse是這兩個(gè)版本中的一個(gè)就可以直接進(jìn)行下面的步驟。下面我們?cè)儆肞DE環(huán)境開發(fā)一個(gè)稍微復(fù)雜一些的插件。

第一步仍然要新建一個(gè)項(xiàng)目,只是在向?qū)е胁皇怯肑ava項(xiàng)目,而是Plug-in Development中的Plug-in Project。在應(yīng)用向?qū)尚马?xiàng)目的時(shí)候,要注意兩點(diǎn):第一是PDE的項(xiàng)目名稱就是plugin的id,因此要保證它的唯一性,這里我們的項(xiàng)目名是com.nidapeng.eclipse.plugin.pde。其次為了進(jìn)一步說明Eclipse插件的結(jié)構(gòu),在Plug-in Code Generators中,選擇用向?qū)0迳梢粋(gè)缺省的插件,如圖六:



圖六

這個(gè)用缺省方式生成的插件類對(duì)于我們將要的代碼并不是必需的,也可以用生成空插件的方式建立我們的項(xiàng)目,這樣做只是為進(jìn)一步說明Eclipse的插件結(jié)構(gòu)。

項(xiàng)目生成之后,在我們的項(xiàng)目中會(huì)包含一個(gè)PdePlugin.java文件,它就是以缺省方式生成的插件類。注意到它繼承了AbstractUIPlugin類,而AbstractUIPlugin類實(shí)現(xiàn)了org.eclipse.ui.plugin接口。事實(shí)上,所有的Eclipse插件都會(huì)有一個(gè)相應(yīng)的實(shí)現(xiàn)plugin接口的類,這個(gè)類將是新插件的主類(類似于有main()函數(shù)的Java類),它負(fù)責(zé)管理插件的生存期。在我們的AbstractUIPlugin繼承子類中,可以用singleton模式來保存在Eclipse中的生成的該插件的第一個(gè)也是唯一實(shí)例,一般來說,在該繼承子類中也要實(shí)現(xiàn)一個(gè)getDefault()方法以返回當(dāng)前插件的實(shí)例。而且,當(dāng)Eclipse首次使用該插件的時(shí)候,這個(gè)主類將是第一個(gè)被調(diào)用的類,因此我們也可以在它的代碼中執(zhí)行一些初始化的工作。而且如果插件需要使用Preferences,Dialogs或Images資源,也可以通過這個(gè)類中的相應(yīng)方法來得到它們的實(shí)例,如用其中的getDialogSettings(),getPreferenceStore(),getImageRegistry()方法。

但是象前面提到的,PdePlugin.java對(duì)下面的例子并不是必需的,我們不用對(duì)它進(jìn)行任何修改。在我們第一個(gè)例子中的Weclome插件,根本就沒有生成AbstractUIPlugin的繼承子類,此時(shí)系統(tǒng)會(huì)自動(dòng)為Weclome插件生成一個(gè)缺省的主類(類似于Java類構(gòu)造函數(shù),如果沒有聲明,系統(tǒng)會(huì)指定一個(gè)默認(rèn)的構(gòu)造函數(shù))。

下面的代碼是才真正實(shí)現(xiàn)了我們新插件的功能,假設(shè)這個(gè)插件名子是NoticeView:


package com.nidapeng.eclipse.plugin.pde;
import org.eclipse.core.resources.*;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.runtime.CoreException;
import java.util.ResourceBundle;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
public class NoticeView extends ViewPart implements 
Runnable,IResourceChangeListener ,IResourceDeltaVisitor{
private ResourceBundle resourceBundle;
private Label label;
private Display disp;
private String dispTxt;
public NoticeView() {
ResourcesPlugin.getWorkspace().addResourceChangeListener(this,
IResourceChangeEvent.PRE_CLOSE
IResourceChangeEvent.PRE_DELETE
IResourceChangeEvent.PRE_AUTO_BUILD
IResourceChangeEvent.POST_AUTO_BUILD
IResourceChangeEvent.POST_CHANGE);
}
public static IWorkspace getWorkspace() {
//ResourcesPlugin插件的主類!
 return ResourcesPlugin.getWorkspace();
 }
public void createPartControl(Composite parent) {
 label = new Label(parent, SWT.WRAP);
label.setText("change your project status...");
 disp = Display.getDefault();
 }
public void setFocus() {
 }
// 實(shí)現(xiàn)IResourceChangeListener接口中的resourceChanged方法
public void resourceChanged(IResourceChangeEvent event) {
IResource res = event.getResource();
switch (event.getType()) {
 case IResourceChangeEvent.PRE_CLOSE :
dispTxt = res.getFullPath() + " is about to closed!";
break;
 case IResourceChangeEvent.PRE_DELETE :
dispTxt = res.getFullPath() + " is about to be deleted!";
 break;
 case IResourceChangeEvent.POST_CHANGE :
try {
 event.getDelta().accept(this);
} catch (CoreException e) {
 e.printStackTrace();
}
break;
 case IResourceChangeEvent.PRE_AUTO_BUILD :
try {
 event.getDelta().accept(this);
} catch (CoreException e) {
 e.printStackTrace();
}
break;
 case IResourceChangeEvent.POST_AUTO_BUILD :
try {
 event.getDelta().accept(this);
} catch (CoreException e) {
 e.printStackTrace();
}
break;
}
disp.syncExec(this);
 }
 // 實(shí)現(xiàn)IResourceDeltaVisitor接口中的visit方法
 public boolean visit(IResourceDelta delta) {
IResource res = delta.getResource();
switch (delta.getKind()) {
 case IResourceDelta.ADDED :
dispTxt = "Resource "+res.getFullPath()+" was added.";
break;
 case IResourceDelta.REMOVED:
dispTxt = "Resource "+res.getFullPath()+" was removed.";
 break;
 case IResourceDelta.CHANGED :
dispTxt = "Resource "+res.getFullPath()+" has changed.";
 break;
}
return true; // visit the children
 }
// 實(shí)現(xiàn)Runnable接口中的run方法
 public void run() {
try {
 label.setText(dispTxt);
} catch (Exception e) {
 e.printStackTrace();
}
}
}




象上面的第一個(gè)Welcome插件,這個(gè)新插件同樣繼承了ViewPart,不同的是實(shí)現(xiàn)了三個(gè)接口:Runnable,IResourceChangeListener ,IResourceDeltaVisitor。其中的Runnable大家應(yīng)該很熟悉:多線程的接口。而IResourceChangeListener和IResourceDeltaVisitor是Eclipse系統(tǒng)中的資源接口,這里的資源是指Eclipse中的項(xiàng)目或文件等。在下面運(yùn)行NoticeView插件的過程中你可以通過添加、打開、刪除項(xiàng)目或文件來觸發(fā)這兩個(gè)接口中的事件,并在我們的觀察窗口中顯示相關(guān)信息。

在程序中比較奇怪部分的是在resourceChanged()函數(shù)里面,并沒有象大家想象的那樣直接調(diào)用label.setText()方法來顯示信息,而是調(diào)用了disp.syncExec(this),其中的disp是Display類型的對(duì)象。這是因?yàn)閞esourceChanged()方法運(yùn)行的線程和lable所在插件運(yùn)行的Eclipse主線程并不是同一個(gè)線程,如果直接調(diào)用label.setText()方法,會(huì)拋出一個(gè)異常。

下面還需要對(duì)項(xiàng)目中的plugin.xml進(jìn)行一些改動(dòng),主要就是加上擴(kuò)展點(diǎn)聲明:


<?xml version="1.0" encoding="UTF-8"?>
<plugin
 id="com.nidapeng.eclipse.plugin.pde"
 name="Pde Plugin"
 version="1.0.0"
 provider-name="NIDAPENG"
 class="com.nidapeng.eclipse.plugin.pde.PdePlugin">
<requires>
 <import plugin="org.eclipse.core.runtime"/>
 <import plugin="org.eclipse.core.resources"/>
 <import plugin="org.eclipse.ui"/>
</requires>
<runtime>
 <library name="pde.jar"/>
</runtime>
<extension
id="NoticeView"
name="Notice View"
point="org.eclipse.ui.views">
 <category
 name="Notice"
 id="com.nidapeng.eclipse.plugin.pde.category1">
 </category>
 <view
 name="Notice Resource View"
 category="com.nidapeng.eclipse.plugin.pde.category1"
 class="com.nidapeng.eclipse.plugin.pde.NoticeView"
 id="com.nidapeng.eclipse.plugin.pde.view1">
</view>
</extension>
</plugin>




這個(gè)xml文件和Welcome插件的plugin.xml非常接近,這里就不做過多的說明了。

要運(yùn)行這個(gè)插件,可以直接用Eclipse中的運(yùn)行按鈕,因?yàn)檫@個(gè)項(xiàng)目是一個(gè)Plug-in Project,此時(shí)項(xiàng)目會(huì)自動(dòng)以Run-time Workbench方式運(yùn)行。運(yùn)行后,會(huì)生成一個(gè)和當(dāng)前Eclipse完全一致的平臺(tái),在這個(gè)平臺(tái)上可以直接運(yùn)行NoticeView插件,查看這個(gè)插件到底會(huì)執(zhí)行什么功能,也可以用直接Run-time Workbench方式調(diào)試插件。這里省去了安裝插件,重啟動(dòng)Eclipse等過程,可以看到用PDE開發(fā)插件的過程比直接用Java開發(fā)環(huán)境簡(jiǎn)潔了很多!

Eclipse的開發(fā)不僅僅限于插件的開發(fā),它還可以取代Java中的標(biāo)準(zhǔn)Swing,進(jìn)行基于Java的獨(dú)立應(yīng)用程序GUI開發(fā)。它帶來的好處是顯而易見的:高速,資源占用低,跨平臺(tái),代碼開放,有大公司的支持等等。

由于Eclipse目前還在開發(fā)階段,筆者在用它調(diào)試程序時(shí)發(fā)現(xiàn)有些性能還不是十分的穩(wěn)定,一些地方會(huì)遇到奇怪的問題,要求使用者能想一些辦法解決。不過,以現(xiàn)在Eclipse的開發(fā)速度,相信過不了多久,它的各種功能會(huì)逐步完善。目前Eclipse雖然有種種不足,但瑕不掩玉,筆者對(duì)Eclipse的總體印象還是非常不錯(cuò)的,運(yùn)行速度,資源占用都要好于IVJ,操作起來也大多順手,而且即使在現(xiàn)階段也很少有意外退出等重大的Bug發(fā)生,希望未來的Eclipse能真正達(dá)到IVJ的功能,VisualCafe的速度,成為廣大程序員開發(fā)軟件的一大利器!

參考資源:

www.eclipse.org是Eclipse的資源總站。

關(guān)于作者
倪大鵬,有五年的軟件開發(fā)經(jīng)驗(yàn),其中的近四年時(shí)間里是在從事與Java相關(guān)技術(shù)的應(yīng)用與開發(fā)。你可以通過e-mail: ndp@21cn.com與他聯(lián)系。