首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

GEF 入門系列(四):DirectEdit、屬性頁與大綱視圖實現

     編輯:Java 相關知識

最近因實驗室任務繁重,未繼續研究 GEF,原本掌握的知識似又丟失不少。剛接觸 GEF 的朋友常有此印象:GEF 概念多、繞,一些能直接實現的功能非要拐彎到另一個類做,且很多類名相似,加上不知其作用,感覺像一團亂麻。我覺得這是由 GUI 複雜性決定的,GUI 看似簡單,實際包含相當多邏輯,特別是 GEF 處理的圖形編輯方式,可說是最複雜的一種。GEF 每個類都有存在理由,需盡可能了解作者意圖,這需要多看文檔和好例子。

在 Eclipse 查看文檔和代碼很便利:不清類用法,先看註解(選中類或方法按 F2),再看其他地方用法(Ctrl+Shift+G),還可看源代碼(Ctrl+滑鼠左鍵或 F3),Ctrl+Shift+T 可按名稱查找類。學 GEF 少不了看代碼,還需時間和耐心。

本文繼續上篇內容,主要討論如何實現 DirectEdit、屬性頁和大綱視圖,這些是完整 GEF 應用程序需要提供的基本功能。

實現 DirectEdit

所謂 DirectEdit(也稱 In-Place-Edit),即允許用戶在原本顯示內容處直接修改內容,如 Windows 資源管理器選中文件按 F2 修改文件名。實現原理直接:用戶發出修改請求(REQ_DIRECT_EDIT)時,在文字內容位置覆蓋一個文本框(也可下拉框,此處只討論文本)作為編輯器,編輯結束後將編輯器內容應用到模型。

圖1 Direct Edit

在 GEF 中,彈出編輯器由 DirectEditManager 類管理。在 NodePart 覆寫 performRequest() 響應用戶 DirectEdit 請求,構造 DirectEditManager 實例(範例中的 NodeDirectEditManager),傳入必要參數:接受請求的 EditPart(this)、編輯器類型(TextCellEditor)以及定位編輯器的 CellEditorLocator(NodeCellEditorLocator),然後用 show() 顯示編輯器,編輯器顯示內容已在構造方法得到。NodeCellEditorLocator 關鍵方法在 relocate(),編輯器內容改變時被調用,讓編輯器始終處於正確座標。DirectEditManager 有重要的 initCellEditor() 方法,主要作用是設置編輯器初始值。範例中初始值設為被編輯 NodePart 對應模型(Node)的 name 屬性值;還完成了設置編輯器字體和全選文字(selectAll)功能,更符合使用習慣。

NodePart 還要增加角色為 DIRECT_EDIT_ROLE 的 EditPolicy,繼承自 DirectEditPolicy,需實現兩方法:getDirectEditCommand() 和 showCurrentEditValue()。前者在編輯結束時生成 Command 將修改結果作用到模型;後者更新 Figure 顯示,雖編輯器覆蓋 Figure 文本似不需管 Figure 顯示,但編輯中保持兩文本一致才不會出現「蓋不住」情況(如編輯器文本較短時)。

實現屬性頁

在 GEF 實現屬性頁與普通應用基本一樣。如希望通過屬性視圖(PropertyView)顯示和編輯每個節點屬性,可讓 Node 類實現 IPropertySource 介面,並通過 IPropertyDescriptor[] 類型成員變數描述要在屬性視圖顯示的屬性。有朋友問,要在屬性頁增加屬性該改哪些地方,主要三處:首先在 IPropertyDescriptor[] 變數增加對應描述,包括屬性名和編輯方式(文本或下拉框,後者還要指定選項列表);其次在 getPropertyValue() 和 setPropertyValue() 增加讀取屬性值和寫入結果代碼,結構如下(以前者為例):

public Object getPropertyValue(Object id) {
    if (PROP_NAME.equals(id))
        return getName();
    if (PROP_VISIBLE.equals(id))
        return isVisible() ? new Integer(0) : new Integer(1);
    return null;
}

根據屬性名做不同操作。注意:下拉框類型編輯器以 Integer 類型數據代表選中項序號,而非 int 或 String,如上代碼根據 visible 屬性返回第零項或第一項,否則會出現 ClassCastException。

圖2 屬性頁

實現大綱視圖

在 Eclipse 中,編輯器被激活時,大綱視圖自動通過編輯器 getAdapter() 尋找其提供的大綱(大綱實現 IContentOutlinePage 介面)。GEF 提供 ContentOutlinePage 類實現大綱視圖,需實現其子類,重點實現 createControl() 方法。ContentOutlinePage 是 org.eclipse.ui.part.Page 子類,大綱視圖是 PageBookView 子類,其中有 PageBook 包含多個 Page 並可切換,切換依據為當前活動的 Editor。故在 createControl() 中構造此 Page,簡化代碼如下:

private Control outline;
public OutlinePage() {
    super(new TreeViewer());
}
public void createControl(Composite parent) {
    outline = getViewer().createControl(parent);
    getSelectionSynchronizer().addViewer(getViewer());
    getViewer().setEditDomain(getEditDomain());
    getViewer().setEditPartFactory(new TreePartFactory());
    getViewer().setContents(getDiagram());
}

因構造方法指定使用樹結構顯示大綱,createControl() 第一句使 outline 變量得到 Tree(見 org.eclipse.gef.ui.parts.TreeViewer 代碼),第二句把 TreeViewer 加到選擇同步器,讓用戶不論在大綱或編輯區選擇 EditPart 時,另一方自動做同樣選擇;最後三行把大綱視圖模型與編輯區模型關聯,體會 MVC 好處。

實現大綱視圖最重要工作基本是這些,但未完:需在 init() 綁定 UNDO/REDO/DELETE 等命令到 Eclipse 主窗口,否則大綱視圖活動時主工具條這些命令會變不可用;getControl() 返回 outline 成員變量(指定讓此控件出現在大綱視圖);dispose() 應把 TreeViewer 從選擇同步器移除;最後,必須在 PracticeEditor 覆寫 getAdapter(),此方法在 Editor 激活時被大綱視圖調用,必須返回實現好的 OutlinePage:

public Object getAdapter(Class type) {
    if (type == IContentOutlinePage.class)
        return new OutlinePage();
    return super.getAdapter(type);
}

樹型大綱視圖完成(見下圖)。許多 GEF 應用同時具有樹型和縮略圖兩種大綱,實現思路相同但代碼稍複雜,因需通過 PageBook 切換,縮略圖一般由 org.eclipse.draw2d.parts.ScrollableThumbnail 實現,暫不講(或許後續詳細說),可看 logic 例子的 LogicEditor 代碼了解。

圖3 大綱視圖

寫此文時對例子做了些修改,皆與本文內容相關,若之前下載過會發現代碼略有不同(功能完全一樣)。另外說明,例子不完善:如刪除節點時其連接未同時刪除,一些鍵盤快捷鍵不工作,存在很多被註釋掉的代碼等。有興趣可來修改,也是不錯學習途徑。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved