GEF 高階,第四部分 Locator

2021-06-12 10:16:49 字數 4430 閱讀 7703

簡介:本文是gef高階的第四部分,主要描述了locator的概念和使用方法。locator是 乙個圖形定位器,用來動態的決定某個圖形相對於另外乙個圖形的位置,因此可以用來構造一些 複雜的圖形或者實現一些比較有趣的功能。由於eclipse 3.3已經發布,本文的示例**是在 eclipse 3.3, gef 3.3執行除錯的。

本文是gef高階的第四部分,主要描述了locator的概念和使用方法。locator是乙個圖形定 位器,用來動態的決定某個圖形相對於另外乙個圖形的位置,因此可以用來構造一些複雜的圖形或者 實現一些比較有趣的功能。由於eclipse 3.3已經發布,本文的示例**是在eclipse 3.3, gef 3.3 執行除錯的。

locator

locator,顧名思義,是乙個定位器。我們先來看看這個介面:

public inte***ce locator
這個介面非常簡單,只有乙個方法,引數是乙個ifigure,所以首先可以明確的是:locator是乙個 圖形定位器。那麼乙個locator用在什麼地方,又為什麼要用locator呢?一般來講,如果你希望乙個圖形 能跟著另外乙個圖形移動,那麼locator就很有用了。因此locator是相對定位的有利工具。我們下面來介 紹locator的幾個典型應用。

connection label

我們在執行gef shapes的例子時,可以看到圖形之間可以有連線,但是連線上沒有文字說明,如果有 文字說明的話,會有如下圖所示的效果:

看到連線上有了乙個「label」的字樣,你可以把它叫做connection label(連線標籤)。總之, 這個標籤是附著在連線上的。不光如此,如果你拖動連線,這個標籤也會跟著移動,這就是locator 的功勞。我們先來修改shapes例子的**,給連線加上這樣的標籤。要修改的地方在connectioneditpart 的createfigure方法裡,修改後如下所示:

清單2. 為連線加上label

protected ifigure createfigure()
加這麼乙個label確實很簡單,我們先建立乙個label物件,再將它加到連線裡面,所以本質上label是連線的 乙個孩子。在新增的時候,我們使用了midpointlocator, 這是gef預設帶的乙個locator,作用是把圖形定位 到連線的中點。所以我們看到label的中點始終和連線的中點相同。而連線的中點又叫做midpointlocator的 reference point(參考點), 我們在本系列的第一部分裡面介紹過anchor(錨點),這個參考點的概念與其是類似的。

隨之而來我們會發現乙個侷限性:這個label永遠只能在連線的中心,無法移動到其它的地方。在有些時候這 確實是個問題:比如某個圖特別複雜,連線特別多,以致於連線上的標籤都重疊在了一起,可是由於它不能拖動,所 以看上去很不美觀。如果我們希望這個label能被拖動該怎麼辦呢?有兩個方案:

為這個label建立乙個editpart,負責控制這個label的移動,改變大小,等等。

使用乙個自定義的locator,並處理label的滑鼠事件,隨時重新整理它的位置

第一種方法需要的**稍多且不符合本文主題。我們來看看第二種方法該如何實施。

確定locator的策略

首要的問題是我們的locator如何工作呢?我們已經使用了midpointlocator,它可以隨時定位到連線的中點, 如果我們給它加乙個偏移,不就可以實現拖動到任何位置的功能了嗎?這個概念如圖2所示:

策略定下來之後我們來實現乙個midpointoffsetlocator,它直接繼承自midpointlocator,但是我們給它添 加乙個offset的成員變數,這樣我們就可以控制標籤中點的位置了。**如下所示:

清單3. midpointoffsetlocator的實現

public class midpointoffsetlocator extends midpointlocator 

@override

protected point getreferencepoint()

public point getoffset()

public void setoffset(point offset)

}

關鍵的方法在於我們覆蓋了getreferencepoint(),讓它返回之前加上我們的偏移量。就這麼簡單,我們自己的locator誕生了!

處理滑鼠事件

