在這個文章系列中,第一部分向讀者介紹了Eclipse的插件開發(fā)環(huán)境,并開發(fā)了一個簡單的插件;第二部分添加了工具欄按鈕、一個菜單項和對話框。一個小發(fā)明并不能為我們做什么事情,它僅僅將樣本信息按照某個字體格式顯示給我們,那么我們要做的是教會它去處理實際的數(shù)據(jù)。我們要通知那些插件,讓它們按照我們的需要來工作。本文討論了如何來定制一個編輯文件的向?qū)А?BR>
一 Invokatron的故事
首先,我們來了解一下Invokatron,在前面的文章中,我們也提到了Invokatron是一個產(chǎn)生Java代碼的圖形化工具,用這個工具,你可以方便的采用拖放方式來創(chuàng)建一個Java Class。這個“dragged-in”方法被編輯好的方法調(diào)用(invoked),這就是它名字的由來。我們將采用數(shù)據(jù)驅(qū)動的方式來設(shè)計我們的系統(tǒng)。
在下面的章節(jié)中,我們將開發(fā)這個圖形應(yīng)用接口程序。從現(xiàn)在開始我們需要列出插件輸入和存儲的重要數(shù)據(jù)。這就是我們常說的應(yīng)用程序的模型。在接下來的文章中,我們將制作這個圖形化界面。目前我們需要考慮的僅僅是提取出哪些信息是我們的插件需要存放的重要數(shù)據(jù)。這部分通常被稱作是應(yīng)用的模型
(Model)部分。以下是設(shè)計系統(tǒng)時需要考慮的東西:
●????????哪部分?jǐn)?shù)據(jù)是需要保存的?
●????????這些數(shù)據(jù)用什么樣的存儲結(jié)構(gòu)來表示他們?POJO,JavaBean,還是EJB?
●????????這些數(shù)據(jù)如何進行持久化?用數(shù)據(jù)庫中的表,XML文件,屬性文件還是一個序列化的二進制流文件?
●????????數(shù)據(jù)的讀取采用哪些途徑?使用新建文件向?qū)В渌愋偷南驅(qū)В粋€彈出式的對話框,一個圖形化的編輯器,文本編輯器還是使用文件屬性頁?
在我們繼續(xù)前行之前,這些問題必須解決。沒有一種答案是適用于所有項目的,這些答案是基于項目需求。我為我們的項目做了以下的定義:
●????????一個Java類包含類名,一個包,一個父類,并實現(xiàn)某些接口。我們先定義這些,在后面的文章中將添加一些其他的數(shù)據(jù)信息。
●????????這些數(shù)據(jù)將由一個繼承自Properties類的子類來表示。這些構(gòu)成了編輯器的“文檔類”。
●????????我們將采用一類屬性文件來實現(xiàn)轉(zhuǎn)換。利用Properties類,這樣的操作很容易實現(xiàn)。
●????????采用一個新建文件向?qū)沓跏蓟瘮?shù)據(jù),接著,我們讓用戶在屬性窗口或者文本編輯器中修改數(shù)據(jù)。這步操作將在下面的文檔中進行說明。
二 文檔類
接下來要做的是寫文檔類。創(chuàng)建一個名為invokatron.model的包,然后創(chuàng)建一個名為InvokatronDocument的類。這是我們最初的文檔類:
public class InvokatronDocument
????????extends Properties
{
????public static final String PACKAGE = "package";
????public static final String SUPERCLASS = "superclass";
????public static final String INTERFACES = "interfaces";
}
使用Properties類可以簡單的實現(xiàn)數(shù)據(jù)的轉(zhuǎn)換和保存操作。其中,getter和setter方法并不是必須的,如果你想添加這些方法的話,你可以添加它們。這個類并沒有寫完,在后面,我們將給它加上Eclipse需要使用的接口。對這個類而言,要取得一個屬性,只需要這樣的操作:
String package =
????document.getProperty(InvokatronDocument.PACKAGE);
三 定制一個向?qū)?/SPAN>
看一下我們在之前的文章中使用到的向?qū)Вㄈ绻悻F(xiàn)在還沒有源代碼,請在這里下載)。記住,你可以通過我們添加的工具欄按鈕或者菜單項來打開這個向?qū)АU埧磮D1:

