程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 創建Eclipse游戲插件,第1部分: 入門

創建Eclipse游戲插件,第1部分: 入門

編輯:關於JAVA

雖然大多數用戶把 Eclipse 當成構建 Java™ 應用程序的集成開發環境,但它實際上更加基礎。Eclipse 是個構建插件的框架,允許任何開發人員擴展它的功能來解決幾乎任何問題,只要利用一套 API 和可用的庫即可。在這個分四個部分的 “創建 Eclipse 游戲插件” 教程系列中,將解決大多數程序員每天編程都會遇到的一個迫切的問題:如何不用切換應用程序就抽身玩一個快速的視頻游戲,同時還不會很明顯。還將學習 Eclipse 的插件架構,學習如何定義自己的插件、用 SWT 開發界面,並創建與其他 Eclipse 資源交互的代碼。

開始之前

這份教程是四部分的 “創建 Eclipse 游戲插件” 系列的第 1 部分,它側重於構建簡單射擊視頻游戲的框架,通過創建插件、安裝插件、把插件與任務列表集成並用 SWT 和 OpenGL 添加一些基本的可視組件,可以在 Eclipse 內部啟動和玩這個游戲。將開發一個簡單的射擊游戲,讀取在任務視圖中遇到的蟲子,並把這些蟲子摧毀。游戲將在 Eclipse 內部作為插件運行,從而演示如何編寫 Eclipse API,以及如何使用標准小部件工具包(SWT)、開放圖形庫(OpenGL)和輕量級 Java 游戲庫(LWJGL)。

關於這個系列

在這個系列中,將介紹用來創建特性完整的 Eclipse 插件的基本技術、工具和庫,將使用標准小部件工具包(SWT)和 OpenGL 庫提供圖形。第 1 部分介紹如何構建簡單視頻游戲的框架,通過創建插件,可以在 Eclipse 內部啟動並玩這個游戲。第 2 部分利用第 1 部分創建的基本框架,開始用 Open GL 添加實際的可視元素。第 3 部分添加實際的游戲元素,讓用戶能夠與第 2 部分中創建的圖形交互。第 4 部分將前三部分創建的所有內容組合在一起工作。

關於這份教程

在第 1 部分中,將介紹 Eclipse 的插件架構,學習如何用 Eclipse 工具本身定義自己的插件。還將開始利用 SWT 開發插件的簡單用戶界面。還將創建代碼,演示如何與其他 Eclipse 資源交互 —— 在這個示例中,是與任務列表交互。在結束時,將擁有一個良好的框架,可以構建一個能直接在 Eclipse 內工作的簡單的射擊視頻游戲;在剩下的教程中,將繼續添加功能。

前提條件

將需要 Eclipse V3.2 和 Java 編譯器和解釋器 V1.4 或以上版本。

創建插件

我們從使用 Eclipse Plug-in 向導來定義插件開始這個開發過程。

啟動 Eclipse 並定義項目

啟動 Eclipse,選擇 File > New > Project。

在 New Project 屏幕中,選擇 Plug-in Development 文件夾,並選擇 Plug-in Project,如圖 1 所示。

圖 1. 選擇 Plug-in Project 向導

在 New Plug-In Project 屏幕上(請參閱圖 2),輸入插件的名稱。因為這是個射擊游戲,所以使用 com.devworks.tutorial.shootout 這個名稱。使用按這個名稱創建的默認目錄;這個目錄位於工作區之下。請確保選中了 Project Settings 中的 Create a Java Project 復選框,保持文件夾的默認名稱 /src 和 /bin 不變。最後,對於目標平台,選擇 Eclipse V3.2。

圖 2. 設置項目名稱和目錄

描述插件

每個插件都由一個叫作 plugin.xml 的 XML 清單文件描述,這個文件和包捆綁在一起。下面的 Plug-in Properties 屏幕(請參閱圖 3)讓您可以不必手工創建這個文件 —— 避免手工創建總是好事。保持屬性頁中的值不變,但是請注意清單提供的信息類型:版本、名稱、供應商等等。

在 Plug-in Options 屏幕上,請確保選中了 Generate an activator 復選框,確保類名設置為 com.devworks.tutorial.shootout.ShootoutPlugin。還請確保選中了 This plug-in will make contributions to the UI 復選框。

