深入了解CCtrlView

2021-06-06 10:46:52 字數 3364 閱讀 1585

如果我們要將乙個控制項轉換成檢視類,我們一般會想到cctrlview,用它實現的控制項檢視一般新增乙個get***ctrl函式,函式的作用是返回檢視中控制項的引用,如果在mfc程式中跟蹤它的呼叫我們會發現它的實現是這樣的(以cedit控制項為例)

_afxext_inline   cedit&   ceditview::geteditctrl()   const

這個轉換讓人覺得很疑惑,因為cedit和ceditview是來自兩條不同繼承鏈上的類,一般來說這樣的轉換是要出問題的,但是為什麼可以進行這種轉換?msdn上有一篇文章對這種轉換做了比較深入的解釋,下面把這篇文章翻出來給大家看看。

問題:

我設計了乙個從cwnd派生而來的自定義控制項,現在我想把它當成檢視來使用。我想到的的第乙個辦法是把控制項嵌入到檢視中然後操控檢視中的onsize函式以使控制項覆蓋客戶區。但問題是傳給控制項的滑鼠訊息無法在檢視中過載。而傳給檢視的擊鍵訊息必須手動傳遞給控制項。我了解到cctrlview可以作為公用控制項的基類。於是我試圖圍繞著它設計檢視(我記得你在msj的某一期上討論了這個問題),但是我無法讓它與我自定義的 cwnd派生控制項類一起工作。請問這樣做可以嗎?應該怎樣做?

mateo anderson(回答者)

回答:

cctrlview是乙個mfc將控制項類轉換為檢視類的技巧。比如從ctreectrl轉換成ctreeview或者從clistctrl轉換成clistview。在cctrlview的文 檔注釋中提到:「cctrlview幾乎允許把任何控制項轉換成檢視。」。不幸的是,說「幾乎」稍微有些誇大其詞了,除非作者所說的「任何控制項」只是關於像 cedit和ctreectrl這樣的windows內建控制項。cctrlview用了乙個只能在特定環境下工作的技巧。要理解cctrlview如何工作,首先讓我們看看ctreeview,ctreeview派生於cctrlview。其中有三個重要的函式需要考慮:建構函式,precreatewindow函式和gettreectrl函式。建構函式告訴cctrlview要建立哪種windows控制項。

ctreeview::ctreeview() :

cctrlview(wc_treeview, dwstyle)

在這個例子中,wc_treeview(在commctrl.h中定義)是樹型控制項類的類名,也就是「systreeview32」。cctrlview會將此類名儲存在乙個資料成員中稍後使用:

cctrlview::cctrlview(lpctstr lpszclass,

dword dwstyle)

下乙個起作用的函式是precreatewindows,這是乙個ctreectrl從cctrlview繼承來的函式。cctrlview::precreatewindow在視窗剛好建立完成之前使用m_strclass在createstruct種設定類名。

// cctrlview uses stored class name

bool cctrlview::precreatewindow(createstruct& cs)

現在建立的視窗就是使用所期望的類建立的了-在這個例子中就是systreeview32。到目前為止,一切都很好。但是如果ctreectrl派生於 cctrlview,而cctrlview又派生於cview,那麼它為什麼能又派生於ctreectrl?難道是mfc類封裝了樹型控制項?ctreeview和ctreectrl是完全獨 立的,有著不同的繼承鏈。ctreectrl直接派生於cwnd,而ctreeview派生於cctrlview/cview。這就是技巧發生作用的地方了。要讓樹型檢視像樹 型控制項一樣操控,cctreeview提供了特殊的函式gettreectrl來獲得樹型控制項。

ctreectrl& ctreeview::gettreectrl() const

