|
(一)樹控制的主要功能 樹控制和視(Tree Control&View)主要用來顯示具有一定層次結(jié)構(gòu)的數(shù)據(jù)項,如資源管理器中的磁盤目錄等,以供用戶在其中進行各種選擇。樹控制中的每個數(shù)據(jù)項包括數(shù)據(jù)項名稱的文本字符串和用于表示該數(shù)據(jù)項的圖像,每個數(shù)據(jù)項下面均可包含各種子項,整個結(jié)構(gòu)就象目錄樹一樣。對于包含各種子項的數(shù)據(jù)項,可通過鼠標雙擊來展開或合攏,這可以通過控制樹的不同風(fēng)格來實現(xiàn)樹控制的不同顯示形態(tài)。這些風(fēng)格主要包括: TVS_HASLINES表示用連線來連接父項和它下面的各個子項,這可以使樹的顯示層次結(jié)構(gòu)更加清晰,但在無父項的各子項之間并沒有連線; TVS_LINESATROOT表示在無父項的各子項即根下面的各子項之間存在連線; TVS_HASBUTTONS表示在帶有子項的父項前面增加一個帶“+”或“-”的按鈕,這使得用戶也可以通過單擊這個小按鈕來實現(xiàn)子項的展開和合攏,當存在子項時,按鈕的初始狀態(tài)為“+”,當子項被展開時,按小按鈕由“+”變?yōu)?#8220;-”號,當子項合攏時,小按鈕由“-”變?yōu)?#8220;+”號,這一風(fēng)格同樣對于根項無效,如果需要可通過組合TVS_LINESATROOT風(fēng)格來實現(xiàn); TVS_EDITLABELS表示允許讓用戶單擊具有輸入焦點的數(shù)據(jù)項來修改其名稱。 對于樹控制,MFC中也以兩種形式來封裝,即樹控制(CTREECTRL)和樹視(CTREEVIEW),來滿足用戶的不同需求,對于一般要求的用戶如在對話框中應(yīng)用,使用樹控制比較方便,而對于具有較高要求的用戶,在使用樹視時還具有視窗口的各種方便特性,可以更好地滿足文檔/視結(jié)構(gòu)的要求。當在窗口中使用樹視時,樹視會占滿兩個窗口的客戶區(qū)域并自動隨窗口的框架結(jié)構(gòu)的調(diào)整而調(diào)整,并能夠很好地處理諸如菜單、加速鍵和工具條中的各種命令消息。在使用樹視時只要利用其成員函數(shù)CtreeView取得其一個引用,就可以象樹控制一樣方便地應(yīng)用:CtreeCtrl &treeCtrl = GetTreeCtrl()。 (二)樹控制的對象結(jié)構(gòu) 1、樹控制的建立方法 CtreeCtrl&treeCtrl 建立樹控制對象結(jié)構(gòu) Create 建立樹控制并綁定對象 樹控制CTreeCtrl::Create的調(diào)用格式如下: BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID ); 其中參數(shù)dwStyle用來確定樹控制的類型;rect用來確定樹控制的大小和位置;pParentWnd用來確定樹控制的父窗口,通用是一個對話框并且不能為NULL;nID用來確定樹控制的標識。樹控制的風(fēng)格可以是下列值的組合: TVS_HASLINES 表示樹控制在各子項之間存在連線; TVS_LINESATROOT 表示樹控制在根項之間存在連線; TVS_HASBUTTONS 表示樹控制視在父項左側(cè)存在展開合攏控制按鈕; TVS_EDITLABELS 表示可以控制鼠標單擊修改樹項的名稱; TVS_SHOWSELALWAYS 表示選中項即使在窗口失去輸入焦點時仍然保持選中狀態(tài); TVS_DISABLEDRAGDROP表示禁止樹控制發(fā)送TVN_BEGINDRAG消息 2、樹控制的屬性類 樹控制屬性類包括取得樹控制中項數(shù)GetCount、取得樹控制中項相對于父項的偏移值GetIndent、取得樹控制圖像列表控制句柄GetImageList、設(shè)置樹控制圖像列表控制句柄SetImageList、取得匹配下一個樹項GetNextItem、判斷給定樹項是否包含子項ItemHasChildren、取得樹項子項GetChildItem、取得下一個同屬樹項GetNextSiblingItem、取得前一個同屬樹項GetPrevSiblingItem、取得父樹項GetParentItem、取得第一個可視樹項GetFirstVisibleItem、取得下一個可視樹項GetNextVisible Item、取得前一個可視的樹項GetPrevVisibleItem、取得被選中的樹項GetSelectedItem、取得根樹項GetRootItem、取得樹項的屬性GetItem、設(shè)置樹項的屬性SetItem、取得樹項的狀態(tài)GetItemState、設(shè)置樹項的狀態(tài)SetItemState、取得與樹項關(guān)聯(lián)圖像GetItemImage、設(shè)置與樹項關(guān)聯(lián)圖像SetItemImage、取得樹項文本GetItemText、設(shè)置樹項文本SetItemText和取得樹項編輯控制句柄GetEditControl等。 3、樹控制的操作方法 樹控制的操作方法包括插入一個樹項InsertItem、刪除一個樹項DeleteItem、刪除所有樹項DeleteAllItems、展開或合攏樹項的子項Expand、選中特定樹項SelectItem、選擇一個樹項作為第一個可視樹項SelectSetFirstVisible、編輯一個可視的樹項EditLabel和排序給定父樹項的子樹項SortChildren等。 (三)樹控制的數(shù)據(jù)結(jié)構(gòu) 在使用樹控制時需要了解兩個個非常重要的數(shù)據(jù)結(jié)構(gòu)TV_ITEM和TV_INSERTSTRUCT,前一個數(shù)據(jù)結(jié)構(gòu)是用來表示樹控制的樹項信息,后一個數(shù)據(jù)結(jié)構(gòu)是用來定義將樹項增加到數(shù)據(jù)控制中所需要的數(shù)據(jù)內(nèi)容。另外,還需要NM_TREEVIEW、TV_DISPINFO和TV_HITTESTINFO三個數(shù)據(jù)結(jié)構(gòu),這幾個數(shù)據(jù)結(jié)構(gòu)的定義方法如下: ①基本數(shù)據(jù)項結(jié)構(gòu) typedef struct _TV_ITEM { UINT mask; //結(jié)構(gòu)成員有效性屏蔽位 HTREEITEM hItem; //數(shù)據(jù)項控制句柄 UINT state; //數(shù)據(jù)項狀態(tài) UINT stateMask; //狀態(tài)有效性屏蔽位 LPSTR pszText; //數(shù)據(jù)項名稱字符串 int cchTextMax; //數(shù)據(jù)項名稱的最大長度 int iImage; //數(shù)據(jù)項圖標索引號 int iSelectedImage;//選中數(shù)據(jù)項圖標索引號 int cChildren; //子項標識 LPARAM lParam; //程序定義的32位數(shù)據(jù) } TV_ITEM, FAR *LPTV_ITEM; ②插入樹項結(jié)構(gòu) typedef struct _TV_INSER TSTRUCT { HTREEITEM hParent; //父項控制句柄 HTREEITEM hInsertAfter; //插入樹項的位置 TV_ITEM item; //數(shù)據(jù)項的結(jié)構(gòu) } TV_INSERTSTRUCT, FAR *LPTV_INSERTSTRUCT; 其中插入的位置如果是TVI_FIRST 或TVI_LAST ,則分別插入到樹控制的最前面或最后面,如果是TVI_SORT ,則插入的樹項自動插入到合適的位置。 ③樹控制通知消息結(jié)構(gòu) typedef struct _NM_TREEVIEW { NMHDR hdr; //通知消息句柄 UINT action; //通知消息標志 TV_ITEM itemOld; //原來的數(shù)據(jù)結(jié)構(gòu) TV_ITEM itemNew; //新的數(shù)據(jù)結(jié)構(gòu) POINT ptDrag; //拖動指針 } NM_TREEVIEW; ④取得或設(shè)置數(shù)據(jù)結(jié)構(gòu) typedef struct _TV_DISPINFO { tvdi NMHDR hdr; //通知消息控制句柄 TV_ITEM item; //數(shù)據(jù)項結(jié)構(gòu) } TV_DISPINFO; ⑤指針測試數(shù)據(jù)結(jié)構(gòu) typedef struct _TVHITTESTINFO { tvhtst POINT pt; //客戶區(qū)域屏幕坐標指針 UINT flags; //存放測試結(jié)果的變量 HTREEITEM hItem; //測試的數(shù)據(jù)項結(jié)構(gòu) } TV_HITTESTINFO, FAR *LPTV_HITTESTINFO; 其中flags測試結(jié)果可以是如下值: TVHT_ABOVE 在客戶區(qū)域上面 TVHT_BELOW 在客戶區(qū)域下面 TVHT_NOWHERE 在客戶區(qū)域中并在最后一項下面 TVHT_ONITEM 在與樹項關(guān)聯(lián)的位圖或標簽內(nèi) TVHT_ONITEMBUTTON 在與樹項關(guān)聯(lián)的按鈕上 TVHT_ONITEMICON 在與樹項關(guān)聯(lián)的位圖上 TVHT_ONITEMINDENT 在與樹項關(guān)聯(lián)的聯(lián)線上 TVHT_ONITEMLABEL 在與樹項關(guān)聯(lián)的標簽上 TVHT_ONITEMRIGHT 在樹項的右側(cè)區(qū)域中 TVHT_ONITEMSTATEICON 在用戶定義的狀態(tài)圖標上 TVHT_TOLEFT 在客戶區(qū)域的左側(cè) TVHT_TORIGHT 在客戶區(qū)域的右側(cè) (四)樹控制的應(yīng)用技巧示例 這里仍以基于對話框演示實例來具體介紹樹控制及其和圖像列表相結(jié)構(gòu)的應(yīng)用技巧: 通過“FILE->NEW->PROJECTS->MFC AppWizard(EXE)”建立名為VCTREE的工程,在建立過程中選擇基于對話框(Dialog based)的應(yīng)用;將對話框中的默認控件刪除,并將所有對話框?qū)傩灾械腖anguage域設(shè)置為Chinese(P.R.C.),以使應(yīng)用程序支持中文;建立兩個圖標IDI_PM和IDI_CJ,用來表示圖標的選中和非選中狀態(tài),對于每個圖標都應(yīng)建立32X32和16X16兩種大小,以保證程序的需要;在對話框窗口中添加樹控制對象(TREE CONTROL),并設(shè)置五個按鈕“增加|刪除|查看|排序|關(guān)閉”,其對應(yīng)標識分別如下: 控制名稱 標題名稱 標識符號 樹控制 IDC_TREECTRL 按鈕 增 加 IDC_ADD 刪 除 IDC_DEL 查 看 IDC_VIEW 排 序 IDC_SORT 關(guān) 閉 IDOK 5、選中樹控制控件,選擇“VIEW->ClassWizard->Memory Variables。 骺刂艻DC_TREECTRL 引入成員變量,其變量類型為: 變量名 種類 變量類型 m_TreeCtrl Control CTreeCtrl 同時利用“MESSAGES MAP”為各命令按鈕增加控制功能函數(shù)。 6、然后在代碼文件VCTREEDlg.CPP中分別加入如下控制代碼: (1)在文件開始處增加圖像列表定義 CImageList Cil1,Cil2;//大小圖標像列表 (2)在初始化文件開始處增加代碼 BOOL CVCTREEDlg::OnInitDialog() { CDialog::OnInitDialog(); ......//原來其它代碼 // TODO: Add extra initialization here // 此處開始增加代碼 CVCTREEApp *pApp=(CVCTREEApp *)AfxGetApp();//創(chuàng)建圖象列表 Cil1.Create(16,16,ILC_COLOR,2,2); Cil1.Add(pApp->LoadIcon(IDI_PM)); Cil1.Add(pApp->LoadIcon(IDI_CJ)); m_TreeCtrl.SetImageList(&Cil1,TVSIL_NORMAL); //設(shè)置圖象列表 DWORD dwStyles=GetWindowLong(m_TreeCtrl.m_hWnd,GWL_STYLE);//獲取樹控制原風(fēng)格 dwStyles|=TVS_EDITLABELS|TVS_HASBUTTONS|TVS_HASLINES|TVS_LINESATROOT; SetWindowLong(m_TreeCtrl.m_hWnd,GWL_STYLE,dwStyles);//設(shè)置風(fēng)格 char * CJ[4]={"玉溪卷煙廠","云南卷煙廠","沈陽卷煙廠","成都卷煙廠"};//根數(shù)據(jù)名稱 char * PM[4][5]={ {"紅梅一","紅梅二","紅梅三","紅梅四","紅梅五"},//產(chǎn)品數(shù)據(jù)項 {"白梅一","白梅二","白梅三","白梅四","白梅五"}, {"綠梅一","綠梅二","綠梅三","綠梅四","綠梅五"}, {"青梅一","青梅二","青梅三","青梅四","青梅五"}}; int i,j; HTREEITEM hRoot,hCur;//樹控制項目句柄 TV_INSERTSTRUCT TCItem;//插入數(shù)據(jù)項數(shù)據(jù)結(jié)構(gòu) TCItem.hParent=TVI_ROOT;//增加根項 TCItem.hInsertAfter=TVI_LAST;//在最后項之后 TCItem.item.mask=TVIF_TEXT|TVIF_PARAM|TVIF_IMAGE|TVIF_SELECTEDIMAGE;//設(shè)屏蔽 TCItem.item.pszText="數(shù)據(jù)選擇"; TCItem.item.lParam=0;//序號 TCItem.item.iImage=0;//正常圖標 TCItem.item.iSelectedImage=1;//選中時圖標 hRoot=m_TreeCtrl.InsertItem(&TCItem);//返回根項句柄 for(i=0;i<4;i++){//增加各廠家 TCItem.hParent=hRoot; TCItem.item.pszText=CJ[i]; TCItem.item.lParam=(i+1)*10;//子項序號 hCur=m_TreeCtrl.InsertItem(&TCItem); for(j=0;j<5;j++){//增加各產(chǎn)品 TCItem.hParent=hCur; TCItem.item.pszText=PM[i][j]; TCItem.item.lParam=(i+1)*10+(j+1);//子項序號 m_TreeCtrl.InsertItem(&TCItem); } m_TreeCtrl.Expand(hCur,TVE_EXPAND);//展開樹 } m_TreeCtrl.Expand(hRoot,TVE_EXPAND);//展開上一級樹 return TRUE; // return TRUE unless you set the focus to a control } (3)增加樹項功能的實現(xiàn) 在增加樹項功能時,除了需要定義和設(shè)置插入樹項的數(shù)據(jù)結(jié)構(gòu)之外,還需要注意的是新增樹項的名稱初始時均為“新增數(shù)據(jù)”,增加后允許用戶給數(shù)據(jù)項設(shè)置自定義名稱。在編程時應(yīng)特別注意m_TreeCtrl.EditLabel(hInsert);后面不能跟任何其它程序命令,否則這條編輯指令無效。 void CVCTREEDlg::OnAdd() { //增加子項功能函數(shù) HTREEITEM hSel=m_TreeCtrl.GetSelectedItem();//取得選擇項句柄 if(hSel==NULL) return;//無任何選項則返回 static int nAddNo=100;//編號大于100為新增數(shù)據(jù) TV_INSERTSTRUCT TCItem;//定義插入項數(shù)據(jù)結(jié)構(gòu) TCItem.hParent=hSel; //設(shè)置父項句柄 TCItem.hInsertAfter=TVI_LAST;//在最后增加 TCItem.item.mask=TVIF_TEXT|TVIF_PARAM|TVIF_IMAGE|TVIF_SELECTEDIMAGE;//設(shè)屏蔽 TCItem.item.pszText="新增數(shù)據(jù)"; TCItem.item.lParam=nAddNo++;//索引號增加 TCItem.item.iImage=0;//正常圖標 TCItem.item.iSelectedImage=1;//選中時圖標 HTREEITEM hInsert=m_TreeCtrl.InsertItem(&TCItem);//增加 m_TreeCtrl.Expand(hSel,TVE_EXPAND); m_TreeCtrl.EditLabel(hInsert);//修改增加的數(shù)據(jù) } (4)刪除樹項功能的實現(xiàn) 在實現(xiàn)刪除功能時,應(yīng)對存在子項的樹項進行提示,以警告用戶是否連同其子項一起刪除。 void CVCTREEDlg::OnDel() { //刪除子項功能函數(shù) HTREEITEM hSel=m_TreeCtrl.GetSelectedItem();//取得選項句柄; if(hSel==NULL) return;//無任何選項則返回 if(m_TreeCtrl.ItemHasChildren(hSel))//判斷是否有子項 if(MessageBox("廠家下存在品名,一同刪除?","警告",MB_YESNO)==IDNO) return; m_TreeCtrl.DeleteItem(hSel); } (5)排序功能的實現(xiàn) 排序功能是對所選中的樹項的所有子項按字符中順序進行排序,如果想要按照其它規(guī)則進行排序,應(yīng)利用SortChildrenItemBC()函數(shù)進行自行開發(fā)排序程序,這個自行開發(fā)的函數(shù)與列表控制中實現(xiàn)的函數(shù)基本相同,可興趣的讀可以試驗。 void CVCTREEDlg::OnSort() { //排序子項功能函數(shù) HTREEITEM hSel=m_TreeCtrl.GetSelectedItem();//取得選項句柄; if(hSel==NULL) return;//無任何選項則返回 m_TreeCtrl.SortChildren(hSel); } (6)查看功能的實現(xiàn) 查看功能用來查看選中樹項的有關(guān)信息,函數(shù)中中顯示了樹項的文本名稱和標識號,可以將這兩個信息作為查找關(guān)鍵字,來查看其它更詳細的信息。 void CVCTREEDlg::OnView() { //查看選中項功能函數(shù) HTREEITEM hSel=m_TreeCtrl.GetSelectedItem();//取得選項句柄; if(hSel==NULL) return;//無任何選項則返回 CString cText=m_TreeCtrl.GetItemText(hSel);//取得數(shù)據(jù)項名 LONG IDs=m_TreeCtrl.GetItemData(hSel);//取得數(shù)據(jù)項序號 char temp[100]; wsprintf(temp,"廠家:%s 編號:%05d",cText,IDs); MessageBox(temp,"選擇信息"); } (7)修改功能的實現(xiàn) 如果不進行其它處理,當修改樹項的文本名稱后,就會發(fā)現(xiàn)其未被修改,這是因為程序中沒有對修改結(jié)果進行保存處理,這就要利用TV_DISPINFO結(jié)構(gòu)和SetItemText函數(shù)對TVN_ENDLABELEDIT進行處理,這樣就可以正確地實現(xiàn)修改功能。 void CVCTREEDlg::OnEndlabeleditTree(NMHDR* pNMHDR, LRESULT* pResult) { TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR; // TODO: Add your control notification handler code here if(pTVDispInfo->item.pszText==0) return;//用戶取消修改操作 m_TreeCtrl.SetItemText(pTVDispInfo->item.hItem, pTVDispInfo->item.pszText);//設(shè)置新數(shù)據(jù) *pResult = 0; } 7、樹視的演練技巧 樹視的應(yīng)用技巧在使用樹視時,其方法與樹控制基本相同,只不過樹視是在窗口中來實現(xiàn)的而樹控制是在對話框中實現(xiàn),樹視的各種功能是通過菜單來實現(xiàn)的而樹控制是通過按鈕等方式來實現(xiàn)的,樹控制需要在對話框中創(chuàng)建樹控制控件而樹視直接占據(jù)整個窗口,在設(shè)計過程中只要將按鈕和樹控制設(shè)計過程變?yōu)椴藛卧O(shè)計,并注意在功能函數(shù)是在類向?qū)е惺峭ㄟ^菜單命令來操作,同時在每個功能函數(shù)前面增加取得列表視引用的命令(CTreeCtrl& TreeCtrl = GetTreeCtrl()),而其余數(shù)據(jù)結(jié)構(gòu)和代碼均不需要修改,實現(xiàn)起來比較容易。
轉(zhuǎn)至:http://blog.csdn.net/tg2003/archive/2008/12/24/3586661.aspx |
|
|