最後,對創建富客戶端應用程序這個問題回答 No。用它創建 Eclipse 的一個線程管理版本,允許在 Eclipse 框架上構建整個應用程序。現在就創建了一個插件。

圖 3. 輸入要在清單中保存的插件屬性

選擇插件的模板

向導的下一個屏幕,如圖 4 所示,提問是否要用模板。對於射擊游戲,將創建一個視圖,所以請選中 Create a plug-in using one of the templates 復選框,然後選中 Plug-in with a view 復選框。正如這個圖右側面板上的文本所解釋的,這個模板會提供工作台視圖的基本功能,包括對菜單、工具欄等的支持。

圖 4. 選擇帶有視圖模板的插件

設置視圖屬性

在圖 5 所示的下一個屏幕中,將定義視圖的各種設置。再一次,為了保證游戲的射擊主題,請確保 View Class Name 是 ShootoutView,View Name 是 Shootout View(請注意空格)。請把 View Category 的名稱改成 Devworks Tutorial。這樣,後面在 Open View 屏幕中打開視圖時,事情會簡潔。確保選中了 Add the view to the resource perspective,這樣就能看到它了。如果要啟動,就要在基本 Table Viewer 模型中展開,所以請選擇 Table viewer 作為這個視圖中容納的查看器模型。

圖 5. 設置視圖屬性

最後,在最後一個屏幕上(請參閱圖 6),保持默認選項(在這個示例中,所有特性都被選中)不變。有些屬性將在後面使用,但是在檢查向導生成的代碼時,看看這些屬性會有指導意義。

圖 6. 選擇視圖支持的動作

完成向導並檢查結果

點擊 Finish,Eclipse 會詢問是否想轉到與插件開發有關的視圖。回答 Yes,將生成項目的框架,並切換到合適的視圖。

Eclipse 桌面現在應當顯示插件視圖(請參閱圖 7)。如果在包浏覽器中研究 com.devworks.tutorial.shootout 包,將看到向導已經生成了兩個類:ShootoutPlugin.java 和 ShootoutView.java。這兩個類與在向導中選擇的名稱匹配。

圖 7. 插件視圖和生成的類

ShootoutPlugin 擴展了 Eclipse 架構定義的 AbstractUIPlugin,是插件行為的啟動點。ShootoutView 類擴展了 ViewPart 抽象類,創建它是因為前面向導要求提供 “帶視圖的插件”。以後將添加自己的小部件和可視元素到這個類。

向導還會用前面在對應的屏幕中提供的值生成 plugin.xml。這個清單文件將與最終的插件捆綁在一起,用來向 Eclipse 描述包。Eclipse 提供了一套很好的表格式屏幕,用來編輯 plug-in.xml,如圖 7 所示。可以用這套屏幕調整與插件相關的屬性 —— 特別是對其他插件的依賴性。

編譯並運行新插件

這個插件目前什麼也不做,但從 Eclipse 的角度來看,它仍然是一個完整、合法的插件。可以用 Eclipse 提供的另一個向導把插件導出以供使用。

選擇如何分發插件

捆綁和部署插件有多種方式和多種技術。可以選擇編寫 Apache Ant 腳本來編譯代碼,把最終代碼壓縮到一個 zip 文件,並作為獨立文件發布。也可以按照這裡介紹的手工方法,用向導生成並正確地打包所需要的所有東西。

請選擇 File > Export 並選擇 Plug-in Development,然後選擇 Deployable Plug-ins and fragments(請參閱圖 8)。

圖 8. 導出插件

然後,會看到所有可以導出的插件。請確保選中了 shootout 插件。對於導出目的地,請選擇 Archive file 選項,浏覽到工作區下的 com.devworks.tutorial.shootout 目錄,並輸入 EclipseShootout 作為歸檔名稱,如圖 9 所示。

圖 9. 設置插件包的屬性

也可以從這個屏幕中選擇其他選項,例如是否把源代碼打包在插件中。對於這個練習,使用默認設置即可。

選擇 Finish,然後 Eclipse 就會開始它的導出過程。

研究生成的包

導出向導將編譯項目中所有的類,把 .class 文件放在 bin 目錄中,就像在項目創建時對項目的設置一樣。(bin 在包浏覽器的視圖中是隱藏的,但它是與 src 目錄對應的目錄。可以用文件系統的浏覽器導航到工作區中查看這個目錄。)

編譯完成之後,請按 F5 刷新包浏覽器窗口,現在在項目的根級上應當看到 EclipseShootout.zip。

請打開 zip 查看器(請參閱圖 10)並研究其中的內容。

圖 10. 研究生成的 zip 文件的內容

看到的內容是 Eclipse 裝入插件時期望看到的結構。有清單 plugin.xml、一個浏覽器使用的圖標(在這個示例中,是由插件向導自動生成的默認圖標);一個包含編譯的類的 JAR 文件。所有的文件都包含在叫作 plugins/com.devworks.tutorial.shootout_1.0.0 目錄中 —— 也就是說,在安裝的時候,插件的內容將進入以插件名稱加插件版本號命名的目錄中,而且全都放在 Eclipse 的 plugin 目錄中。

如果選擇通過 Apache Ant 腳本自動進行插件的構建和打包,請確保構建過程生成類似的目錄結構。

安裝插件

現在已經有了一個打包好的插件,可以實際地把它安裝在 Eclipse 中,看到它和其他插件列在一起。

現在,這個插件的安裝方法可能沒有下載和安裝其他插件時使用的方法那麼漂亮。這是因為大多數公開的插件是通過精心構造的 Web 站點(稱為 Eclipse 更新站點)分發的。可以通過另一個向導輕松地創建這樣的插件,但是這超出了這份教程的范圍。

要安裝我們的插件,只要關閉 Eclipse,把 zip 文件解壓縮到 Eclipse 的應用程序目錄即可(注意要解壓到與 plugin 目錄同級的目錄中,如圖 11 所示)。

圖 11. 檢查 Eclipse 的 plugin 目錄,查看自己的插件

重新啟動 Eclipse 並選擇 Window > Show View > Other。在出現的窗口中,應當看到一個叫作 Devworks Tutorials 的分類。展開這個分類,就應當看到 Eclipse Shootout,如圖 12 所示。

圖 12. 選擇新插件的視圖

運行插件

請從列表中選擇插件,這將把插件裝入當前的 Eclipse 環境。將看到 Eclipse 把視圖裝入底部面板,作為一個選項卡與 Tasks、Problems 等信息卡並列,如圖 13 所示。

圖 13. 享用 Shootout 視圖

請注意選項卡的名稱是 “Shootout View”,與前面在向導中指定的名稱完全相同。還請注意,它提供了一些默認行為 —— 即有三個條目的列表。如果點擊其中一個條目,將看到事件被捕捉到並顯示在屏幕上。(請參閱圖 14)。

圖 14. 從視圖上捕捉到的鼠標點擊事件

所有這些行為都定義在向導生成的 ShootoutView.java 類中。請從包浏覽器中選擇這個文件,並注意條目列表是在哪裡定義的:

public Object[] getElements(Object parent) { 
  return new String[] { "One", "Two", "Three" } 
  } 

類似的,點擊事件捕獲的動作由這樣的代碼定義:

action1 = new Action() {      
    public void run() { 
    showMessage("Action 1 executed"); 
    } 
}; 

通過查看這個文件,可以看到添加游戲功能所需修改的一些代碼。

創建基本界面

現在已經有了插件的基本框架,可以用標准小部件工具包(SWT)添加一些可視組件了。

SWT 介紹

SWT 是一個輕量級部件 API,利用了平台的本機部件。這就允許實現 Java 承諾的 “編寫一次,處處運行”,同時還具有豐富的用戶界面,看起來就像在本機窗口環境中編寫的應用程序一樣 —— 不論是 Windows®、OS X 還是 KDE 等等。

SWT 為圖形設計師創建最復雜的應用程序提供了所需要的全部部件 —— 從簡單的文本和按鈕,到更復雜的樹和菜單,應有盡有。SWT 捕捉事件(例如鍵盤按鍵和鼠標點擊),允許編寫自定義處理程序。它為更復雜的組件(例如表格)提供布局管理器和一套充當模型的對象(稱為 JFace)。簡而言之,它是一個特性全面的用戶界面 API。

