VC中樹形控件(CTreeCtrl)的使用

樹形控件可以用於樹形的結構,其中有一個根接點(Root)然後下面有許多子結點,而每個子結點上有允許有一個或多個或沒有子結點。MFC中使用CTreeCtrl類來封裝樹形控件的各種操作。通過調用 BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );

創建一個窗口,dwStyle中可以使用以下一些樹形控件的專用風格:

TVS_HASLINES 在父/子結點之間繪製連線
TVS_LINESATROOT 在根/子結點之間繪製連線
TVS_HASBUTTONS 在每一個結點前添加一個按鈕,用於表示當前結點是否已被展開
TVS_EDITLABELS 結點的顯示字符可以被編輯
TVS_SHOWSELALWAYS 在失去焦點時也顯示當前選中的結點
TVS_DISABLEDRAGDROP 不允許Drag/Drop
TVS_NOTOOLTIPS 不使用ToolTip顯示結點的顯示字符

在樹形控件中每一個結點都有一個句柄(HTREEITEM),同時添加結點時必須提供的參數是該結點的父結點句柄,(其中根Root結點只有一個,既不可以添加也不可以刪除)利用 HTREEITEM InsertItem( LPCTSTR lpszItem, HTREEITEM hParent = TVI_ROOT, HTREEITEM hInsertAfter = TVI_LAST );
可以添加一個結點,pszItem爲顯示的字符,hParent代表父結點的句柄,當前添加的結點會排在hInsertAfter表示的結點的後面,返回值爲當前創建的結點的句柄。下面的代碼會建立一個如下形式的樹形結構:

+--- Parent1
    +--- Child1_1
    +--- Child1_2
    +--- Child1_3
+--- Parent2
+--- Parent3

/*假設m_tree爲一個CTreeCtrl對象,而且該窗口已經創建*/
HTREEITEM hItem,hSubItem;
hItem = m_tree.InsertItem("Parent1",TVI_ROOT);在根結點上添加Parent1
hSubItem = m_tree.InsertItem("Child1_1",hItem);//在Parent1上添加一個子結點
hSubItem = m_tree.InsertItem("Child1_2",hItem,hSubItem);//在Parent1上添加一個子結點,排在Child1_1後面
hSubItem = m_tree.InsertItem("Child1_3",hItem,hSubItem);

hItem = m_tree.InsertItem("Parent2",TVI_ROOT,hItem);   
hItem = m_tree.InsertItem("Parent3",TVI_ROOT,hItem);   

如果你希望在每個結點前添加一個小圖標,就必需先調用
CImageList* SetImageList( CImageList * pImageList, int nImageListType );
指明當前所使用的ImageList,nImageListType爲TVSIL_NORMAL。在調用完成後控件中使用圖片以設置的ImageList中圖片爲準。然後調用
HTREEITEM InsertItem( LPCTSTR lpszItem, int nImage, int nSelectedImage, HTREEITEM hParent = TVI_ROOT, HTREEITEM hInsertAfter = TVI_LAST);
添加結點,nImage爲結點沒被選中時所使用圖片序號,nSelectedImage爲結點被選中時所使用圖片序號。下面的代碼演示了ImageList的設置。

/*m_list 爲CImageList對象
IDB_TREE 爲16*(16*4)的位圖,每個圖片爲16*16共4個圖標*/
m_list.Create(IDB_TREE,16,4,RGB(0,0,0));
m_tree.SetImageList(&m_list,TVSIL_NORMAL);
m_tree.InsertItem("Parent1",0,1);//添加,選中時顯示圖標1,未選中時顯示圖標0


此外CTreeCtrl還提供了一些函數用於得到/修改控件的狀態。
HTREEITEM GetSelectedItem( );將返回當前選中的結點的句柄。
BOOL SelectItem( HTREEITEM hItem );將選中指明結點。
BOOL GetItemImage( HTREEITEM hItem, int& nImage, int& nSelectedImage ) / BOOL SetItemImage( HTREEITEM hItem, int nImage, int nSelectedImage )用於得到/修改某結點所使用圖標索引。
CString GetItemText( HTREEITEM hItem ) /BOOL SetItemText( HTREEITEM hItem, LPCTSTR lpszItem );用於得到/修改某一結點的顯示字符。
BOOL DeleteItem( HTREEITEM hItem );用於刪除某一結點,
BOOL DeleteAllItems( );將刪除所有結點。

此外如果想遍歷樹可以使用下面的函數:
HTREEITEM GetRootItem( );得到根結點。
HTREEITEM GetChildItem( HTREEITEM hItem );得到子結點。
HTREEITEM GetPrevSiblingItem/GetNextSiblingItem( HTREEITEM hItem );得到指明結點的上/下一個兄弟結點。
HTREEITEM GetParentItem( HTREEITEM hItem );得到父結點。