圖1 以前的向?qū)?BR>
這個向?qū)е挥幸豁摚谟疑辖且矝]有圖片。我們想添加更多的信息并且有個漂亮的圖片。換句話說,我們想定制這個向?qū)А?BR>
首先讓我們來剖析一下向?qū)А4蜷_InvokatronWizard.java文件,注意這個類繼承了Wizard并且實現(xiàn)了InewWizard接口。這里有很多你必須知道的方法。定制我們的向?qū)В恍枰唵蔚恼{(diào)用或者重寫這些方法。這里有一些重要介紹:
3.1 關(guān)于生命期的方法
我們需要重寫這些方法來加入關(guān)于那些初始化和銷毀定制的向?qū)Тa。
●????????構(gòu)造器。這個方法將在向?qū)нM行實例化的時候、并且Eclispe向它傳送信息之前調(diào)用。是向?qū)У某R?guī)信息初始化的實現(xiàn)。通常情況下你會調(diào)用“美化方法”(見下面)來給對話框做默認(rèn)設(shè)置。
●????????init(IWorkbench workbench, IStructuredSelection editorSelection):這個方法由Eclipse調(diào)用,它給向?qū)峁┮恍┕ぷ魅⌒畔ⅰV貙戇@個方法來處理Iworkbench和之后將使用的對象。如果這是個編輯向?qū)Ф皇切陆ㄏ驅(qū)В覀冃枰獙?dāng)前編輯器的選擇項也作為一個參數(shù)。
●????????dispose():由Eclipse調(diào)用來處理回收。重寫這個方法來回收向?qū)加玫馁Y源。
●????????finalize():對于回收處理,建議采用dispose()方法調(diào)用。
3.2 美化方法
以下的方法將裝飾這個向?qū)Т翱冢?BR>●????????setWindowTitle(String title):調(diào)用這個方法來取得標(biāo)題欄字符。
●????????setDefaultPageImageDescriptor(ImageDescriptor image):調(diào)用這個方法來取得顯示在所有向?qū)ы撚疑辖堑膱D片。
●????????setTitleBarColor(RGB color):調(diào)用這個方法來來定義標(biāo)題欄的顏色。
3.3 按鈕的常用方法
下面的方法控制向?qū)е械陌粹o的可用性和它的操作。
●????????boolean canFinish():重寫這個方法,根據(jù)向?qū)У臓顟B(tài)來指明Finish按鈕是否可用。
●????????boolean performFinish():重寫這個方法,實現(xiàn)這個向?qū)ё罡镜臉I(yè)務(wù)邏輯。如果向?qū)Р荒芡瓿桑óa(chǎn)生錯誤)則返回false。
●????????boolean performCancel():重寫這個方法,當(dāng)用戶單擊Cancel按鈕的時候做清除操作。如果這個向?qū)Р荒苋∠祷豧alse。
●????????boolean isHelpAvailable():重寫這個方法,定義Help按鈕是否可見。
●????????boolean needsPreviousAndNextButtons():重寫這個方法,定義Previous和Next按鈕是否可見。
●????????boolean needsProgressMonitor():重寫這個方法,指明過程監(jiān)聽器控件是否可見。它將在單擊“Finish”按鈕后調(diào)用performFinish()方法的時候出現(xiàn)。
3.4 頁面的常用方法
下面的方法將控制頁面的出現(xiàn):
●????????addPages():當(dāng)向?qū)Э虺霈F(xiàn)的時候調(diào)用。重寫這個方法給向?qū)砑有马撁妗?BR>●????????createPageControls(Composite pageContainer):Eclipse調(diào)用這個方法將向?qū)е械乃许撁妫ㄓ缮厦娴腶ddPages()方法添加的)實例化。重寫這個方法,添加向?qū)е幸恢笨梢姷目丶ú粌H僅是頁面)。
●????????IWizardPage getStartingPage():重寫這個方法來定義向?qū)У牡谝粋€頁面。
●????????IWizardPage getNextPage(IWizardPage nextPage):在默認(rèn)情況下,單擊Next按鈕將得到addPages()方法提供的頁面數(shù)組中的下一頁。你可能需要根據(jù)用戶的選擇而轉(zhuǎn)向不同的頁面。重寫這個方法來得到下個頁面。
●????????IWizardPage getPreviousPage(IWizardPage previousPage):與getNextPage()方法類似,用來計算得到前一個頁面。
●????????int getPageCount():返回使用addPages()方法添加的頁面?zhèn)€數(shù)。你不需要重寫這個方法,除非你想顯示和頁面實際數(shù)量不一致的數(shù)量。
3.5 其他有用的方法
這里有很多有用的輔助性方法:
●????????setDialogSettings(IDialogSettings settings):你可以加載對話框的設(shè)置并調(diào)用init()方法來發(fā)布其中的數(shù)據(jù)。典型的,向?qū)е械膯栴}設(shè)置是默認(rèn)的,在這里(DialogSettings)察看更多的信息。
●????????IDialogSettings getDialogSettings():使用這個方法可以找回需要的數(shù)據(jù)。在performFinish()方法的最后,你可以將數(shù)據(jù)再次存入文件。
●????????IWizardContainer getContainer():可以得到Shell對象,運行后臺線程,刷新窗口,等等。
3.6 向?qū)ы摲椒?/SPAN>
我們已經(jīng)看到,一個向?qū)且粋€或者多個頁面的組合。這些頁面擴展了WizardPage類并實現(xiàn)了IwizardPage接口。為了定制一個個性化的向?qū)В€有很多方法是必須掌握的。這里介紹一些比較重要的方法:
●????????構(gòu)造器:初始化頁面
●????????dispose():重寫這個方法,實現(xiàn)清除代碼。
●????????createControl(Composite parent):重寫這個方法,為這個頁面添加控制器。
●????????IWizard getWizard():用來得到向?qū)ο蟆T谡{(diào)用getDialogSettings()方法的時候有用。
●????????setTitle(String title):為向?qū)У臉?biāo)題區(qū)提供顯示的文字。
●????????setDescription(String description):提供顯在在標(biāo)題文字下的信息。
●????????setImageDescriptor(ImageDescriptor image):得到一個圖片,用來取代西安在在向?qū)в疑辖堑哪J(rèn)圖片。
●????????setMessage(String message):在描述信息的下方顯示的文本信息,一般用來提示或者警告用戶。
●????????setErrorMessage(String error):在描述信息的下面高亮度顯示一個字符串。它表示向?qū)г谔幚硗赍e誤信息之前不能做下一步的操作。
●????????setPageComplete(boolean complete):如果輸入?yún)?shù)是true,那么Next按鈕可以使用。
●????????performHelp():重寫這個方法,提供內(nèi)容敏感的幫助。這個將在Help按鈕被按下的時候被向?qū)д{(diào)用。
四 為向?qū)Ь幋a
這些方法使得我們開發(fā)一個可擴展的向?qū)С蔀榭赡堋N覀儸F(xiàn)在來修改這個在前面文章中創(chuàng)建的Invokatron向?qū)Вo他添加一個頁面來請求原始的文檔數(shù)據(jù),并添加一個圖片。下面的代碼中粗體部分是新增加的:
public class InvokatronWizard extends Wizard
????????implements INewWizard {
????private InvokatronWizardPage page;
????private InvokatronWizardPage2 page2;
????private ISelection selection;
????public InvokatronWizard() {
????????super();
????????setNeedsProgressMonitor(true);
????????ImageDescriptor image =
????????????AbstractUIPlugin.
????????????????imageDescriptorFromPlugin("Invokatron",
?????????????????? "icons/InvokatronIcon32.GIF");
????????setDefaultPageImageDescriptor(image);
????}
????public void init(IWorkbench workbench,
????????????IStructuredSelection selection) {
????????this.selection = selection;
????}
在構(gòu)造函數(shù)中,我們打開了過程監(jiān)聽器并為向?qū)гO(shè)置了圖片。你可以通過右鍵下載這個新圖標(biāo):