SWT 與已經打包在 Java 中的用戶界面 API(AWT、Swing)的區別在於,它大量地使用了本機部件。盡可能多的工作都委托給本機平台,包括渲染和聲明。這就讓實現非常輕便,而且還能保證它的行為與本機用戶界面的行為盡可能接近,而且不需要折衷或為特定的平台編寫特殊代碼。

整個 Eclipse 平台就完全是用 SWT 構建的,所以 SWT 是編寫插件的合理選擇。因為已經告訴插件向導創建一個與用戶界面交互的視圖插件,所以 SWT 庫已經成為項目構建環境的一部分,已經可以使用了。如果檢查 ShootoutView 類,可以看到已經導入和使用了一些 SWT 類。

對於這個系列的第 1 部分中的射擊游戲,將創建幾個啟動和控制游戲的按鈕,在屏幕上顯示這些按鈕,並提供它們行為的框架。在後面的教程中,將擴展這些,並創建更復雜的部件,創建游戲剩下的部分。

檢查 Eclipse 生成的內容

對於射擊游戲,可以在 Eclipse 已經生成的基礎上進行構建。首先,請打開 ShootoutView 類。

這個類擴展抽象類 org.eclipse.ui.part.ViewPart。ViewPart 是 Eclipse 中所有視圖的基類。作為抽象類,其中有一些在擴展中必須實現的方法。

具體來說,請檢查 createPartControl 方法,其中一部分如清單 1 所示(請參閱 下載 查看整個方法,以及這份教程中創建的其他類和方法)。這個方法在需要的時候由 Eclipse 工作台調用,用於創建視圖。就是在這裡進行部件布局要做的基本工作,在這裡也可以看到生成的代碼用一個叫作 viewer 的實例變量做這件事。Viewer 被定義成類 TableViewer 的實例。

清單 1. 原始的 createPartControl 方法的一部分

/**
    * This is a callback that will allow us
    * to create the viewer and initialize it.
    */
   public void createPartControl(Composite parent) {
     viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
     viewer.setContentProvider(new ViewContentProvider());
     viewer.setLabelProvider(new ViewLabelProvider());
     viewer.setSorter(new NameSorter());
     viewer.setInput(getViewSite());
     makeActions();
     hookContextMenu();
     hookDoubleClickAction();
     contributeToActionBars();
   }

TableViewer 是 JFace 組件的一個示例。JFace 是 SWT 中的一套類,它們包裝了比較復雜的部件(例如樹、復合框等等),並提供了與復雜對象更好的結合。也就是說,JFace 對象使程序員不必手工地把業務對象(可能包含行為、復雜對象等)解構成簡單的名稱/值組合(SWT 部件要求的)。類 org.eclipse.jface.viewers.TableViewer 包裝了 org.eclipse.swt.widgets.Table。

視圖如何創建和初始化

在 createPartControl 方法中,請注意在 viewer 實例變量用新的 TableViewer 初始化之後,下一行是 viewer.setContentProvider(new ViewContentProvider()。 ViewContentProvider 是在 ShootoutView 內部定義的內部類。

ViewContentProvider 實現了接口 org.eclipse.jface.Viewers.ISructuredContentProvider。這個接口定義了方法 getElements(),TableViewer 在需要填充底層表格時調用這個方法。可以看到它返回一個對象數組。在這個示例中,Eclipse 向導創建了一個簡單的對象數組。可以看到在需要用真實數據填充表格的時候,這個方法是需要修改的方法。

createPartControl() 方法包含對私有方法的額外調用,這些方法設置處理鍵盤輸入和鼠標點擊所需要的回調。在後面的部分中,將進一步詳細研究這些內容。

安排好布局

但是首先,要創建兩個按鈕,並把它們放在 TableViewer 下面。要做這個工作,必須首先創建和管理一個包含所有部件的布局。

同樣,請注意創建 TableViewer 的那一行:

viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);

所有的 SWT 組件,在創建的時候,都被分配給一個容器,容器成為組件的雙親。現在的視圖的雙親被傳遞給 createPartControl,並定義為 org.eclipse.SWT.widgets.Composite。而 composite 指的是任何能夠包含其他 SWT 部件的 SWT 部件。從插件視圖的角度來說,就是窗口。