樹形控件的消息映射使用ON_NOTIFY宏,形式如同:ON_NOTIFY( wNotifyCode, id, memberFxn ),wNotifyCode爲通知代碼,id爲產生該消息的窗口ID,memberFxn爲處理函數,函數的原型如同void OnXXXTree(NMHDR* pNMHDR, LRESULT* pResult),其中pNMHDR爲一數據結構,在具體使用時需要轉換成其他類型的結構。對於樹形控件可能取值和對應的數據結構爲:

TVN_SELCHANGED 在所選中的結點發生改變後發送,所用結構:NMTREEVIEW
TVN_ITEMEXPANDED 在某結點被展開後發送,所用結構:NMTREEVIEW
TVN_BEGINLABELEDIT 在開始編輯結點字符時發送,所用結構:NMTVDISPINFO
TVN_ENDLABELEDIT 在結束編輯結點字符時發送,所用結構:NMTVDISPINFO
TVN_GETDISPINFO 在需要得到某結點信息時發送,(如得到結點的顯示字符)所用結構:NMTVDISPINFO
關於ON_NOTIFY有很多內容,將在以後的內容中進行詳細講解。

關於動態提供結點所顯示的字符:首先你在添加結點時需要指明lpszItem參數爲:LPSTR_TEXTCALLBACK。在控件顯示該結點時會通過發送TVN_GETDISPINFO來取得所需要的字符,在處理該消息時先將參數pNMHDR轉換爲LPNMTVDISPINFO,然後填充其中item.pszText。但是我們通過什麼來知道該結點所對應的信息呢,我的做法是在添加結點後設置其lParam參數,然後在提供信息時利用該參數來查找所對應的信息。下面的代碼說明了這種方法:

char szOut[8][3]={"No.1","No.2","No.3"};

//添加結點
HTREEITEM hItem = m_tree.InsertItem(LPSTR_TEXTCALLBACK,...)
m_tree.SetItemData(hItem, 0 );
hItem = m_tree.InsertItem(LPSTR_TEXTCALLBACK,...)
m_tree.SetItemData(hItem, 1 );
//處理消息
void CParentWnd::OnGetDispInfoTree(NMHDR* pNMHDR, LRESULT* pResult)
{
TV_DISPINFO* pTVDI = (TV_DISPINFO*)pNMHDR;
pTVDI->item.pszText=szOut[pTVDI->item.lParam];//通過lParam得到需要顯示的字符在數組中的位置
*pResult = 0;
}

關於編輯結點的顯示字符:首先需要設置樹形控件的TVS_EDITLABELS風格,在開始編輯時該控件將會發送TVN_BEGINLABELEDIT,你可以通過在處理函數中返回TRUE來取消接下來的編輯,在編輯完成後會發送TVN_ENDLABELEDIT,在處理該消息時需要將參數pNMHDR轉換爲LPNMTVDISPINFO,然後通過其中的item.pszText得到編輯後的字符,並重置顯示字符。如果編輯在中途中取消該變量爲NULL。下面的代碼說明如何處理這些消息:

//處理消息 TVN_BEGINLABELEDIT
void CParentWnd::OnBeginEditTree(NMHDR* pNMHDR, LRESULT* pResult)
{
TV_DISPINFO* pTVDI = (TV_DISPINFO*)pNMHDR;
if(pTVDI->item.lParam==0);//判斷是否取消該操作
*pResult = 1;
else
*pResult = 0;
}
//處理消息 TVN_BEGINLABELEDIT
void CParentWnd::OnBeginEditTree(NMHDR* pNMHDR, LRESULT* pResult)
{
TV_DISPINFO* pTVDI = (TV_DISPINFO*)pNMHDR;
if(pTVDI->item.pszText==NULL);//判斷是否已經取消取消編輯
m_tree.SetItemText(pTVDI->item.hItem,pTVDI->pszText);//重置顯示字符
*pResult = 0;
}

上面講述的方法所進行的消息映射必須在父窗口中進行(同樣WM_NOTIFY的所有消息都需要在父窗口中處理)。

*************************************************************************************************************************************

CTreeCtrl樹控件介紹(讀取數據庫來動態顯示)

ListCtrl在系統中大量被使用,例如Windows資源管理器就是一個典型的例子。

ListCtrl樹形控件功能描述:可以用於樹形的結構,其中有一個根接點(Root)然後下面有許多子結點,而每個子結點上有允許有一個或多個或沒有子結點。MFC中使用CTreeCtrl類來封裝樹形控件的各種操作。   

調用方法:

BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );

創建一個窗口,dwStyle中可以使用以下一些樹形控件的專用風格:

TVS_HASLINES 在父/子結點之間繪製連線