locator有了,下面的問題就是如何才能在適當的時機修改這個偏移量呢?第一想到的就是滑鼠事件***。由於figure本身 已經支援新增各種各樣的***,所以這一步也非常簡單。我們繼續修改connectioneditpart的createfigure方法,給我們的label 加上滑鼠事件處理方法,如下所示:

清單4. 新增滑鼠事件***

protected ifigure createfigure() 

public void mousepressed(mouseevent me)

public void mousereleased(mouseevent me)

});label.addmousemotionlistener(new mousemotionlistener()

me.consume();

}// 省略其它無關**

......

});return connection;

}

要注意的有三點,第一我把midpointlocator替換成了我們自己的locator,第二我在connectioneditpart加了四個成員變數(dx, dy, anchorx, anchory)來跟蹤滑鼠位置,第三我在滑鼠拖動事件中修改偏移量並重新整理它,但是為了安全起見,我先判斷了constraint型別。

小節總結

我們現在完成了label的拖動功能,不過你可以發現一些可以繼續提高的地方,最明顯的莫過於label的位置不能儲存。我們應該把這個偏移量儲存到connection模型中去。這個問題和本文無關,留給讀者做個練習。本小節的示例**在org.eclipse.gef.examples.shapes_locator_step1.zip中,大家可以看看實際的效果。

handle

locator另乙個典型的應用是用在handle中,所謂handle,就是你選擇乙個圖形之後,在它的邊框周圍出現的一些輔助性的圖形,比如一些小方塊。如下圖所示:

因為handle也使用了locator,所以我們在拖**形的時候,handle的位置也會隨之更新。回頭看看上一小節中的label,可以發現乙個美中不足的是:label的周圍沒有handle,這樣的話使用者可能會不知道我們的label是可以拖動的,對使用者不太直觀,如果能在連線被選擇的時候把label的周圍也加上handle,那麼使用者可以容易的發現這個label原來也支援拖動,這有利於提高使用者友好度。本小節的例子就來實現這個功能。

myconnectionendpointeditpolicy

追究handle的發源地,會發現連線上的handle是在connectionendpointeditpolicy中建立的, 我們要新增handle,自然就是要實現乙個自己的editpolicy了。關於editpolicy的相關概念,這裡不做贅述。觀察connectionendpointeditpolicy的實現,可以看到乙個有趣的方法createselectionhandles,那麼我們來覆蓋它,如下:

清單5. 為label新增handle

public class myconnectionendpointeditpolicy extends	connectionendpointeditpolicy 

return handles;}}

我們遍歷了連線的所有孩子,如果它是乙個label,就為它建立乙個movehandle,movehandle使用了movehandlelocator,這些類都是gef自帶的,不需要費什麼功夫。

有了自定義的editpolicy,別忘了在connectioneditpart中替換原來的editpolicy,這部分**過於簡單,省略不提。

修改label上的滑鼠事件處理**

到這裡為止,我們的label就有了handle了,如下圖所示:

小節總結

回頁首

結束語gef中的幾乎一切東西都可以定製,本文介紹的是locator的定製,locator是相對布局的關鍵介面。靈活使用locator,可以實現一些很有趣的功能。

第四部分 方法3

對employee.calculatepay方法的呼叫是問題的原因。我們需要的是晚繫結。晚繫結 latebinging 意味著編譯器到執行時才選擇要執行的方法。為了迫使編譯器呼叫向上型別轉換得到的物件的方法的正確版本。我們使用了兩個關鍵字 virtual 和override.必須在基類方法中使用vi...

第四部分 方法5

linux繼承了unix作業系統結構清晰的特點。在linux下的檔案結構非常有條理。但是,上述的優點只有在對linux相當熟悉時,才能體會到。vmlinuz 我們已經知道,每乙個linux都有乙個核心 vmlinuz 我們在這個核心上新增上可以完成各種特定功能的模組,每個模組就體現在 linux中各...

JavaScript筆記(第四部分)

命 名 空 間 管理變數,防止汙染全域性,適用於模組開發 之 前 的 解 決 辦 方 已經不用 命名空間 var org xuming department2 lisi 了解即可 用 法 org.department1.jicheng.name 簡化 var jc org.department1.j...