程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> EMF介紹系列(五、定制應用程序界面)

EMF介紹系列(五、定制應用程序界面)

編輯:關於JAVA

第三篇帖子介紹了定制一個EMF應用程序的基本方法,這一篇讓我們來看看怎樣定制應用 程序的使用界面。沒有任何一個界面是萬能的,所以定制工作不可避免,而大多數定制都是 通過修改代碼來實現的。在實際應用中,同一個需求可能有多種修改方式可以實現,我認為 修改涉及的地方(類,方法)越少越有利於發揮EMF的優勢,因此我們應該對EMF生成的代碼 有一定的了解,這是發揮自己創造力的基礎。

下面有幾個常見的需求,通過對這些需求的實現,相信你會對EMF應用程序的開發過程有 一個更具體的認識。

一、簡化模型創建向導

EMF幫我們生成的模型創建向導(菜單File->New->Other->Shop Model)分為兩 步,第一步要用戶輸入文件名,對於商店的例子文件名是*.shop格式;第二步用戶要選擇以 哪個對象作為根節點,同時要指定XML文件的編碼方式,商店例子裡顯然要以商店對象為根節 點,所以其實第二步可以省去,以免造成使用者的困擾。

生成的向導類是ShopModelWizard,比起增加一個步驟來,去掉一個步驟要簡單得多。首 先找到addPages()方法,把最後四句關於initialObjectCreationPage最的語句都注釋掉;

/**
* The framework calls this to create the contents of the wizard.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
*/
public void addPages() {

   //initialObjectCreationPage = new ShopModelWizardInitialObjectCreationPage("Whatever2");
   //initialObjectCreationPage.setTitle(ShopEditorPlugin.INSTANCE.getString ("_UI_ShopModelWizard_label"));
   //initialObjectCreationPage.setDescription (ShopEditorPlugin.INSTANCE.getString ("_UI_Wizard_initial_object_description"));
   //addPage(initialObjectCreationPage);
}

現在因為沒有了這個向導頁,原來由它提供的信息我們要改為在程序裡提供,所以要修改 另外兩個方法:第一,createInitialModel()方法本來是建立一個用戶選擇的對象作為根節 點的模型,我們把它改為直接建立一個Shop對象;

protected EObject createInitialModel() {
//  EClass eClass = (EClass)shopPackage.getEClassifier (initialObjectCreationPage.getInitialObjectName());
//  EObject rootObject = shopFactory.create(eClass);
   EObject rootObject=shopFactory.createShop();
   return rootObject;
}
第二,在performFinish()方法裡設置文件編碼的地方,改為使用UTF-8編碼,當 然你也可以規定使用其他編碼,只是用戶不能選擇了:

public boolean performFinish() {

   options.put(XMLResource.OPTION_ENCODING, "UTF- 8"/*initialObjectCreationPage.getEncoding()*/);

}

因此,這個類裡我們總共修改了三個方法,一定記得要把每個方法前的@generated標記刪 除或修改。現在,用戶只要簡單的指定文件名後就可以Finish了,如圖1所示。

圖1 向導的最後一頁

二、改造大綱視圖的顯示

對於EMF來說,在應用程序模型的根節點上還有兩層,分別是Resource和ResourceSet,在 商店的例子裡,Category的父節點是Shop,Shop的父節點是Resource(具體來說是 XMLResource),Resource的父節點是ResourceSet,它們之間都是多對一的關系。缺省情況 下,大綱視圖裡顯示的是完整的ResourceSet樹(根節點不顯示),顯示出的最上層節點是“ platform: /resource/Project3/My.shop”,它代表一個Resource,這個Resource(通過這 個URI)指向保存著模型信息的 XML文件My.shop。對於使用者來說,這個節點顯示在這裡沒 有什麼意義,用戶看到的根節點應該是.shop文件裡保存的Shop對象,見圖2的對比。

圖2 在大綱視圖裡隱藏最上層節點

那麼該修改哪些代碼來實現這個需求呢?我們想到 大綱視圖裡的內容是從ShopEditor的getAdapter()方法裡得到的,通過查看 ShopEditor的 getAdapter()方法發現名為getContentOutlinePage()的方法負責產生大綱模型,在這個方法 裡,變量contentOutlineViewer是對大綱視圖裡的樹控件的包裝對象,它的輸入(Input)是 editingDomain.getResourceSet(),我們要把它的輸入改成ResourceSet的第一個Resource, 修改後的代碼如下:

public IContentOutlinePage getContentOutlinePage() {
  
  //contentOutlineViewer.setInput (editingDomain.getResourceSet());
  contentOutlineViewer.setInput (editingDomain.getResourceSet().getResources().get(0));
  
}

你可能會問,那麼從Resource怎樣得到Shop對象呢?很簡單,(Shop) yourResource.getContents().get (0)即可,有興趣的話你可以試試把大綱視圖的輸入設為 Shop對象會看到什麼。最後說一次不要忘記修改@generated,以後不再提醒了。

三、 移除編輯器裡多余的Tab頁

EMF生成的Editor為我們提供了六個Tab頁,其主要目的是 向我們演示如何以各種方式展示數據(例如在大綱視圖裡選擇一個Category對象,通過 Parent頁裡可以很容易的看到前面說過的Category->Shop->Resource- >ResourceSet關系),在實際的應用裡一般不會用到全部這些頁,下面我們就只保留 Table頁而移除其他五頁,利用大綱和Table頁的組合,實現類似Windows資源管理器的界面。