不幸的是,生成的代碼認為在這個窗口中要做的全部工作就是 TableViewer。由於代碼已經生成,所以沒有簡單的方法可以添加按鈕並讓按鈕出現在需要的位置上。必須首先引入一個布局,由它管理部件(包括 TableViewer)的位置和尺寸。

使用 GridLayout 和 GridData

Eclipse 在 org.eclipse.swt.layout 包中提供了許多布局。其中最強大最靈活的布局之一是 GridLayout。請在 createPartControl 方法的頂部現有方法之前,添加以下代碼:

GridLayout gridLayout = new GridLayout();
gridLayout.numColumns = 2;
parent.setLayout(gridLayout);

這就創建了一個 GridLayout 布局管理器,它有兩個列,並把它設置成畫布(傳遞給這個方法的雙親)使用的布局管理器。

現在可以控制 TableViewer 部件的擺放了。要做這個工作,將使用 GridLayout 的伴侶類 GridData。請添加下面這些行:

GridData gridData = new GridData();
gridData.horizontalSpan = 2;
gridData.horizontalAlignment = SWT.FILL;

這告訴布局管理器:想讓部件占兩列,讓布局管理器把對象拓寬以占滿每個列。

然後把 GridData 對象分配給想在上面實施這些約束的部件。在這個示例中,是 TableViewer 對象。但是有一個問題:TableViewer 實際不是個 SWT 對象;它是 Table 對象的包裝器。這個對象上看起來沒有方法可以用來設置它的布局。

實際上,必須要做的是訪問底層 SWT 表格,然後直接設置它的布局。請在調用 viewer 的不同設置器的塊之後添加這行代碼:

viewer.getTable().setLayoutData(gridData); 

createPartControl 現在看起來應當像清單 2 一樣。

清單 2. 到目前為止的 createPartControl 方法

public void createPartControl(Composite parent) {

   GridLayout gridLayout = new GridLayout();
   gridLayout.numColumns = 2;
   parent.setLayout(gridLayout);
   GridData gridData = new GridData();
   gridData.horizontalSpan = 2;
   gridData.horizontalAlignment = SWT.FILL;

   viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
   viewer.setContentProvider(new ViewContentProvider());

   viewer.setLabelProvider(new ViewLabelProvider());
   viewer.setSorter(new NameSorter());
   viewer.setInput(getViewSite());
   viewer.getTable().setLayoutData(gridData);
   makeActions();
   hookContextMenu();
   hookDoubleClickAction();
   contributeToActionBars();
}

添加按鈕

現在要添加兩個簡單的 SWT 部件按鈕。現在它們還什麼也不做。但是在下一節,將讓其中一個用來自任務列表的數據裝載 TableViewer;另一個將在下一篇教程處理,讓它啟動游戲。

在 createPartControl 現有的代碼塊(多數由向導創建)之後,請添加以下代碼:

清單 3. 創建按鈕

Button loadBugsButton = new Button(parent, SWT.PUSH);
loadBugsButton.setText("Load Bugs");

Button startGameButton = new Button(parent, SWT.PUSH);

startGameButton.setText("Start Game");

這將在視圖的底部添加兩個按鈕,一個挨著一個,在 TableViewer 對象下面,看起來就像本機平台的按鈕一樣。

請注意,不需要把 GridData 對象修改或分配給這兩個按鈕。根據定義,GridLayout 的性質就是調整這兩個對象的尺寸,從左到右填滿網格。由於把 TableViewer 限制在只接受所定義的兩列,所以按鈕會在下一行繪制。

createPartControl 現在看起來應當像清單 4。

清單 4. 完成的 createPartControl 方法

