員的程式設計,mfc只是提供了乙個程式設計框架,應用的實質性**還是必須由程式設計師自己來寫。同時,mfc的問題也是顯而易見的,那就是其gui素材太豐富,以至於程式設計師們過分依賴mfc,當想要實現mfc中沒有的gui特性時便不知所措。對於如何實現資料夾式樣的標籤控制介面,有人可能想到了從現成的標籤控制項tabcontrol入手,但是經驗證明:如果自己建立乙個視窗類,能夠讓你完全控制**的修改,不必顧及因現有控制項版本的變化而對自己的**造成的巨大影響和麻煩,微軟的開發人員肯定也是這麼做,如果用spy++檢視一下excel和visual c++的介面,你就會發現其資料夾式樣的標籤控制並不是tabcontrol,而是另外建立的視窗類。本例項通過定義乙個cfoldertabctrl實現了我們所要的介面功能。程式執行後的介面效果如圖一所示:
圖一、類似
excel的資料夾式樣的標籤
一、實現方法
有關cfoldertabctrl的實現細節請參考源**。其標頭檔案為ftab.h,實現檔案為ftab.cpp。在分析cfoldertabctrl的實現原理之前,讓我先來說明一下這個類的使用方法。當fldrtab程式的initinstance()函式獲得控制權時,它建立乙個主對話方塊的例項cmydialog dlg;,並執行這個對話方塊。cmydialog有兩個控制:乙個是m_wndstaticinfo,另乙個是m_wndfoldertab,顧名思義,第乙個控制為乙個靜態文字視窗,它顯示選中的標籤,第二個是
標籤控制本身,即cfoldertabctrl例項。通過在cmydialog::oninitdialog()函式中呼叫subclassdlgitem()函式,對話方塊以常規方式子類化靜態文字,遺憾的是它不能子類化
標籤控制,因為對話方塊中並沒有實際的
標籤控制視窗。在ondialoginit()函式中通過呼叫乙個特殊的函式m_wndfoldertab.createfromstatic(idc_foldertab, this),在程式執行時將靜態文字替換成
標籤控制。
cfoldertabctrl::createfromstatic()函式不僅在靜態文字控制項的位置上建立乙個
標籤控制,它還負責刪除靜態文字控制項。在呼叫create()函式之前,createfromstatic()呼叫cfoldertab::getdesiredheight()來獲得控制的高度,而忽略靜態文字控制項的高度。在非對話方塊應用中不能呼叫createfromstatic();而是要直接呼叫cfoldertab::create()。建立了
標籤控制後,接下來必須設定標籤名字。這裡是在cmydialog中呼叫m_wndfoldertab.load(idr_foldertabs) 函式來裝載字串資源。其中 idr_foldertabs是字串資源的id,它是乙個包含新行指示符("n")分割的標籤名。
僅僅通過上述處理cfoldertabctrl類還不能做任何事情,你還必須處理它的通知訊息,當使用者按下乙個標籤時,cfoldertabctrl便用特殊**ftn_tabchanged向對話方塊傳送乙個wm_notify訊息。然後對話方塊處理這條訊息,也就是在上面的靜態文字控制項中顯示一條資訊:
nmfoldertab結構在ftab.h檔案中定義:
struct nmfoldertab:public nmhdr ;
這個結構除了nmhdr所包含的成員之外,還有專案索引和指向當前標籤cfoldertab的指標,它與cfoldertabctrl有所不同,從cfoldertab中你可以得到標籤的文字。以上就是cfoldertabctrl的使用方法。
下面我們就來揭示這個c++類的實現原理。前面已經對createfromstatic()進行了描述,那麼cfoldertabctrl::load是個什麼樣的函式呢,這個函式的功能是載入乙個串標籤名,這個串是用新行指示符("n")分割的字串,吸取其中的子串,並呼叫cfoldertabctrl::additem()將它新增到每乙個標籤上:
int cfoldertabctrl::additem(lpctstr lpsztext)
就這麼簡單,建立乙個新的cfoldertab物件並將它新增到乙個列表中。與additem()相對的是removeitem()函式,它們的實現都在ftab.cpp檔案中,這兩個函式分別負責動態新增和刪除標籤頁,而不是訪問資源串。然後是getitem()和getitemcount()函式,一看它們的名字你就應該明白它們的作用,前者用來獲取cfoldertab標籤的索引號(從0開始),後者則返回m_lstabs.getcount,即總共有多少標籤。此外,還需要有個函式來獲取和設定標籤文字,沒問題,每乙個cfoldertab物件都有乙個m_stext成員變數來儲存標籤名,訪問方法是gettext()和settext()。
接下來要做的事情很重要,首先是繪製標籤,cfoldertabctrl::onpaint()函式在迴圈中遍歷所有標籤,對每乙個標籤呼叫cfoldertab::draw()函式來進行繪製處理。這裡有兩個技巧:乙個是必須在最後繪製當前選中的標籤(m_icuritem),以便它看起來重疊在最上面。另乙個是要繪製其它標籤,必須讓每個標籤知道自己的位置--也就是定義標籤的梯形座標。這是此
標籤控制的重點所在。下面就來看看實際**是怎麼做的。
cfoldertabctrl有乙個recomputelayout()函式,它計算所有標籤的位置。只要你改變控制的版面,則必須呼叫它,如新增或刪除某個標籤以及修改某個標籤的名字(它會影響標籤大小)等操作。recomputelayout()函式的關鍵**如下:
int x = 0;
for (int i=0; icomputergn(dc, x) - cxoffset;}
recomputelayout()為每乙個標籤呼叫cfoldertab類的成員函式computergn()。computergn()計算出標籤的梯形大小並返回算出的寬度,recomputelayout()將它與當前x軸座標相加,然後作為下乙個標籤的起始x軸座標進行引數傳遞,最後減去形狀修飾因子cxoffset,使得它們看起來有重疊的效果。之所以這麼做是因為給定的標籤只能決定其大小,不能決定其絕對位置,它需要更多的x軸資訊。 一旦computergn()有了x軸座標,它就可以計算出乙個足夠大的梯形來容納標籤文字,注意要加一些邊空,使文字的顯示不會產生混亂。用dt_calcrect 呼叫cdc::drawtext()來計算文字所佔的矩形,然後用結果計算梯形的大小。私有函式gettrapezoid()計算與文字矩形相配的梯形。當cfoldertab::computergn()計算出梯形的座標,它呼叫crgn::createpolygonrgn函式強行建立乙個多邊形區域。}
當標籤的區域確定後,cfoldertab::draw()函式對選中標籤(選中和未選中狀態)要顯示的顏色和字型進行處理。因為標籤將梯形資料儲存在crgn物件中,因此只要呼叫cdc::fillrgn即可繪製標籤。然後用moveto() 和lineto()以適當的顏色繪製線條。最後呼叫drawtext繪製文字。注意線條有的是黑色,有的是灰色以便呈現3d效果,選中標籤為白色(color_window)並且頂邊沒有黑色邊線。這樣做便於與上面的視窗融於一體。為了簡單起見,例子程式沒有建立這樣的視窗,但是在實際應用中,一般都會象
excel和visual studio那樣有乙個甚至多個視窗與每個選中的標籤對應,這在例項二中會慢慢擴充。
例子程式裡選中標籤的另外乙個特點是使用了小字型,這是從visual studio借鑑過來。說到字型,到底應該使用哪一種呢?這裡cfoldertabctrl預設為arial,你完全可以改用其它的字型,為此cfoldertabctrl類中提供了乙個改變字型的成員函式 cfoldertabctrl::setfonts()。
以上討論的都是標籤的繪製問題,下面來看看事件及行為。有關標籤區域計算的重點和難點問題都已經解決,剩下的問題就簡單多了。當cfoldertabctrl獲悉onlbuttondown事件,它呼叫函式hittest()找出滑鼠位於哪乙個標籤上,hittest()函式在每乙個cfoldertab物件上迴圈,呼叫cfoldertab的同名函式cfoldertab::hittest,這個函式再用已經計算好的的梯形座標呼叫crgn::ptinregion()。crgn必須在這裡做好自己的工作。如果hittest()函式返回true,則cfoldertabctrl::hittest()函式返回標籤的索引,此時onlbuttondown呼叫的另乙個函式是cfoldertabctrl::selectitem(),以此選中標籤。selectitem()沒有什麼玄機,它將新的值賦給m_icuritem並使的值失效,選中新標籤後重畫。完成selectitem()函式的呼叫後,onlbuttondown建立乙個nmfoldertab結構並將資訊填寫到結構,然後向父視窗傳送wm_notify訊息。對話方塊和主應用就是這樣把握著所發生的一切。
二、程式設計步驟
1、 啟動visual c++6.0,生成乙個基於對話方塊的應用程式,將該程式命名為"fldrtab;
2、 在程式的對話方塊模板中新增兩個靜態控制項,id分別定義為idc_staticinfo 、idc_foldertab;
3、 在程式中定義cfoldertabctrl、cfoldertab類和結構struct nmfoldertab;
4、 在程式中定義訊息ftn_tabchanged;
5、 新增**,編譯執行程式。
vc 遞迴拷貝資料夾
自己用vc寫的乙個拷貝資料夾函式 2008 4 16 18 19 42 前兩天,在專案中遇到乙個需要從乙個伺服器上拷貝檔案到另一台機子的問題。開始考慮使用shfileoperation,在本機上試過感覺還不錯,能考過去,但是這個函式把整個資料夾都copy過去了。當我想要從伺服器上在根目錄上建的共享目...
VC遍歷資料夾下所有檔案和資料夾
2010 03 25 16 59 一 先介紹乙個結構win32 find data typedef struct win32 find data win32 find data win32 find data ffd handle hfind findfirstfile c ffd 二 函式find...
VC遍歷資料夾下所有檔案和資料夾
一 先介紹乙個結構win32 find data typedef struct win32 find data win32 find data 可以通過 findfirstfile 函式,根據檔案路徑把待操作檔案的相關屬性讀取到 win32 find data 結構中去 win32 find dat...