TVS_LINESATROOT 在根/子結點之間繪製連線

TVS_HASBUTTONS 在每一個結點前添加一個按鈕,用於表示當前結點是否已被展開

TVS_EDITLABELS 結點的顯示字符可以被編輯

TVS_SHOWSELALWAYS 在失去焦點時也顯示當前選中的結點

TVS_DISABLEDRAGDROP 不允許Drag/Drop

TVS_NOTOOLTIPS 不使用ToolTip顯示結點的顯示字符

在樹形控件中每一個結點都有一個句柄(HTREEITEM),同時添加結點時必須提供的參數是該結點的父結點句柄,利用

HTREEITEM InsertItem( LPCTSTR lpszItem, HTREEITEM hParent = TVI_ROOT, HTREEITEM hInsertAfter = TVI_LAST );

可以添加一個結點,pszItem爲顯示的字符,hParent代表父結點的句柄,當前添加的結點會排在hInsertAfter表示的結點的後面,返回值爲當前創建的結點的句柄

樹控件圖像列表

樹控件 (Tree Control) (CTreeCtrl) 中的每項都可以有一對與之關聯的位圖化圖像。這些圖像出現在項標籤的左邊。如果選擇了該項,就會顯示一個圖像;如果沒有選擇該項,就會顯示另一個圖像。例如,某項可能在選定時顯示一個打開的文件夾,而在未選定時顯示關閉的文件夾。

若要使用項圖像,必須通過構造 CImageList 對象和使用 CImageList::Create 函數創建相關圖像列表來創建一個圖像列表。然後,將想要的位圖添加到創建的列表中, 如果你希望在每個結點前添加一個小圖標,就必需先調用CImageList* SetImageList( CImageList * pImageList, int nImageListType );指明當前所使用的ImageListnImageListTypeTVSIL_NORMAL。在調用完成後控件中使用圖片以設置的ImageList中圖片爲準。然後調用

HTREEITEM InsertItem( LPCTSTR lpszItem, int nImage, int nSelectedImage, HTREEITEM hParent = TVI_ROOT, HTREEITEM hInsertAfter = TVI_LAST);添加結點,nImage爲結點沒被選中時所使用圖片序號,nSelectedImage爲結點被選中時所使用圖片序號。

用VC實現按數據庫記錄構建樹控件

將樹中的每一個項目作爲數據庫中的一條記錄(ACCESS2000),將程序啓動時,對數據庫進行讀操作;創建樹的各個項目時,是對數據庫進行讀操作,每次的讀取,都是在可是查尋符合條件的記錄,並將其一一添加到樹中!

  實現方法:

  使用ACCESS2000,創建一個數據庫,名字爲City.mdb(我們將製作一個關於省與市的樹,特別適合通訊錄);在數據庫中創建一表,表名爲TreeItem,字段內容與類型如下圖:

  ID: 索引號碼(可有,可無)

  Name: 項目名稱(必須)

  ParentItem: 父項名稱(必須)

  SecNum: 電話區號(可有,可無)

  輸入一些原始數據.數據庫已經準備好,那我們就進行實地的編程階段.

  程序實現:

  創建一個基於對話框的工程---TreeData

  一.ADO的引入和初始化

  由於在程序中,我使用了ADO來連接和操作數據庫,所以要進行以下操作:

  1.Stdafx.h中添加引作ADO的代碼:

  2.TreeData.h中聲明兩個私有變量:

  3.CTreeDataApp的構造函數CTreeDataApp中添加如下代碼:

4.CTreeDataApp的初始化函數中添加如下代碼:

.Recordset的創建:

  1.CTreeDataDlg.h中聲明變量:

  2. (1).在對話框窗口中添加一個TreeCtrl控件,一個ComboExe控件; TreeCtrl的風格設置如下圖;

  (2).導入一個BMP文件,做爲Tree的項目圖標(TreeBoot.bmp),將其ID設置爲IDB_TreeBootImage;

  (3).在嚮導中,爲三個控件添加連接對象.

  3.CTreeDataDlg中右擊,選擇添加一個成員函數

  4.添加一個COM變量到CString變量的轉換函數:

  5.同樣的方法添加另外一個成員函數

  6.添加一個求當前項子項串的成員函數

  7.處理TreeCtrl控件的點擊(OnClick)和改變選擇項(SelchangedTree)事件:

  三.在BOOL CTreeDataDlg::OnInitDialog()中添加以下代碼: TreeAddTree();

***************************************************************************************************************************************

在MFC中應用CTreeCtrl控件的技巧

 