gettreectrl只是簡單的將ctreeview轉換為ctreectrl。但是等等-怎麼會發生這麼詭異的事?這兩個類完全不同,有著不同的資料成員和虛函式 表-你根本無法將乙個轉換成另乙個同時還指望著能夠正常工作!答案就是:ctreectrl沒有虛函式也沒有資料成員。你可以把它稱為乙個純包裝類。 ctreectrl不對它的基類cwnd新增任何東西(不新增資料成員也不新增虛函式),所有新增的內容只是一些包裝函式,一些將訊息傳送給內在hwnd 的有形函式。

htreeitem ctreectrl::insertitem(...)

insertitem訪問的唯一資料成員是m_hwnd,所有的cwnd派生類都有該成員。insertitem和所有其它的包裝函式只是將它們的引數傳遞給了內在的 hwnd,將c++風格的成員函式轉換成windows風格的sendmessage呼叫。物件本身(「this」指標)可以是任何cwnd派生類的例項,只要m_hwnd處於 正確的位置(也即是類的第乙個資料成員),並且hwnd(實際上就是如此)是乙個樹型控制項的控制代碼。相同的原因發生在下面的寫法中:

pedit = (cedit*)getdlgitem(id_foo);

即便在這裡getdlgitem返回的是乙個指向cwnd的指標,不是cedit。但是這樣是允許的,因為cedit也是乙個包裝類,而且對於它從cwnd繼承來的內容沒有新增額外的資料和虛函式。 所以注釋中「cctrlview幾乎允許將任何控制項轉換為檢視」的說法中所說的「幾乎任何」意思是特指對cwnd沒有新增資料成員和虛函式的這些控制項,也就是我所說的「純包裝類。」如果你的控制項類有它自己的資料或虛函式,你無法使用cctrlview,因為在cctrlview/cview中不存在這些額外的資料成員和虛函式。

舉例來說,cview中的第乙個虛函式是cview::isselected。如果你的控制項類有其它虛函式,在你把 cctrlview類轉換成你的cfooctrl類呼叫那個虛函式的時候就肯定會爆發問題了,因為這個函式根本不存在。類似的,cview中的第乙個資料成員是m_pdocument。如果你的控制項類需要一些其它的資料成員,那你在訪問它們的時候就要倒霉了,因為物件事實上呼叫的是cctrlview,而不是cfooctrl。多麼糟糕,多麼令人沮喪。

簡而言之,唯一可以使用cctrlview技巧的時候是cwnd派生控制項類沒有它自己的虛函式和資料成員之時。這就是生活。

看到這裡,大家應該就很明白了,這裡的轉換有乙個與普通類型別之間的轉換有乙個重要區別,控制項類中沒有虛函式和新的資料成員,因此控制項類具有和cwnd一樣的虛函式表和資料擺放,所謂將ceditview轉換成cedit控制項,實際cedit控制項物件只會呼叫ceditview中cwnd那部分的成員,因而這種呼叫是可行的。

深入了解A

一 前言 在這裡我將對a 演算法的實際應用進行一定的 並且舉乙個有關a 演算法在最短路徑搜尋的例子。值得注意的是這裡並不對a 的基本的概念作介紹,如果你還對a 演算法不清楚的話,請看姊妹篇 初識a 演算法 這裡所舉的例子是參考amit主頁中的乙個源程式,使用這個源程式時,應該遵守一定的公約。二 a ...

深入了解A

一 前言 在這裡我將對a 演算法的實際應用進行一定的 並且舉乙個有關a 演算法在最短路徑搜尋的例子。值得注意的是這裡並不對a 的基本的概念作介紹,如果你還對a 演算法不清楚的話,請看姊妹篇 初識a 演算法 這裡所舉的例子是參考amit主頁中的乙個源程式,使用這個源程式時,應該遵守一定的公約。二 a ...

深入了解Dojo Data

譯自http www.sitepen.com blog 2010 10 13 dive into dojo data 使用dojo data有助於快速建立web應用的介面,且易於嵌入各種資料來源。它在使用者介面與底層資料之間提供了一層抽象層,使得使用者介面開發人員能夠專注於ui的開發,而無需擔心資料...