將這個圖標(biāo)保存在Invokatron/icons文件夾下。為了促進圖片的加載,我們使用了AbstractUIPlugin.imageDescriptorFromPlugin()方法。
注意:你必須知道,盡管這個向?qū)荌newWizard類型的向?qū)В⒉皇撬械南驅(qū)怯脕懋a(chǎn)生新文檔的。要想知道怎么去顯示一個“獨立”的向?qū)В垍⒖次恼伦詈蟮馁Y源部分。
接下來是addPages()方法:
????public void addPages() {
????????page=new InvokatronWizardPage(selection);
????????addPage(page);
????????page2 = new InvokatronWizardPage2(
????????????selection);
????????addPage(page2);
????}
在這個方法中,我們添加了一個名為InvokatronWizardPage2的新頁面,我們待會就會寫這個頁面。接下來是用戶按下向?qū)е械腇inish按鈕后會調(diào)用的方法:
????
public boolean performFinish() {
????????//First save all the page data as variables.
????????final String containerName =
????????????page.getContainerName();
????????final String fileName =
????????????page.getFileName();
????????final InvokatronDocument properties =
????????????new InvokatronDocument();
????????properties.setProperty(
????????????InvokatronDocument.PACKAGE,
????????????page2.getPackage());
????????properties.setProperty(
????????????InvokatronDocument.SUPERCLASS,
????????????page2.getSuperclass());
????????properties.setProperty(
????????????InvokatronDocument.INTERFACES,
????????????page2.getInterfaces());
????????//Now invoke the finish method.
????????IRunnableWithProgress op =
????????????new IRunnableWithProgress() {
????????????public void run(
????????????????????IProgressMonitor monitor)
????????????????????throws InvocationTargetException {
????????????????try {
????????????????????doFinish(
????????????????????????containerName,
????????????????????????fileName,
????????????????????????properties,
????????????????????????monitor);
????????????????} catch (CoreException e) {
????????????????????throw new InvocationTargetException(e);
????????????????} finally {
????????????????????monitor.done();
????????????????}
????????????}
????????};
????????try {
????????????getContainer().run(true, false, op);
????????} catch (InterruptedException e) {
????????????return false;
????????} catch (InvocationTargetException e) {
????????????Throwable realException =
????????????????e.getTargetException();
????????????MessageDialog.openError(
????????????????getShell(),
????????????????"Error",
????????????????realException.getMessage());
????????????return false;
????????}
????????return true;
????}
現(xiàn)在我們需要作一些數(shù)據(jù)保存的工作。這個工作將被向?qū)У娜萜鳎‥clipse工作區(qū))執(zhí)行,所以必須實現(xiàn)IrunnableWithProgress接口,這個接口只包含一個run()方法。IprogressMonitor允許輸出任務(wù)的過程信息。這是我們接下來將會看到的。真正的數(shù)據(jù)保存操作在輔助性方法中,doFinish():
????
private void doFinish(
????????String containerName,
????????String fileName,
????????Properties properties,
????????IProgressMonitor monitor)
????????throws CoreException {
????????// create a sample file
????????monitor.beginTask("Creating " + fileName, 2);
????????IWorkspaceRoot root = ResourcesPlugin.
????????????getWorkspace().getRoot();
????????IResource resource = root.findMember(
????????????new Path(containerName));
????????if (!resource.exists() ||
????????????!(resource instanceof IContainer)) {
????????????throwCoreException("Container \"" +
????????????????containerName +
????????????????"\" does not exist.");
????????}
????????IContainer container =
????????????(IContainer)resource;
????????final IFile iFile = container.getFile(
????????????new Path(fileName));
????????final File file =
????????????iFile.getLocation().toFile();
????????try {
????????????OutputStream os =
????????????????new FileOutputStream(file, false);
????????????properties.store(os, null);
????????????os.close();
????????} catch (IOException e) {
????????????e.printStackTrace();
????????????throwCoreException(
????????????????"Error writing to file " +
????????????????file.toString());
????????}
????????//Make sure the project is refreshed
????????//as the file was created outside the
????????//Eclipse API.
????????container.refreshLocal(
????????????IResource.DEPTH_INFINITE, monitor);
????????monitor.worked(1);
????????monitor.setTaskName(
????????????"Opening file for editing...");
????????getShell().getDisplay().asyncExec(
????????????new Runnable() {
????????????public void run() {
????????????????IWorkbenchPage page =
????????????????????PlatformUI.getWorkbench().
????????????????????????getActiveWorkbenchWindow().
????????????????????????getActivePage();
????????????????try {
????????????????????IDE.openEditor(
????????????????????????page,
????????????????????????iFile,
????????????????????????true);
????????????????} catch (PartInitException e) {
????????????????}
????????????}
????????});
????????monitor.worked(1);
????}
這里,我們做了很多工作:
●????????我們得到了想保存的這個文件的路徑(作為Eclipse的IFile類)
●????????我們也得到了與之等價的File
●????????我們將屬性保存到了相應(yīng)的路徑下
●????????接著,我們請求Eclipse工作臺刷新項目,這樣,這個新的文件就顯示出來了。
●????????最后,我們制定為將來制定了一個工作計劃。這些工作包括在編輯器中打開一個新的文件。
●????????我們傳遞一個參數(shù),調(diào)用IprogressMonitor對象的方法,使用戶能接收到整個工作過程的信息。
最后一個方法是當(dāng)保存文件失敗的情況下,在向?qū)е酗@示錯誤信息的輔助性方法:
????
private void throwCoreException(
????????????String message) throws CoreException {
????????IStatus status =
????????????new Status(
????????????????IStatus.ERROR,
????????????????"Invokatron",
????????????????IStatus.OK,
????????????????message,
????????????????null);
????????throw new CoreException(status);
????}
}
一個CoreException被向?qū)Р东@,接著,它所包含的Status對象將信息呈現(xiàn)給用戶。這時,向?qū)Р]有關(guān)閉。
五 為新建向?qū)ы摼幊?/SPAN>
接著,我們來寫InvokatronWizardPage2。這個類是一個新添加的文件:
public class InvokatronWizardPage2 extends WizardPage {
????private Text packageText;
????private Text superclassText;
????private Text interfacesText;
????private ISelection selection;
????public InvokatronWizardPage2(ISelection selection) {
????????super("wizardPage2");
????????setTitle("Invokatron Wizard");
????????setDescription("This wizard creates a new"+
????????????" file with *.invokatron extension.");
????????this.selection = selection;
????}
????private void updateStatus(String message) {
????????setErrorMessage(message);
????????setPageComplete(message == null);
????}
????public String getPackage() {
????????return packageText.getText();
????}
????public String getSuperclass() {
????????return superclassText.getText();
????}
????public String getInterfaces() {
????????return interfacesText.getText();
????}
上面的構(gòu)造函數(shù)設(shè)置了頁面的標(biāo)題(它將高亮顯示在標(biāo)題欄下)。我們也有一些輔助性方法。updateStatus將管理顯示出的這個特定頁面的錯誤信息。如果沒有錯誤信息,,那就說明頁面完成了;這時,Next按鈕將變成可用的狀態(tài)。這里對數(shù)據(jù)屬性內(nèi)容設(shè)置了getter方法。接下來是createControl()方法,它將創(chuàng)建頁面上所有可見的組建。
????
public void createControl(Composite parent) {
????????Composite controls =
????????????new Composite(parent, SWT.NULL);
????????GridLayout layout = new GridLayout();
????????controls.setLayout(layout);
????????layout.numColumns = 3;
????????layout.verticalSpacing = 9;
????????Label label =
????????????new Label(controls, SWT.NULL);
????????label.setText("&Package:");
????????packageText = new Text(
????????????controls,
????????????SWT.BORDER | SWT.SINGLE);
????????GridData gd = new GridData(
????????????GridData.FILL_HORIZONTAL);
????????packageText.setLayoutData(gd);
????????packageText.addModifyListener(
????????????new ModifyListener() {
????????????????public void modifyText(
????????????????????????ModifyEvent e) {
????????????????????dialogChanged();
????????????????}
????????});
????????label = new Label(controls, SWT.NULL);
????????label.setText("Blank = default package");
????????label = new Label(controls, SWT.NULL);
????????label.setText("&Superclass:");
????????superclassText = new Text(
????????????controls,
????????????SWT.BORDER | SWT.SINGLE);
????????gd = new GridData(
????????????GridData.FILL_HORIZONTAL);
????????superclassText.setLayoutData(gd);
????????superclassText.addModifyListener(
????????????new ModifyListener() {
????????????????public void modifyText(
????????????????????????ModifyEvent e) {
????????????????????dialogChanged();
????????????}
????????});
????????label = new Label(controls, SWT.NULL);
????????label.setText("Blank = Object");
????????label = new Label(controls, SWT.NULL);
????????label.setText("&Interfaces:");
????????interfacesText = new Text(
????????????controls,
????????????SWT.BORDER | SWT.SINGLE);
????????gd = new GridData(
????????????GridData.FILL_HORIZONTAL);
????????interfacesText.setLayoutData(gd);
????????interfacesText.addModifyListener(
????????????new ModifyListener() {
????????????????public void modifyText(
????????????????????????ModifyEvent e) {
????????????????????dialogChanged();
????????????}
????????});
????????label = new Label(controls, SWT.NULL);
????????label.setText("Separated by ','");
????????dialogChanged();
????????setControl(controls);
????}
你需要了解SWT來書寫這些代碼。如果你對SWT不了解,在文章的最后有一些鏈接,這些鏈接可以告訴你學(xué)習(xí)SWT的地方。基本上這個方法創(chuàng)建了標(biāo)簽、輸入框并對他們進行了布局。每次輸入框的改變,它的數(shù)據(jù)也通過dialogChanged()方法來進行修改:
????
private void dialogChanged() {
????????String aPackage = getPackage();
????????String aSuperclass = getSuperclass();
????????String interfaces = getInterfaces();
????????String status = new PackageValidator().isValid(aPackage);
????????if(status != null) {
????????????updateStatus(status);
????????????return;
????????}
????????status = new SuperclassValidator().isValid(aSuperclass);
????????if(status != null) {
????????????updateStatus(status);
????????????return;
????????}
????????status = new InterfacesValidator().isValid(interfaces);
????????if(status != null) {
????????????updateStatus(status);
????????????return;
????????}
????????updateStatus(null);
????}
}
這些工作利用了3個工具類來完成:PackageValidator,SuperclassValidator和InterfacesValidator。我們將在后面來完成這三個類。
5.1 驗證類
在用戶輸入數(shù)據(jù)后,驗證工作可以在插件的任何部分完成。所以,將驗證代碼放在一個可重用的類中是有意義的,這樣比將驗證代碼四處拷貝要好得多。下面是一個驗證類的例子:
public class InterfacesValidator implements ICellEditorValidator
{
????public String isValid(Object value)
????{
????????if( !( value instanceof String) )
????????????return null;
????????String interfaces = ((String)value).trim();
????????if( interfaces.equals(""))
????????????return null;
????????String[] interfaceArray = interfaces.split(",");
????????for (int i = 0; i < interfaceArray.length; i++)
????????{
????????????IStatus status = JavaConventions
????????????????????.validateJavaTypeName(interfaceArray[i]);
????????????if (status.getCode() != IStatus.OK)
????????????????return "Validation of interface " + interfaceArray[i]
????????????????????????+ ": " + status.getMessage();
????????}
????????return null;
????}
}
其他的驗證類跟這個十分相似——參見文檔最后的源代碼。
另一個Eclipse工廠中的漂亮的類是JavaConventions,它將為我們驗證數(shù)據(jù)。它包含了很多驗證方法,例如:
●????????validateJavaTypeName()用來檢查類和接口的名稱
●????????validatePackageName()用來檢查包名
●????????validateFieldName()用來檢查數(shù)據(jù)成員的名稱
●????????validateMethodName()用來檢查方法名稱
●????????validateIdentifierName()用來檢查變量名稱
我們目前不需要使用ICellEditorValidator接口,但是在下一篇文章中,我們將使用到它。
六 結(jié)果
到這里,我們已經(jīng)完成了一個有圖片并由第二頁的向?qū)В鼘⒊跏蓟疘nvokatron文檔。圖2就是結(jié)果:

圖2 自定義的向?qū)?BR>
七 耀眼的小發(fā)明
正如我們所看到的,很多應(yīng)用都是數(shù)據(jù)驅(qū)動的。表現(xiàn)方式也很重要。一個糟糕的小發(fā)明是賣不出去的,但是一個耀眼的小發(fā)明卻可以賣出去。但是數(shù)據(jù),才是我們這些程序員的根源。
在這篇文章中,我們首先決定了那些數(shù)據(jù)是需要處理的。接著,我們通過定制的向?qū)Э梢暬夭东@了這些數(shù)據(jù)。下篇文章將在表現(xiàn)方式上進行進一步闡述,這將包括一個定制的編輯器和一個屬性頁。
八 資源
●????????PluginTest3.zip 示例代碼:[下載文件]
●????????“Eclipse Platform Online Help: Wizards”
●????????“Creating JFace Wizards”闡述了如何創(chuàng)建獨立的向?qū)?BR>●????????讀這些文檔來學(xué)習(xí)SWT。一定要閱讀“SWT: The Standard Widget Toolkit”的第一和第二部分,還有“Understanding Layouts in SWT”。
九 作者和譯者簡介
作者:Emmanuel Proulx 是一位J2EE和EJB方面的資深專家,也是一位WebLogic Server 7.0鑒定工程師。他主攻電信和網(wǎng)絡(luò)開發(fā)領(lǐng)域。
譯者:hopeshared 是一位在讀MSE,目前從事Eclipse插件研究與開發(fā)工作。
十 相關(guān)文檔
Eclipse Plugins Exposed, Part 2: Simple GUI Elements
Eclipse由大量的插件組成,但是你不能隨意的編寫代碼然后簡單的與之合并起來。在Emmanuel Proulx這個關(guān)于Eclipse的文章系列的第二部分中,他通過創(chuàng)建一個工具欄按鈕、菜單項、對話框等介紹了Eclipse的“擴展點”……
Eclipse Plugins Exposed, Part 1: A First Glimpse
很多開發(fā)者僅僅將Eclipse作為一個集成開發(fā)環(huán)境來使用,從來不去它強大的可擴展性。就像Emmanuel Proulx在這個系列文章的開始所展示的,Eclipse的插件系統(tǒng)提供給你一個可定制的工作平臺,這樣,你可以定制Eclipse來適應(yīng)開發(fā)的需求……