




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、mfc樹控件實現(xiàn)目錄樹瀏覽由一個全封閉的派生目錄樹類實現(xiàn)這個例程是由vc+ ctreectrl控件派生的完整目錄樹類,可以瀏覽本地pc的目錄樹。vs2008下經(jīng)作者試驗,結(jié)果準(zhǔn)確,反應(yīng)迅速。 本例程由一個cdirtreectrl類(dirtreectrl.h, dirtreectrl.cpp)和一個對話框(作為test bench)構(gòu)成。 本例使用網(wǎng)上下載的源碼,消除原有的bugs,使程序可以正確流暢地運行;簡化并明確功能和目的,刪除冗余代碼,改進結(jié)構(gòu),使代碼結(jié)構(gòu)簡練清晰易懂,并且在代碼中作者做了詳細的注解,主要目的是為本作者自己以后可以迅速查閱,順便也就適應(yīng)不同level的編程朋友閱讀交流;
2、提升了反應(yīng)速度和改進結(jié)構(gòu)和消息機制。本例程較源碼增加和改進的方面如下:1 以往的ctreectrl控件構(gòu)造的目錄樹,都是把鼠標(biāo)消息和樹消息的處理放在父窗口中,這樣破壞了封閉性,不利于代碼的重復(fù)利用, 本例程構(gòu)造目錄樹派生類,最后的實現(xiàn)目錄樹類的完全封閉。( 這個主意最先來自源碼例程,那個作者已經(jīng)構(gòu)造了派生類cdirtreectrl,但是很遺憾,他沒有實現(xiàn)目錄樹的類的封閉,他只是假期作業(yè),沒時間了,他最后還是在父窗口類中處理消息。 本例程非常自然地利用了mfc反射功能,完美實現(xiàn)了這一個構(gòu)想。 )2 網(wǎng)上的例程都以鼠標(biāo)左鍵的onclick處理來定位鼠標(biāo)位置,根據(jù)鼠標(biāo)位置由hittest來確定鼠標(biāo)點
3、擊項。這樣做每當(dāng)鼠標(biāo)點擊控件,即使沒有點擊目錄項,都會調(diào)用處理函數(shù),效率很受影響; 而且,目錄樹上每一個item有button,label, icon等多個子項,hittest后的uflag的值不相同,點擊時位置需要限定在button,label, icon這三個子項上才能有反應(yīng),其余位置要忽略。 (這種處理方法本例程有試驗,被注釋掉,恢復(fù)一下即可試驗。) 試驗很多可以利用的消息的結(jié)果表明,最好是利用 =tvn_itemexpanding 反射消息,添加ontvnitemexpanding(nmhdr *pnmhdr, lresult *presult),從pnmhdr中得到被選中的item的
4、句柄(htreeitem hitem = pnmtreeview->itemnew;),操作時系統(tǒng)已經(jīng)肯定知道選中的目錄項,處理只需只針對這個句柄,形式及其簡單明了,并且效率提高。3如果初始化利用遞歸時把全部硬盤的目錄全部建好并加入目錄樹,耗時很大。本人200g硬盤,安裝程序較多,測試結(jié)果運行時間約30分鐘。因此這種把全部目錄加入的方法行不通,必須在目錄樹展開的瞬間,僅僅把該目錄內(nèi)下一級子目錄的項全部添加到樹上,這個見解也是網(wǎng)上很多朋友認同的。但是在使用中,會發(fā)現(xiàn),下一級的子目錄中即使有子項,前面的button上也沒有+號,但是你展開后再合上,再展開會有+號的。為避免這個問題, 我的方法
5、是在鼠標(biāo)選中任意一個子項時,首先刪除該子項下所有的子目錄項,然后不僅僅加入該子項的所有子目錄,還要把子目錄中有子目錄的項子目錄也加入。這樣就會避免有子目錄項+號沒有的問題。2013/10/2于國慶長假 dirtreectrl.h 頭文件#pragma once/ cdirtreectrlclass cdirtreectrl : public ctreectrldeclare_dynamic(cdirtreectrl)/dataprivate:bool addsubdirasitem(htreeitem hparent);bool addsubdirasitem1(htreeitem hpare
6、nt);bool findsubdir(lpctstr strpath);cstring getfullpath(htreeitem hitem);bool displaydrives();bool attachimglist();htreeitem additem( htreeitem hparent, lpctstr strname );cstring m_strerror; cimagelist m_imglist;htreeitem m_hdirtreeroot;dword m_treestyle;public:cdirtreectrl();void setdirtreestyle()
7、;bool displaytree(lpctstr strroot);virtual cdirtreectrl();/ generated message map functionsprotected:/afx_msg(cdirtreectrl)/ note - the classwizard will add and remove member functions here./afx_msgdeclare_message_map()public:/afx_msg void onnmclick(nmhdr *pnmhdr, lresult *presult); / 用這個作為鼠標(biāo)消息響應(yīng)也可以
8、,但是下面的一個更好afx_msg void ontvnitemexpanding(nmhdr *pnmhdr, lresult *presult);dirtreectrl.cpp#include "stdafx.h"#include "test_dir_tree.h"#include "dirtreectrl.h"/ cdirtreectrlimplement_dynamic(cdirtreectrl, ctreectrl)/ cdirtreectrl message handlerscdirtreectrl:cdirtreectr
9、l()cdirtreectrl:cdirtreectrl() m_imglist.detach();begin_message_map(cdirtreectrl, ctreectrl) /afx_msg_map(cdirtreectrl) / note - the classwizard will add and remove mapping macros here. /afx_msg_map/on_notify_reflect(nm_click, &cdirtreectrl:onnmclick)on_notify_reflect(tvn_itemexpanding, &cdi
10、rtreectrl:ontvnitemexpanding)end_message_map()/ cdirtreectrl message handlers/程序調(diào)用的接口,顯示一棵目錄樹,/strroot為根目錄路徑bool cdirtreectrl:displaytree(lpctstr strroot) setitemheight(20); settextcolor(rgb(0x0,0x0,0xff); deleteallitems(); setdirtreestyle(); if ( !attachimglist() ) return false; displaydrives(); re
11、turn true;/設(shè)置目錄樹屬性void cdirtreectrl:setdirtreestyle() dword dwstyle = getwindowlong(m_hwnd, gwl_style ); dwstyle |= tvs_hasbuttons | tvs_haslines | tvs_linesatroot | /*tvs_checkboxes |*/ ws_border | ws_tabstop ; m_treestyle = dwstyle; setwindowlong(m_hwnd, gwl_style, dwstyle );/獲取系統(tǒng)圖標(biāo)bool cdirtreect
12、rl:attachimglist() shfileinfo shfinfo; himagelist himglist = null; if ( getimagelist( tvsil_normal ) ) m_imglist.detach(); himglist = (himagelist)shgetfileinfow(_t("c:"), 0, &shfinfo, sizeof( shfinfo ), shgfi_sysiconindex | shgfi_smallicon ); if ( !himglist ) m_strerror = _t("無法得到
13、系統(tǒng)圖標(biāo)文件!"); return false; m_imglist.m_himagelist = himglist; setimagelist( &m_imglist, tvsil_normal ); return true; /顯示系統(tǒng)盤符bool cdirtreectrl:displaydrives() deleteallitems(); tchar szdrives260; tchar* pdrive=null; if ( !getlogicaldrivestrings( sizeof(szdrives), szdrives ) ) m_strerror =_t(&q
14、uot;驅(qū)動信息獲取失??!"); return false; pdrive = szdrives; /szdrives 中的字符串格式:_t("c:0d:0d:0e:0") m_hdirtreeroot = insertitem(_t("計算機"),15,25);/15 和是計算機的兩個圖標(biāo),前一個是沒選中時的,后一個是選中時的/cstringarray strdrives;/cstring strdrive;/while( *pdrive!=0 )/strdrives.add(pdrive);/pdrive += _tcslen( pdriv
15、e ) + 1;/for (int n=0; n<strdrives.getcount(); n+)/strdrive=strdrives.getat(n);/strdrive.setat(strdrive.getlength()-1,_t('0'); /試驗表明:uincode 的"0"字符同樣適用!/htreeitem hparent = additem( m_hdirtreeroot,strdrive );/if ( findsubdir( strdrive ) insertitem(_t("dummy"),0,0,hpare
16、nt);/ 去掉盤符后的"",下面的思路經(jīng)驗證也可行,而且更加簡練int len;while( *pdrive!=0 )len = _tcslen(pdrive);pdrivelen-1 = _t('0');htreeitem hparent = additem( m_hdirtreeroot, pdrive );if ( findsubdir( pdrive ) addsubdirasitem(hparent); / 一個技巧先加入下一級子目錄項,/ 然后再點擊該項后,首先去掉所有子項,然后再加入,/ 這樣的好處是在前面路徑的方框中會有一個+號,/ 因為如
17、果把全部的目錄一次加入,大約需要半個小時時間,所以采取點擊時先去掉所有項,然后再增加子目錄pdrive += len + 1; expand( m_hdirtreeroot, tve_expand ); return true;/是否有子目錄可展開bool cdirtreectrl:findsubdir(lpctstr strpath) cfilefind find; cstring strtemp = strpath; bool bfind; if ( strtemp.right(1) = _t('') ) strtemp += _t("*.*"); el
18、se strtemp += _t("*.*"); bfind = find.findfile( strtemp ); while ( bfind ) bfind = find.findnextfile(); if ( find.isdirectory() && !find.isdots() ) return true; if ( !find.isdirectory()/* && m_bshowfiles*/ ) return true; return false;/獲取全目錄cstring cdirtreectrl:getfullpath(h
19、treeitem hitem) cstring strreturn; cstring strtemp; htreeitem hparent = hitem; strreturn = "" while ( hparent ) strtemp = getitemtext( hparent ); if(strtemp != _t("計算機")if ( strtemp.right(1) != _t("") ) strtemp += _t(""); strreturn = strtemp + strreturn; hpare
20、nt = getparentitem( hparent ); return strreturn;/ 需要在此節(jié)點上,加入它的整個子目錄和下一級的子目錄,作為迭代加入bool cdirtreectrl:addsubdirasitem(htreeitem hparent)cstring strpath,strfilename;htreeitem hchild;/-去除該父項下所有的子項-/ 因為有dummy項,并且有時子目錄再次打開,或子目錄會刷新等,因此必須去除。while ( itemhaschildren(hparent)hchild = getchilditem(hparent); del
21、eteitem( hchild );/-裝入該父項下所有子項-strpath = getfullpath(hparent); / 從本節(jié)點開始到根的路徑cstring strsearchcmd = strpath;if( strsearchcmd.right( 1 ) != _t( "" ) strsearchcmd += _t( "" );strsearchcmd += _t( "*.*" );cfilefind find;bool bcontinue = find.findfile( strsearchcmd );while (
22、bcontinue )bcontinue = find.findnextfile();strfilename = find.getfilename();if ( !find.ishidden() && ! find.isdots() && find.isdirectory() )hchild = additem( hparent, strfilename );if ( findsubdir( getfullpath(hchild) ) addsubdirasitem1(hchild); / 一個技巧:先加入下一級子目錄項,/ 然后再點擊該項后,再先去掉所有子項,
23、然后再加入,/ 這樣的好處是在前面路徑的方框中會有一個+號,/ 因為如果把全部的目錄一次加入,大約需要半個小時時間,所以采取點擊時先去掉所有項,然后再增加子目錄if ( !find.ishidden() && ! find.isdots() && !find.isdirectory() )insertitem( strfilename, 0, 0, hparent );/return true;/僅僅裝入下一級子目錄bool cdirtreectrl:addsubdirasitem1(htreeitem hparent)cstring strpath,strfi
24、lename;htreeitem hchild;/-去除該父項下所有的子項-/ 因為有dummy項,并且有時子目錄再次打開,或子目錄會刷新等,因此必須去除。while ( itemhaschildren(hparent)hchild = getchilditem(hparent); deleteitem( hchild );/-裝入該父項下所有子項-strpath = getfullpath(hparent); / 從本節(jié)點開始到根的路徑cstring strsearchcmd = strpath;if( strsearchcmd.right( 1 ) != _t( ""
25、) strsearchcmd += _t( "" );strsearchcmd += _t( "*.*" );cfilefind find;bool bcontinue = find.findfile( strsearchcmd );while ( bcontinue )bcontinue = find.findnextfile();strfilename = find.getfilename();if ( !find.ishidden() && ! find.isdots() && find.isdirectory()
26、)hchild = additem( hparent, strfilename );if ( !find.ishidden() && ! find.isdots() && !find.isdirectory() )insertitem( strfilename, 0, 0, hparent );/return true;/添加項htreeitem cdirtreectrl:additem(htreeitem hparent, lpctstr strname)/ 獲取路徑cstring strpath = getfullpath(hparent);cstring
27、strtemp = strpath + cstring(strname);if ( strtemp.right(1) != _t("") ) strtemp += _t("");shfileinfo shfinfo;int iicon, iiconsel;if ( !shgetfileinfo( strtemp,0,&shfinfo,sizeof( shfinfo ),shgfi_icon |shgfi_smallicon ) )m_strerror = _t("系統(tǒng)圖表獲取失敗!");return null;iicon =
28、shfinfo.iicon;/ we only need the index from the system image listdestroyicon( shfinfo.hicon );if ( !shgetfileinfo( strtemp,0,&shfinfo,sizeof( shfinfo ),shgfi_icon | shgfi_openicon |shgfi_smallicon ) )m_strerror = _t("系統(tǒng)圖表獲取失敗!");return null;iiconsel = shfinfo.iicon;/ we only need the i
29、ndex of the system image listdestroyicon( shfinfo.hicon );return insertitem( strname, iicon, iiconsel, hparent );/ 這里利用反射實現(xiàn)此函數(shù),好處是可以把消息的處理完全封閉到類內(nèi),有利于使用/ 父窗口去掉對此消息的處理即可,沒有處理,消息自然返回/void cdirtreectrl:onnmclick(nmhdr *pnmhdr, lresult *presult)/ todo: add your control notification handler code here/cpoi
30、nt mypoint;/uint uflag;/getcursorpos(&mypoint);/screentoclient(&mypoint);/htreeitem hitem = hittest(mypoint, &uflag);/if(null = hitem ) return;/if (_t("計算機")=getitemtext(hitem) return;/ 用戶點選了一個目錄項/ (tvht_onitem & uflag)的原因:如果不添加,即使在離圖標(biāo)或標(biāo)識的較遠的地方點一下左鍵(沒在正上面),也會有有樹的展開和收縮動作/ (0
31、x0010&uflag) 如果不加此項,則點擊+號時,addsubdirasitem不會被調(diào)用,下一級的有子目錄的文件夾前面就沒有+號/ #define tvht_onitembutton 0x0010 我是通過跟蹤試驗找到這個值的 /if (tvht_onitem & uflag)|(0x0010&uflag)/addsubdirasitem(hitem);/else return;/expand( hitem, tve_expand );/*presult = 0;/經(jīng)本人測試,用這個消息作為鼠標(biāo)點擊響應(yīng)的入口最好/用上面click消息也可以/這里也是利用反射,好處
32、是可以把消息的處理完全封閉到類內(nèi),實現(xiàn)封閉void cdirtreectrl:ontvnitemexpanding(nmhdr *pnmhdr, lresult *presult)lpnmtreeview pnmtreeview = reinterpret_cast<lpnmtreeview>(pnmhdr);/ todo: add your control notification handler code here/htreeitem hitem = getselecteditem(); / 注意:用這個函數(shù)不行,在+號打開時,子目錄總是沒有+號,盡管子目錄中有子項tv_ite
33、m tvi= pnmtreeview->itemnew;htreeitem hitem = tvi.hitem;if(null = hitem ) return;if (_t("計算機")=getitemtext(hitem) return;addsubdirasitem(hitem);*presult = 0;test bench 測試平臺搭建 構(gòu)建一個mfc基于對話框的應(yīng)用程序,把上面cdirtreectrl類(dirtreectrl.h, dirtreectrl.cpp)兩個文件,拷入工程文件中。在對話框資源中加入一個樹控件,如下圖:然后點擊樹控件為它加入一個變
34、量m_treedir,類名手工改為cdirtreectrl。 如下圖:主對話框?qū)ο笾芯蜁黾右粋€cdirtreectrl的變量對象m_treedir。然后在主對話框?qū)ο蟮膐ninitdialog()中增加一個調(diào)用 m_treedir.displaytree(null)即可,見下面: bool ctestbench_dirtreedlg:oninitdialog()cdialog:oninitdialog();/ 將“關(guān)于.”菜單項添加到系統(tǒng)菜單中。/ idm_aboutbox 必須在系統(tǒng)命令范圍內(nèi)。assert(idm_aboutbox & 0xfff0) = idm_aboutbox
35、);assert(idm_aboutbox < 0xf000);cmenu* psysmenu = getsystemmenu(false);if (psysmenu != null)bool bnamevalid;cstring straboutmenu;bnamevalid = straboutmenu.loadstring(ids_aboutbox);assert(bnamevalid);if (!straboutmenu.isempty()psysmenu->appendmenu(mf_separator);psysmenu->appendmenu(mf_string
36、, idm_aboutbox, straboutmenu);/ 設(shè)置此對話框的圖標(biāo)。當(dāng)應(yīng)用程序主窗口不是對話框時,框架將自動/ 執(zhí)行此操作seticon(m_hicon, true);/ 設(shè)置大圖標(biāo)seticon(m_hicon, false);/ 設(shè)置小圖標(biāo)/ todo: 在此添加額外的初始化代碼m_treedir.displaytree(null); / 就這里,加一句話即可。return true; / 除非將焦點設(shè)置到控件,否則返回true到此,就可以開始調(diào)試。 問題1:應(yīng)用mfc ctreectrl 樹控件,如果從中間刪除幾個子項,那么它帶的的子項是不是就會自動刪掉?是否需要我們先刪
37、掉它的子項才然后可以刪掉它本身? 可以同過試驗證明嗎?bool deleteitem( htreeitem hitem ); msdn上說:hitem handle of the tree item to be deleted. if hitem has the tvi_root value, all items are deleted from the tree view control. 由此估計只要刪掉一項,其子項自然會刪除,不必我們自己再去刪除。網(wǎng)上有個例子:在實現(xiàn)刪除功能時,應(yīng)對存在子項的樹項進行提示,以警告用戶是否連同其子項一起刪除。void cvctreedlg:ondel() /刪除子項功能函數(shù)htreeitem hsel=m_treectrl.getselectedi
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 地鐵車輛維修與運營安全考核試卷
- 制定個人職業(yè)目標(biāo)的步驟計劃
- 品牌塑造中的情感營銷策略計劃
- 交通出行安全管理與宣傳教育
- 前臺工作的自我提升與歸納計劃
- 站點安全管理與監(jiān)控技術(shù)計劃
- 主管在提升服務(wù)質(zhì)量中的作用計劃
- 學(xué)科融合教學(xué)的嘗試計劃
- 企業(yè)營銷戰(zhàn)略與市場拓展方法
- 企業(yè)網(wǎng)絡(luò)攻擊防御的技術(shù)研究
- 2024-2025學(xué)年一年級語文下冊第一單元測試(含答案)
- 2025年春新人教PEP版英語三年級下冊課件 Unit 1 Part C 第8課時 Reading time
- 固定矯治器粘接的護理流程
- 《疼痛治療》課件
- GB/T 45032-2024智慧城市面向城市治理的知識可信賴評估框架
- 2025年安全員B證理論考試900題及答案
- 廣東省廣州市2025屆高三下學(xué)期一模考試數(shù)學(xué)試題含解析
- 《畢業(yè)生就業(yè)協(xié)議書》(空白)原件
- 《胰島素和C肽》課件
- 開題報告:家庭教育投入視角下的中小學(xué)生減負政策效果研究
- 大學(xué)圖書館發(fā)展規(guī)劃
評論
0/150
提交評論