首先,我們要創建一個基本對話框的MFC工程MFC_TreeCRTL(名字隨便給一個)。然後在資源視圖中插入兩個Dialog,ID分別爲IDD_DIALOG11和IDD_DIALOG211,都更改Style屬性爲Child,Border屬性爲None,爲它們建立兩個類,分別命名爲Cdialog11和Cdialog211,並在MFC_TreeCRTLDlg.CPP文件中包含dialog11.h和dialog211.h兩個頭文件。再導入幾個資源圖標作爲樹形控件節點的圖標及裝飾面板。最後在主面板上添加一個CTreeCtrl控件,ID爲默認,並在ClassWizard中添加它的一個變量,命名爲m_mytree。

  接着,我們進行具體代碼編寫。

  我們必須在CMFC_TreeCRTLDlg類中加入這些變量和函數

CDialog * m_treePages[2];

CString node_name;

BOOL InitMytree();

  我們還要在CMFC_TreeCRTLDlg類的構造函數中爲m_treePages[2]分配空間, m_treePages[0]=new Cdialog11;

m_treePages[1]=new Cdialog211;

InitMytree()函數爲m_mytree的初始化過程 BOOL CMFC_TreeCRTLDlg::InitMytree()

{

 //節點的圖標

 int i=0;

 int i_count=2;

 //載入圖標

 HICON icon[4];

 icon[0]=AfxGetApp()->LoadIcon (IDI_ICON6);

 icon[1]=AfxGetApp()->LoadIcon (IDI_ICON7);

 //創建圖像列表控件

 CImageList *m_imagelist=new CImageList;

 m_imagelist->Create(16,16,0,7,7);

 m_imagelist->SetBkColor (RGB(255,255,255));

 for(int n=0;n {

  m_imagelist->Add(icon[n]); //把圖標載入圖像列表控件

 }

 m_mytree.SetImageList(m_imagelist,TVSIL_NORMAL); //爲m_mytree設置一個圖像列表,使CtreeCtrl的節點顯示不同的圖標

 m_mytree.SetBkColor(RGB(0,250,255));//設置m_mytree的背景色

 //創建節點

 //父節點

 HTREEITEM root0=m_mytree.InsertItem("Dialog1",0,1,TVI_ROOT,TVI_LAST);

 HTREEITEM root1=m_mytree.InsertItem("Dialog2",0,1,TVI_ROOT,TVI_LAST);

 //一層子節點

 HTREEITEM sub_son0=m_mytree.InsertItem("Dialog 1-1",0,1,root0,TVI_LAST);

 HTREEITEM sub_son1=m_mytree.InsertItem("Dialog 2-1",0,1,root1,TVI_LAST);

 //二層孫子節點

 HTREEITEM sub_m_son0=m_mytree.InsertItem("Dialog 2-1-1",0,1,sub_son1,TVI_LAST);

 //建立節點對應的Dialog

 m_treePages[0]->Create(IDD_DIALOG11,this);

 m_treePages[1]->Create(IDD_DIALOG211,this);

 m_treePages[0]->ShowWindow(SW_SHOW);

 m_treePages[1]->ShowWindow(SW_HIDE);

 //把Dialog移到合適位置

 CRect m_rect;

 GetClientRect(m_rect);

 m_rect.left=200;

 m_treePages[0]->MoveWindow(m_rect);

 m_treePages[1]->MoveWindow(m_rect);

 return true;

}

  始初化完成後,我們要添加CTreeCtrl的消息響應事件,這樣才能讓它按我們的要求起作用。我們打開Class Wizard點選IDC_TREE1添加TVN_SELCHANGED消息,並在消息響應函數中寫入代碼。

void CMFC_TreeCRTLDlg::OnSelchangedTree1(NMHDR* pNMHDR, LRESULT* pResult)

{

 NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;

 // TODO: Add your control notification handler code here

 UpdateData(true);

 node_name=m_mytree.GetItemText(pNMTreeView->itemNew.hItem);

 //在標題欄顯示節點信息

 SetWindowText(node_name);

 //切換面板

 if(node_name=="Dialog 1-1"){

  m_treePages[0]->ShowWindow(SW_SHOW);

  m_treePages[1]->ShowWindow(SW_HIDE);

 }

 else if(node_name=="Dialog 2-1-1"){

  m_treePages[0]->ShowWindow(SW_HIDE);

  m_treePages[1]->ShowWindow(SW_SHOW);

 }

 UpdateData(false);

 *pResult = 0;

}

  最後,我們在 CMFC_TreeCRTLDlg::OnInitDialog()初始化函數裏調用InitMytree()函數。程序運行效果:


到這裏爲止,我們就把一個Dialog粘貼到了主Dialog上了,通過CTreeCtrl控件的節點的變化,讓不同的Dialog交替地粘貼在主Dialog上,從而方便於我們只用少數的窗口,調用更多的功能模塊,不必再爲每個模塊都作爲彈出窗口,而顯得繁雜。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章