public void createPartControl(Composite parent) {

   GridLayout gridLayout = new GridLayout();
   gridLayout.numColumns = 2;
   parent.setLayout(gridLayout);
   GridData gridData = new GridData();
   gridData.horizontalSpan = 2;
   gridData.horizontalAlignment = SWT.FILL;

   viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
   viewer.setContentProvider(new ViewContentProvider());
   viewer.setLabelProvider(new ViewLabelProvider());
   viewer.setSorter(new NameSorter());
   viewer.setInput(getViewSite());
   viewer.getTable().setLayoutData(gridData);
   makeActions();
   hookContextMenu();
   hookDoubleClickAction();
   contributeToActionBars();

   Button loadBugsButton = new Button(parent, SWT.PUSH);
   loadBugsButton.setText("Load Bugs");
   Button startGameButton = new Button(parent, SWT.PUSH);
   startGameButton.setText("Start Game");
}

測試目前為止的插件

插件創建之後,曾經像處理完成的產品一樣安裝它 —— 把包解壓縮到 Eclipse 的 plugin 目錄。現在已經修改了它,所以再次測試它需要重新導出最新的包,關閉任何打開的插件視圖,退出 Eclipse,導航到 plugin 目錄,刪除以前的版本,解壓縮最新版本並重新啟動 Eclipse。可以想像,如果每次都要做所有這些工作才能進行測試,會減慢測試/編譯/調試的過程。謝天謝地,Eclipse 有一種直接測試插件的方式:運行時工作台。要使用這種方式,請先刪除前面安裝的插件(按照上面過程的第一部分),重新啟動 Eclipse,並做以下操作:

從菜單中,選擇 Run > Run... 並從 “Create, manage, and run configurations” 屏幕的 Configureations 菜單選擇 Eclipse Application。

選擇 New 並輸入名稱 Eclipse Shootout Plug-in Test。可以保持 Main 選項卡中的剩余字段為默認值(請參閱圖 15)。

選擇 Plug-ins 選項卡。還是保持默認值不變,但是請確保看到我們的插件列在 “Workspace Plug-ins” 之下。請選擇 Apply。

圖 15. 配置測試插件的運行時工作台

現在選擇 Run。Eclipse 將編譯代碼,然後在一個新的 Eclipse 環境中運行它,就像手工安裝的一樣。應當看到出現第二個窗口,與圖 16 類似。

圖 16. 目前為止的插件

請注意,在工作台的視圖區中已經創建了插件視圖。點擊按鈕應當造成它們的外觀切換,但是它們什麼也不做,因為還沒有編寫它們的事件。但是 TableViewer 本身的行為應當像從前一樣。雙擊列表中的一個條目,應當顯示一個模態對話框,指出所點擊的項目。

與任務視圖鏈接

正在編寫的游戲可以讓你摧毀添加到任務視圖的蟲子。在這一節,將編寫 Load Tasks 按鈕,把任務視圖裝入視圖中的 TreeViewer。

IMarker 接口和任務標記器

任務視圖中的條目實際上是 Eclipse 架構中內置的一個類的實例,用來容納注釋和其他標注,稱為標記器(Marker)。標記器由叫作 IMarker 的接口定義,實際上標記器是容納注釋和其他屬性的容器的句柄。

有各種不同類型的標記器 —— 有些是預定義的,有些是自己創建的。標記器由類型字符串標識。Eclipse 預定義了五種類型,其中一個就是任務。任務標記器的類型字符串是 org.eclipse.core.resources.taskmarker。

把資源裝入項目

IMarker 接口和需要使用的其他一些類都在包 org.eclipse.core.resources 中。這個包不是由向導在創建插件時添加的包,所以需要手工把它添加成依賴包。

從包浏覽器視圖中,選擇 plugin.xml 進行編輯,然後選擇底部的 Dependence 選項卡。應當看到與圖 17 所示類似的編輯器窗格。

圖 17. 編輯 plugin.xml,添加新的依賴包

選擇 Add,將看到一個彈出窗口,列出所有可以添加的包,如圖 18 所示。

圖 18. 添加 org.eclipse.core.resource 包

請選擇 OK,並確保保存 plugin.xml。(請記住:盡管 Eclipse 提供了漂亮的彈出窗口和部件,實際上在底層仍然是在編寫 XML。)這個包將列在包浏覽器的插件依賴項當中。這讓它既可以在編輯和編譯的時候使用(允許編輯器解析對這個包的引用),又可以在部署時使用。