編輯器裡的頁面在createPages()方法裡被添加,它雖然很長但EMF在這個方法裡生成了不 少注釋,每段代碼的作用都很明顯,只要把我們不需要的那五段注釋掉即可。現在把程序運 行起來,打開一個模型文件,稍微調整一下布局把大綱視圖放在編輯器的旁邊,如圖3所示, 有點資源管理器的樣子了吧。

圖3 和資源管理器類似的布局

但是很遺憾,現在的表格裡只有兩列,而且兩列裡顯示的內容是相同的。按照資源管理器 的設計,當用戶在大綱視圖裡選擇一個對象時,表格中應該顯示該對象的子對象詳細信息的 列表,現在子對象列表已經有了(表格裡每一行就是一個子對象),讓我們做一些修改以顯 示詳細信息。

首先增加一個表格列,還是在ShopEditor的createPages()方法裡修改,搜索一下 TableColumn很容易找到應該修改的位置。新的三列標題分別為“Name”、“Children”和“ Description”,其中Children列裡顯示子對象的數目。

public void createPages() {

   TableColumn objectColumn = new TableColumn(table, SWT.NONE);
   layout.addColumnData(new ColumnWeightData(3, 100, true));
   objectColumn.setText("Name");
   objectColumn.setResizable(true);

   TableColumn childrenColumn = new TableColumn(table, SWT.NONE);
   layout.addColumnData(new ColumnWeightData(2, 100, true));
   childrenColumn.setText("Children");
   childrenColumn.setResizable(true);

   TableColumn descColumn = new TableColumn(table, SWT.NONE);
   layout.addColumnData(new ColumnWeightData(2, 100, true));
   descColumn.setText("Description");
   descColumn.setResizable(true);

}

如果現在運行程序,看到的將是三列,但內容仍然是相同的。表格裡顯示的內容是由生成 的XXXItemProvider類決定的,例如對於一個 Category對象在表格或樹控件裡怎樣展示是由 CategoryItemProvider來負責,你可以把它看作是JFace裡的 ContentProvider加上 LabelProvider,這些XXXItemProvider都被放在.edit項目裡了。EMF生成的 CategoryItemProvider沒有實現ITableItemLabelProvider接口,所以缺省情況下不能支持表 格的展示(能夠顯示,但每列的內容相同),所以我們要對代碼進行一些修改,在 CategoryItemProvider實現的接口列表裡增加 ITableItemLabelProvider,並實現它的兩個 方法,修改後的代碼如下:

public class CategoryItemProvider
   extends ItemProviderAdapter
   implements
     IEditingDomainItemProvider,
     IStructuredItemContentProvider,
     ITreeItemContentProvider,
     IItemLabelProvider,
     IItemPropertySource,
     ITableItemLabelProvider{

   public Object getColumnImage(Object object, int columnIndex) {
     return null;
   }

   public String getColumnText(Object object, int columnIndex) {
     Category category=(Category)object;
     switch (columnIndex) {
     case 0:
       return category.getName();
     case 1:
       return category.getChildren().size()+"";
     case 2:
       return "";//Categories don't own descriptions
     default:
       return "";
     }
   }

}

現在只差一步就完成了,如果你注意看過ShopEditor的createPages()方法裡定義 TableViewer的代碼,會發現這個 TableViewer的ContentProvider和LabelProvider都是一個 AdapterFactoryContentProvider對象,這個對象會把TableViewer對getText()、 getElements ()的請求轉發到XXXItemProvider上;轉發之前它要得到這個XXXItemProvider ,這是通過 ShopItemProviderAdapterFactory的adapt()方法實現的,而 ShopItemProviderAdapterFactory維護了一個supportTypes列表,只有注冊到這個列表中的 類型才能被adapt。這裡出現了不少新內容,可能不那麼容易理解,沒有關系,因為在以後的 帖子裡會專門介紹到它們,現在只要記住需要把我們新實現的接口類型注冊到 ShopItemProviderAdapterFactory的supportTypes裡即可,具體的方法是修改它的構造方法 ,如下所示:

public ShopItemProviderAdapterFactory() {
   supportedTypes.add(IEditingDomainItemProvider.class);
   supportedTypes.add(IStructuredItemContentProvider.class);
   supportedTypes.add(ITreeItemContentProvider.class);
   supportedTypes.add(IItemLabelProvider.class);
   supportedTypes.add(IItemPropertySource.class);
   supportedTypes.add(ITableItemLabelProvider.class);//Added to support table
}

現在,表格裡顯示的Category對象已經按我們的要求列出其他信息了,如圖4 所示,Description列是空白因為Category沒有這個屬性。我們還應該修改 ProductItemProvider以展示產品的詳細信息,方法和修改Category是類似的,而且增加 supportTypes的步驟不須要重復做,所以更加簡單了,不妨就留作練習。

圖4 經過定制的表格

經過上面的這些定制,我們就實現了應用程序從EMF缺省界面到資源管理器風格界面的轉 換,雖然文字比較多,但掌握以後這個過程是相當快速的,而且其他的定制也是同樣的思路 。

本文配套源碼

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