這個包物理上的分發是在 Eclipse 安裝的 plugin 目錄的 org.eclipse.core.runtime_3.2.0.v20051208.jar 中。您可能想只把它添加到構建路徑中。這樣只允許代碼編譯,但是在工作台的測試期間,就會收到運行時錯誤,報告 Workspace is closed。如果手工地導出和安裝它,就會接收到運行時錯誤,因為這個包中的類無法解析。把這個包添加為插件依賴項,可以確保把合適的類打包,在插件運行的時候能夠使用。

查找當前工作區中的任務

要訪問任務列表,必須訪問當前工作區的所有標記器的列表,並過濾出類型為 org.eclipse.core.resources.taskmarker 的標記器。

請在編輯器中打開 ShootoutView 類,並添加清單 5 所示的方法。

清單 5. 從當前工作區檢索任務的新方法

private void getTasks() throws CoreException {

   IWorkspace workspace = ResourcesPlugin.getWorkspace();

   IWorkspaceRoot workspaceRoot = workspace.getRoot();

   IMarker[] imarkers = workspaceRoot.findMarkers\
   (IMarker.TASK, true, IResource.DEPTH_INFINITE);

}

請記住,在 Eclipse 中,幾乎所有東西都是插件,ResourcesPlugin 是一個代表 Resources 插件的單體 —— 也就是說,是一個可以訪問運行時資源(包括當前工作區)的插件。

getWorkspace 調用返回當前工作區,然後 getRoot 調用返回這個工作區的根。從這兒開始,就能夠檢查當前環境了。

對 findMarkers 的調用詢問當前工作區的根,查找當前所有類型為 IMarker.TASK(這是個預定義常量,代表 Task 類型的標記器的類型字符串)的標記器。下一個參數 true 告訴 findMarkers 包含 Task 類型的子類型(通常沒有)。最後一個參數告訴方法從任何直接或間接的資源中檢索任務標記器,這應當包含整個工作台。findMarkers 會返回與這些參數匹配的標記器的數組。

讓 TableViewer 能夠查看任務

接下來,請修改 ViewContentProvider 以及與它相關的類,把默認的 “one, two, three” 替換成來自任務視圖的任務。請把下面這些行添加到 ViewContentProvider 內部類,如清單 6 所示。

清單 6. 修改 ViewContentProvider 類

private IMarker[] tasks = new IMarker[0];

public void setTasks(IMarker[] tasks) {

   this.tasks = tasks;

}

然後修改 getElements 方法,檢索這個新屬性:

public Object[] getElements(Object parent) {

   return tasks;

}

這將修改插件的 TableViewer 使用的模型。通過把 tasks 屬性初始化為空而不是 null,可以避免收到運行時錯誤 “Unable to create view: null argument”。

這個代碼現在並不顯示列出的任務的名稱。相反,將看到一個典型的 toString 輸出(類名和哈希碼)。在這種情況下,是容納任務的標記器類的實例的 toString。當然,我們想得到的是任務的文本。

為了讓視圖看到任務的文本,需要修改向導生成並由 TableViewer 使用的另一個內部類:ViewLabelProvider。ViewLabelProvider 擴展了 LabelProvider 類並實現了 ILabelProvider 接口。這個接口定義了一個叫作 getText 的方法,它的作用就是通過編寫這個方法,從 ContentProvider 持有的對象中檢索對應的屬性。

LabelProvider 類返回對象的 toString,實現了這個方法的默認行為,這就是在 TableViewer 中看到這樣的任務標記器標簽的原因。要把這個方法改成返回合適的值,應該覆蓋這個方法,添加下面這些代碼到 ViewLabelProvider 類中,如清單 7 所示。

清單 7. 覆蓋 getText 方法

public String getText(Object obj)
{

   return ((IMarker)obj).getAttribute(IMarker.MESSAGE, "<none>");

}

如前所述,實現 IMarker 接口的類的實例只是到對象的句柄,對象實際容納構成標記器的屬性。為了訪問屬性,IMarker 接口包含許多字符串,代表許多預定義標記器類型的公共屬性。在這個示例中,想看到的是任務標記器的 MESSAGE 屬性。這個屬性容納用戶輸入的字符串。

編寫按鈕,裝入 TableViewer

最後,想讓這個代碼在按下 Load Bugs 時全部執行。要把動作加到按鈕上,請通過 addSelectionListener 方法把 SelectionListener 添加到按鈕部件。這個方法需要 SelectionListener 類的實例。對於簡單偵聽器,可以用匿名內部類擴展 SelectionAdapter, 如清單 8 所示。

清單 8. 添加選擇偵聽器到 loadBugsButton

loadBugsButton.addSelectionListener(new SelectionAdapter() {

   public void widgetSelected(SelectionEvent event) {
     try {

       ShootoutView.this.getTasks();
     }

     catch (Exception e) { showMessage("loadBugsButton.widgetSelected():exception. "
+ e.getMessage());
     }
   }
});

這會調用前面定義的 getTasks 方法,它會查詢工作區,得到當前任務。但是,這個方法在檢索完任務之後什麼也不做。作為最後一步,必須把它們傳遞給 ViewContentProvider 並刷新 TableViewer。請把以下這些行添加到 getTasks 方法的底部:

((ViewContentProvider)ShootoutView.this.viewer.getContentProvider()).setTasks(imarkers);
   ShootoutView.this.viewer.refresh(true);

第一行從 ShootoutView 中的 TableViewer 實例檢索出 ViewContentProvider 類上的 setTasks 方法,然後傳遞給它 findMarkers 發現的結果,對它進行調用。

下一行重繪 TableViewer 部件,這樣新的記錄就會顯示出來。true 參數讓 TableViewer 重繪整個列表,而不僅僅是它認為是新的條目。getTasks 方法現在看起來應當像清單 9 這樣。

清單 9. 完成的 getTasks 方法

private void getTasks() throws CoreException {

   IWorkspace workspace = ResourcesPlugin.getWorkspace();
   IWorkspaceRoot workspaceRoot = workspace.getRoot();
   IMarker[] imarkers = workspaceRoot.findMarkers(IMarker.TASK, true,
  IResource.DEPTH_INFINITE);
   ((ViewContentProvider)ShootoutView.\
   this.viewer.getContentProvider()).setTasks(imarkers);
   ShootoutView.this.viewer.refresh(true);
}

測試 Load Bugs 按鈕

請選擇 Run > Run... 並選擇最後一次創建的 “Eclipse Shootout Plug-in Test” 配置。按下 Run 來測試到目前為止的工作。請選擇 Window > Show View > Other > Open Other > Basic > Tasks 打開任務視圖。輸入一些任務,如圖 19 所示。

圖 19. 在運行時工作台中輸入任務

接下來,切換到 Shootout 視圖,按下 Load Bugs 按鈕。應當看到與圖 20 類似的東西。

圖 20. 完成後的插件在按下 Load Bugs 之後的動作

恭喜!現在已經創建了一個正常工作的插件,而且為 “創建 Eclipse 游戲插件” 這個系列以後的教程打好了基礎,在後來的教程中,將把這個蟲子列表變成真正的敵人,用超級火力消滅它們。

結束語

插件框架是 Eclipse 的核心,它的設計目的是輕松地進行擴展以滿足任何需求。向導可以容易地快速創建插件。插件可以執行許多功能,但是通常有視圖顯示在工作台上。在這份教程中(四部分系列的第 1 部分),為創建射擊游戲插件打好了基礎。用來設計最初的用戶界面的 SWT 是一個輕量級圖形庫,允許程序員將圖形元素添加到視圖中,例如按鈕和列表。列表通常由 JFace 的 TableViewer 處理。JFace 是一組比較復雜的部件,包裝了 SWT 中一些較簡單的部件;TableViewer 包裝了簡單的 Table 對象,提供了定義良好的接口,用來對表格使用的數據和標簽進行建模。

工作台本身包含許多可供插件開發人員使用的資源,包括稱作標記器的特性。任務視圖中的任務(在游戲中被摧毀的蟲子列表)實際上是標記器,能夠通過 org.eclipse.core.resources 包中的類訪問。任務視圖運行和測試插件是通過運行時工作台特性實現的,而插件的打包可以通過導出特性完成。

在這個 “創建 Eclipse 游戲插件” 系列的第 2 部分中,將添加形狀、顏色和移動,開始開發射擊游戲。

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved