https://download.csdn.net/download/h3974/33161552
一 用代码创建树控件
1.在要创建树控件的父对话框的头文件中,声明树控件对象(或称变量):
CTreeCtrl tree;
2.添加父对话框的OnCreate函数,在函数中创建树控件:
int CMFCApplication1Dlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDialogEx::OnCreate(lpCreateStruct) == -1)
return -1;
tree.Create(WS_CHILD | WS_VISIBLE | WS_BORDER| TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT | TVS_SHOWSELALWAYS,
CRect(10, 10, 300, 400), this, IDC_TREE1);
return 0;
}
3.在父对话框DoDataExchange函数中,子类化控件:
void CMFCApplication1Dlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_TREE1, tree);
}
4.在资源头文件中,定义树控件标识:
#define IDC_TREE1 1000
二 使用图像的树控件的初始化
1.在对话框头文件中声明树控件使用的图像列表:
CImageList imagelist;
2.在对话框初始化函数中,初始化树控件:
imagelist.Create(32, 32, ILC_COLOR32, 6, 6);//创建图像列表
//初始化图像列表
imagelist.Add(AfxGetApp()->LoadIcon(IDI_ICON9));//不使用索引为0的图像
imagelist.Add(AfxGetApp()->LoadIcon(IDI_ICON1));
imagelist.Add(AfxGetApp()->LoadIcon(IDI_ICON2));
imagelist.Add(AfxGetApp()->LoadIcon(IDI_ICON3));
imagelist.Add(AfxGetApp()->LoadIcon(IDI_ICON4));
imagelist.Add(AfxGetApp()->LoadIcon(IDI_ICON5));
imagelist.Add(AfxGetApp()->LoadIcon(IDI_ICON6));
imagelist.Add(AfxGetApp()->LoadIcon(IDI_ICON7));
imagelist.Add(AfxGetApp()->LoadIcon(IDI_ICON8));
tree.SetImageList(&imagelist, TVSIL_NORMAL);//为树控件设置图像列表。如果树控件不使用图像,此步可以省略,并可以不创建图像列表
//为树控件添加项,并设置项使用的图像
HTREEITEM h1 = tree.InsertItem(_T("A"), 1,1,0, TVI_LAST);
HTREEITEM h11=tree.InsertItem(_T("A1"), 4, 4, h1, TVI_LAST); HTREEITEM h12=tree.InsertItem(_T("A2"), 5, 5, h1, TVI_LAST);
HTREEITEM h2 = tree.InsertItem(_T("B"),2,2, 0, TVI_LAST);
HTREEITEM h21=tree.InsertItem(_T("B1"), 6, 6, h2, TVI_LAST); HTREEITEM h22=tree.InsertItem(_T("B2"), 7, 7, h2, TVI_LAST);
HTREEITEM h3 = tree.InsertItem(_T("C"), 3,3,0, TVI_LAST);
HTREEITEM h31=tree.InsertItem(_T("C1"), 8, 8, h3, TVI_LAST);
//为树控件项关联数值
tree.SetItemData(h1, 100); tree.SetItemData(h11, 130); tree.SetItemData(h12, 150);
tree.SetItemData(h2, 200); tree.SetItemData(h21, 230); tree.SetItemData(h22, 250);
tree.SetItemData(h3, 300); tree.SetItemData(h31, 330);
//设置树控件的背景色,文本颜色
tree.SetBkColor(RGB(20, 118, 252)); tree.SetTextColor(RGB(255, 255, 255));
//设置树控件的扩展样式
tree.SetExtendedStyle(TVS_EX_AUTOHSCROLL, TVS_EX_AUTOHSCROLL);//不需要扩展样式,省略此步
tree.SetLineColor(RGB(255, 0, 0));//设置连接线的颜色,没有连接线的控件省略此步
tree.SetInsertMarkColor(RGB(255, 0, 0));//设置插入标记的颜色,如果不使用插入标记,或不更改插入标记的默认颜色,省略此步
三 不使用图像的树控件的初始化
在对话框初始化函数中,初始化树控件:
//为树控件添加项,并设置项使用的图像
HTREEITEM h1 = tree.InsertItem(_T("A"), 0, TVI_LAST);
HTREEITEM h11=tree.InsertItem(_T("A1"), h1, TVI_LAST); HTREEITEM h12=tree.InsertItem(_T("A2"), h1, TVI_LAST);
HTREEITEM h2 = tree.InsertItem(_T("B"), 0, TVI_LAST);
HTREEITEM h21=tree.InsertItem(_T("B1"), h2, TVI_LAST); HTREEITEM h22=tree.InsertItem(_T("B2"), h2, TVI_LAST);
HTREEITEM h3 = tree.InsertItem(_T("C"), 0, TVI_LAST);
HTREEITEM h31=tree.InsertItem(_T("C1"), h3, TVI_LAST);
//为树控件项关联数值
tree.SetItemData(h1, 100); tree.SetItemData(h11, 130); tree.SetItemData(h12, 150);
tree.SetItemData(h2, 200); tree.SetItemData(h21, 230); tree.SetItemData(h22, 250);
tree.SetItemData(h3, 300); tree.SetItemData(h31, 330);
tree.SetBkColor(RGB(20, 118, 252)); tree.SetTextColor(RGB(255, 255, 255));//设置树控件的背景色,文本颜色
tree.SetExtendedStyle(TVS_EX_AUTOHSCROLL, TVS_EX_AUTOHSCROLL);//设置树控件的扩展样式。不需要扩展样式,省略此步
tree.SetLineColor(RGB(255, 0, 0));//设置连接线的颜色,没有连接线的控件省略此步
tree.SetInsertMarkColor(RGB(255, 0, 0));//设置插入标记的颜色,如果不使用插入标记,或不更改插入标记的默认颜色,省略此步
四 添加根项
在末尾添加根项:
tree.InsertItem(_T("项文本"), 0, TVI_LAST);
在开头添加根项:
tree.InsertItem(_T("项文本"), 0, TVI_FIRST);
在某根项的后面添加根项:
tree.InsertItem(_T("项文本"), 0, hItem);//在句柄为hItem的根项后面添加根项
五 添加子项
在开头添加子项:
tree.InsertItem(_T("项文本"), h_par, TVI_FIRST);//h_par是父项句柄
在末尾添加子项:
tree.InsertItem(_T("项文本"), h_par, TVI_LAST);//h_par是父项句柄
六 在某项的前面添加新项
HTREEITEM hSel = tree.GetSelectedItem();//获取选中项的句柄
if (hSel != NULL)
{
HTREEITEM hPar = tree.GetParentItem(hSel);//获取选中项的父项
HTREEITEM hPre = tree.GetPrevSiblingItem(hSel);//获取选中项的上一个兄弟项
if (hPre == NULL)//如果没有上一个兄弟项
{
tree.InsertItem(_T("新项文本"), hPar, TVI_FIRST);//在子项列表的开头添加子项
}
else//如果有上一个兄弟项
{
tree.InsertItem(_T("新项文本"), hPar, hPre);//在上一个兄弟项的后面添加新项
}
}
七 在某项的后面添加新项
HTREEITEM hSel = tree.GetSelectedItem();//获取选中项的句柄
if (hSel != NULL)
{
HTREEITEM hPar = tree.GetParentItem(hSel);//获取选中项的父项
tree.InsertItem(_T("新项文本"), hPar, hSel);//在选中项的后面添加新项
}
八 保存树控件所有项的文本及数值到文件
HTREEITEM h_item = tree.GetRootItem();//获取第一个根项
CString item_str; UINT cj = 0; int data;//记录项文本,项层级,项数值
if (h_item == NULL)return; //如果树控件不包含任何项返回
else
{
item_str = tree.GetItemText(h_item); data = tree.GetItemData(h_item);//获取项文本和数值
}
CFile F(_T("树控件数据.dat"), CFile::modeCreate | CFile::modeWrite);
CArchive ar(&F, CArchive::store);
UINT count = tree.GetCount();
ar << count;
ar << item_str << cj << data;//写入项文本,项层级,项数值
jump1:
if (tree.ItemHasChildren(h_item)) //如果有子项
{
h_item = tree.GetChildItem(h_item);//获取子项
cj += 1;//层级加1
item_str = tree.GetItemText(h_item); data = tree.GetItemData(h_item);//获取项文本和数值
ar << item_str << cj << data;//写入项文本,项层级,项数值
goto jump1;
}
jump2:
if (tree.GetNextSiblingItem(h_item) == NULL) //如果没有下一个兄弟项
{
if (cj == 0)goto end;//如果层级到达0,且没有下一个兄弟项,跳出循环
h_item = tree.GetParentItem(h_item);//获取父项
cj -= 1;//层级减1
goto jump2;
}
else //如果有下一个兄弟项
{
h_item = tree.GetNextSiblingItem(h_item);//获取下一个兄弟项
item_str = tree.GetItemText(h_item); data = tree.GetItemData(h_item);//获取项文本和数值
ar << item_str << cj << data;//写入项文本,项层级,项数值
goto jump1;
}
end:
;
九 由文件加载项到树控件
CFile F(_T("树控件数据.dat"), CFile::modeRead);
CArchive ar(&F, CArchive::load);
HTREEITEM h[15];//声明的数组的大小必须大于或等于树控件的层深,层深已由"树控件数据.dat"文件决定
CString item_str; UINT cj,count; int data;//记录项文本,项层级,项数值的变量类型,必须与保存到文件时使用的类型一致
ar >> count;
for (UINT i = 0; i < count;i++)
{
ar >> item_str >> cj >> data;
if (cj == 0)
{
h[cj] = tree.InsertItem(item_str, 0, 0); tree.SetItemData(h[cj], data);
}
else
{
h[cj] = tree.InsertItem(item_str, h[cj - 1], TVI_LAST); tree.SetItemData(h[cj],data);
}
}
十 就地编辑树控件项文本
树控件必须具有TVS_EDITLABELS样式,在对话框编辑器创建的树控件指定控件Edit Lablels属性为TRUE;为树控件添加TVN_ENDLABELEDIT事件响应函数,在函数中添加如下代码:
void CMFCApplication1Dlg::OnTvnEndlabeleditTree1(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTVDISPINFO pTVDispInfo = reinterpret_cast<LPNMTVDISPINFO>(pNMHDR);
if (pTVDispInfo->hdr.idFrom == IDC_TREE1)//如果通知由IDC_TREE1树控件发出
{
*pResult = 1;
}
else
*pResult = 0;
}
pTVDispInfo->hdr.code;//UINT 通知代码
pTVDispInfo->hdr.hwndFrom;//HWND 发送通知的树控件的窗口句柄
pTVDispInfo->hdr.idFrom;//UINT_PTR 发送通知的树控件的标识
pTVDispInfo->item;//TVITEM结构
pTVDispInfo->item.hItem;//HTREEITEM 就地编辑文本的项的句柄
pTVDispInfo->item.pszText;//LPWSTR 正在编辑的文本
十一 在树控件中查找项
此代码在树控件查找项文本具有指定前缀的项,如果查找到,选中该项。
CString str=_T("要查找的文本");
HTREEITEM h_item = tree.GetRootItem();
CString item_str; UINT cj = 0;
if (h_item == NULL)return;//如果树控件不包含项返回
else
{
item_str = tree.GetItemText(h_item);//获取项文本
}
if (str == item_str.Left(str.GetLength()))//如果找到匹配项
{
tree.SelectItem(h_item); return;//选中该项,返回
}
jump1:
if (tree.ItemHasChildren(h_item))//如果有子项
{
h_item = tree.GetChildItem(h_item);//获取子项
cj += 1;
item_str = tree.GetItemText(h_item);//获取项文本
if (str == item_str.Left(str.GetLength()))//如果找到匹配项
{
tree.SelectItem(h_item); return;//选中该项,返回
}
goto jump1;
}
jump2:
if (tree.GetNextItem(h_item, TVGN_NEXT) == NULL)//如果没有下一个兄弟项
{
if (cj == 0)return;//如果层级到达0,且没有下一个兄弟项,返回
h_item = tree.GetParentItem(h_item);//获取父项
cj -= 1;
goto jump2;
}
else//如果有下一个兄弟项
{
h_item = tree.GetNextItem(h_item, TVGN_NEXT);//获取下一个兄弟项
item_str = tree.GetItemText(h_item);//获取项文本
if (str == item_str.Left(str.GetLength()))//如果找到匹配项
{
tree.SelectItem(h_item); return;//选中该项
}
goto jump1;
}
十二 拖放项
方法一,使用MFC函数:
1. 以CTreeCtrl为基类创建派生类CMyTreeCtrl,修改树控件变量声明:
CMyTreeCtrl tree;
2.在CMyTreeCtrl类的头文件中,声明被拖动项句柄,声明拖动图像列表,声明布尔变量:
HTREEITEM hSour;//被拖动项句柄
CImageList* pList;//拖动图像列表
BOOL g_fDragging = FALSE;
3. 在CMyTreeCtrl类中,添加TVN_BEGINDRAG通知响应函数,在函数中添加如下代码:
void CMyTreeCtrl::OnTvnBegindrag(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
RECT rcItem;
hSour = pNMTreeView->itemNew.hItem;
pList=CreateDragImage(hSour);
GetItemRect(hSour, &rcItem, TRUE);
pList->BeginDrag(0, CPoint(0, 0));
CWnd* pwnd = FromHandle(pNMTreeView->hdr.hwndFrom);
pList->DragEnter(pwnd, CPoint(pNMTreeView->ptDrag.x, pNMTreeView->ptDrag.x));
ShowCursor(FALSE);
SetCapture();
g_fDragging = TRUE;
*pResult = 0;
}
4.在CMyTreeCtrl类中,添加WM_MOUSEMOVE消息响应函数,在函数中添加如下代码:
void CMyTreeCtrl::OnMouseMove(UINT nFlags, CPoint point)
{
HTREEITEM htiTarget;
TVHITTESTINFO tvht;
if (g_fDragging)
{
pList->DragMove(point);
pList->DragShowNolock(FALSE);
tvht.pt.x = point.x;
tvht.pt.y = point.y;
if ((htiTarget = HitTest(&tvht)) != NULL)
{
SelectDropTarget(htiTarget);
}
pList->DragShowNolock(TRUE);
}
CTreeCtrl::OnMouseMove(nFlags, point);
}
5.在CMyTreeCtrl类中,添加WM_LBUTTONUP消息响应函数,在函数中添加如下代码:
void CMyTreeCtrl::OnLButtonUp(UINT nFlags, CPoint point)
{
if (g_fDragging)
{
HTREEITEM htiDest = GetDropHilightItem();
if (htiDest != NULL)//在这里,处理被拖动节点的实际移动
{
}
pList->EndDrag();
SelectDropTarget(htiDest);
ReleaseCapture();
ShowCursor(TRUE);
g_fDragging = FALSE;
delete pList;
}
CTreeCtrl::OnLButtonUp(nFlags, point);
}
方法二,使用控件宏:
1. 以CTreeCtrl为基类创建派生类CMyTreeCtrl,修改树控件变量声明:
CMyTreeCtrl tree;
2.在CMyTreeCtrl类的头文件中,声明被拖动项句柄,声明拖动图像列表,声明布尔变量:
HTREEITEM hSour;//被拖动项句柄
CImageList* pList;//拖动图像列表
BOOL g_fDragging = FALSE;
3. 在CMyTreeCtrl类中,添加TVN_BEGINDRAG通知响应函数,在函数中添加如下代码:
void CMyTreeCtrl::OnTvnBegindrag(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
HIMAGELIST himl;
RECT rcItem;
hSour = pNMTreeView->itemNew.hItem;//被拖动项句柄
himl = TreeView_CreateDragImage(GetSafeHwnd(), pNMTreeView->itemNew.hItem);
TreeView_GetItemRect(GetSafeHwnd(), pNMTreeView->itemNew.hItem, &rcItem, TRUE);
ImageList_BeginDrag(himl, 0, 0, 0);
ImageList_DragEnter(GetSafeHwnd(), pNMTreeView->ptDrag.x, pNMTreeView->ptDrag.x);
ShowCursor(FALSE);
SetCapture();
g_fDragging = TRUE;
*pResult = 0;
}
4. 在CMyTreeCtrl类中,添加WM_MOUSEMOVE消息响应函数,在函数中添加如下代码:
void CMyTreeCtrl::OnMouseMove(UINT nFlags, CPoint point)
{
HTREEITEM htiTarget;
TVHITTESTINFO tvht;
if (g_fDragging)
{
ImageList_DragMove(point.x, point.y);
ImageList_DragShowNolock(FALSE);
tvht.pt.x = point.x;
tvht.pt.y = point.y;
if ((htiTarget = TreeView_HitTest(GetSafeHwnd(), &tvht)) != NULL)
{
TreeView_SelectDropTarget(GetSafeHwnd(), htiTarget);
}
ImageList_DragShowNolock(TRUE);
}
CTreeCtrl::OnMouseMove(nFlags, point);
}
5. 在CMyTreeCtrl类中,添加WM_LBUTTONUP消息响应函数,在函数中添加如下代码:
void CMyTreeCtrl::OnLButtonUp(UINT nFlags, CPoint point)
{
if (g_fDragging)
{
HTREEITEM htiDest = TreeView_GetDropHilight(GetSafeHwnd());//目标项句柄
if (htiDest != NULL)//在这里,处理被拖动节点的实际移动
{
}
ImageList_EndDrag();
TreeView_SelectDropTarget(GetSafeHwnd(), NULL);
ReleaseCapture();
ShowCursor(TRUE);
g_fDragging = FALSE;
delete pList;
}
CTreeCtrl::OnLButtonUp(nFlags, point);
}
十三 为项添加覆盖图像
覆盖图像是覆盖在项图像上面的图像。
CImageList imagelist;//在对话框头文件中声明图像列表对象
//下面代码创建并初始化图像列表,将图像列表设置给树控件,初始化树控件。可将下面代码放在对话框初始化函数中
imagelist.Create(32, 32, ILC_COLOR32 | ILC_MASK, 8, 8);//创建图像列表,要求图像列表具有ILC_MASK类型
imagelist.Add(AfxGetApp()->LoadIcon(IDI_ICON8));//不使用索引为0的图片
imagelist.Add(AfxGetApp()->LoadIcon(IDI_ICON1));//索引为1的图片
imagelist.Add(AfxGetApp()->LoadIcon(IDI_ICON2));//索引为2的图片
imagelist.Add(AfxGetApp()->LoadIcon(IDI_ICON3));//索引为3的图片
imagelist.Add(AfxGetApp()->LoadIcon(IDI_ICON4));//索引为4的图片
imagelist.Add(AfxGetApp()->LoadIcon(IDI_ICON5));//索引为5的图片
imagelist.Add(AfxGetApp()->LoadIcon(IDI_ICON6));//索引为6的图片
int index = imagelist.Add(AfxGetApp()->LoadIcon(IDI_ICON7));//索引为7的图片,将用作覆盖图片
imagelist.SetOverlayImage(index, 1);//创建覆盖图像,1为覆盖图像基于1的索引
tree.SetImageList(&imagelist, TVSIL_NORMAL);//将图像列表设置给树控件
HTREEITEM h1 = tree.InsertItem(_T("A"), 1, 1, 0, 0);//初始化树控件
HTREEITEM h11 = tree.InsertItem(_T("A1"), 2, 2, h1, TVI_LAST); HTREEITEM h12 = tree.InsertItem(_T("A2"), 3, 3, h1, TVI_LAST);
HTREEITEM h2 = tree.InsertItem(_T("B"), 4, 4, 0, 0);
HTREEITEM h21 = tree.InsertItem(_T("B1"), 5, 5, h2, TVI_LAST); HTREEITEM h22 = tree.InsertItem(_T("B2"), 6, 6, h2, TVI_LAST);
为指定项添加覆盖图像:
TVITEM tvItem;
tvItem.mask = TVIF_HANDLE | TVIF_STATE;
tvItem.hItem = h_item;//为要添加覆盖图像的项的句柄
tvItem.stateMask = TVIS_OVERLAYMASK;//此掩码指定项使用覆盖图像
tvItem.state = INDEXTOOVERLAYMASK(1);//1为覆盖图像基于1的索引
tree.SetItem(&tvItem);
十四 为项添加状态图像
状态图像是显示在项图像左侧的图像。
在对话框头文件中,声明状态图像列表:
CImageList statelist;
创建并初始化状态图像列表:
statelist.Create(32, 32, ILC_COLOR32, 10, 10);
statelist.Add(AfxGetApp()->LoadIcon(IDI_ICON1));//将第一个图像设置为一个不使用的图像,其索引为0
statelist.Add(AfxGetApp()->LoadIcon(IDI_ICON2));//状态图像
设置树控件使用的状态图像列表:
tree.SetImageList(&statelist, TVSIL_STATE);//参数2必须为 TVSIL_STATE
设置项的状态图像:
TVITEM tvItem;
tvItem.mask = TVIF_HANDLE | TVIF_STATE;
tvItem.hItem = hItem;//要设置状态图像的项的句柄
tvItem.stateMask = TVIS_STATEIMAGEMASK;//此掩码指定项使用状态图像
tvItem.state = INDEXTOSTATEIMAGEMASK(1);
tree.SetItem(&tvItem);
十五 使用树控件信息提示
下面代码,将项文本添加到项的提示信息中。
要求控件具有TVS_INFOTIP样式,或指定树控件Info Tip属性为TREU,ToolTips属性为TRUE;添加TVN_GETINFOTIP通知的响应函数,在函数中添加如下代码:
void CMFCApplication1Dlg::OnTvnGetInfoTipTree1(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTVGETINFOTIP pGetInfoTip = reinterpret_cast<LPNMTVGETINFOTIP>(pNMHDR);
if (pGetInfoTip->hdr.idFrom == IDC_TREE1)//IDC_TREE1是要添加提示信息的树控件标识
{
CTreeCtrl* pTree = (CTreeCtrl*)FromHandle(pGetInfoTip->hdr.hwndFrom);//获取树控件指针
TVITEM tvitem;
tvitem.mask = TVIF_TEXT;
tvitem.hItem = pGetInfoTip->hItem;
TCHAR temp[1024];
tvitem.pszText = temp;
tvitem.cchTextMax = sizeof(temp) / sizeof(TCHAR);
pTree->GetItem(&tvitem);//获取项的文本。
wcscpy_s(pGetInfoTip->pszText, pGetInfoTip->cchTextMax, tvitem.pszText);//将项文本复制到信息提示。
}
*pResult = 0;
}
十六 树控件事件
NM_CLICK
通知父窗口,用户在树控件中单击了鼠标左键。
处理函数声明:
afx_msg void OnNMClickTree1(NMHDR* pNMHDR, LRESULT* pResult);
消息映射:
ON_NOTIFY(NM_CLICK, IDC_TREE1, &CMFCApplication1Dlg::OnNMClickTree1)
处理函数定义:
void CMFCApplication1Dlg::OnNMClickTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
// TODO: 在此添加控件通知处理程序代码
*pResult = 0;
}
参数pNMHDR
为NMHDR结构的指针,包含此通知的其他信息。
pNMHDR->code;//UINT 通知代码,为NM_CLICK
int n = (int)(pNMHDR->code);//n==NM_CLICK==-2
pNMHDR->hwndFrom;//HWND 发送通知的树控件的窗口句柄
pNMHDR->idFrom;//UINT_PTR 发送通知的树控件的标识
参数pResult
*pResult = 1;
返回非零以防止默认处理。
*pResult = 0;
返回零以允许默认处理。
NM_CUSTOMDRAW
由树控件发送,通知其父窗口,实现控件的自定义绘制。此通知代码以WM_NOTIFY消息的形式发送。
处理函数声明:
afx_msg void OnNMCustomdrawTree1(NMHDR* pNMHDR, LRESULT* pResult);
消息映射:
ON_NOTIFY(NM_CUSTOMDRAW, IDC_TREE1, &CMFCApplication1Dlg::OnNMCustomdrawTree1)
处理函数定义:
void CMFCApplication1Dlg::OnNMCustomdrawTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMCUSTOMDRAW pNMCD = reinterpret_cast<LPNMCUSTOMDRAW>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
*pResult = 0;
}
参数
LPNMTVCUSTOMDRAW pD = reinterpret_cast<LPNMTVCUSTOMDRAW>(pNMHDR);
pD->nmcd;//NMCUSTOMDRAW结构
pD->nmcd.hdr;//NMHDR结构
pD->nmcd.hdr.hwndFrom;//HWND 发送通知的控件的句柄
pD->nmcd.hdr.idFrom;//UINT_PTR 发送通知的控件的标识
pD->nmcd.hdr.code;//UINT 通知代码,为NM_CUSTOMDRAW
pD->nmcd.dwDrawStage;//DWORD 当前绘制阶段
pD->nmcd.hdc;//HDC 控件的设备上下文的句柄
pD->nmcd.rc;//RECT结构,要绘制区域的边界矩形
pD->nmcd.dwItemSpec;//DWORD_PTR 项句柄
pD->nmcd.uItemState;//UINT 当前项状态
pD->nmcd.lItemlParam;//LPARAM 项数据
参数pResult
*pResult = CDRF_DODEFAULT;
控件将自行绘制。在此绘制周期内,它将不会发送其他NM_CUSTOMDRAW通知代码。该标志不能与任何其他标志一起使用。
*pResult = CDRF_DOERASE;
控件将仅绘制背景。
*pResult = CDRF_NEWFONT;
您的应用程序为此项指定了新字体;控件将使用新字体。当dwDrawStage等于CDDS_ITEMPREPAINT时,会发生这种情况。
*pResult = CDRF_NOTIFYITEMDRAW;
控件将把任何与项相关的绘图操作通知给父级。它将在绘制项之前和之后发送NM_CUSTOMDRAW通知代码。当dwDrawStage等于CDDS_PREPAINT时,会发生这种情况。
*pResult = CDRF_NOTIFYPOSTERASE;
控件将在擦除项后通知父级。当dwDrawStage等于CDDS_PREPAINT时,会发生这种情况。
*pResult = CDRF_NOTIFYPOSTPAINT;
当整个控件的绘制周期完成时,控件将发送NM_CUSTOMDRAW通知代码。当dwDrawStage等于CDDS_PREPAINT时,会发生这种情况。
*pResult = CDRF_NOTIFYSUBITEMDRAW;
您的应用程序将收到NM_CUSTOMDRAW通知代码,其中dwDrawStage设置为CDDS_ITEMPREPAINT | CDDS_SUBITEM绘制每个列表视图子项之前。然后,您可以分别为每个子项目指定字体和颜色,或者返回CDRF_DODEFAULT进行默认处理。当dwDrawStage等于CDDS_ITEMPREPAINT时,会发生这种情况。
*pResult = CDRF_SKIPDEFAULT;
您的应用程序手动绘制了该项。控件将不会绘制该项。当dwDrawStage等于CDDS_ITEMPREPAINT时,会发生这种情况。
*pResult = CDRF_SKIPPOSTPAINT;
控件将不会在项周围绘制焦点矩形。
绘制阶段值 说明
CDDS_PREPAINT 在绘制周期开始之前
CDDS_POSTPAINT 在绘制周期完成之后
CDDS_PREERASE 擦除开始之前
CDDS_POSTERASE 擦除完成后
CDDS_ITEMPREPAINT 绘制项之前
CDDS_ITEMPOSTPAINT 绘制项后
CDDS_ITEMPREERASE 删除项之前
CDDS_ITEMPOSTERASE 删除项之后
CDDS_SUBITEM 绘制子项
自定义绘制示例1://绘制树控件的背景,项的选中状态,热点状态,焦点状态。
void CMFCApplication1Dlg::OnNMCustomdrawTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMCUSTOMDRAW pNMCD = reinterpret_cast<LPNMCUSTOMDRAW>(pNMHDR);
LPNMTVCUSTOMDRAW pD = reinterpret_cast<LPNMTVCUSTOMDRAW>(pNMHDR);
if (pD->nmcd.hdr.idFrom == IDC_TREE1)//IDC_TREE1为树控件标识
{
CDC dc; dc.Attach(pD->nmcd.hdc);
switch (pD->nmcd.dwDrawStage)
{
case CDDS_PREPAINT://在绘制周期开始之前
dc.FillSolidRect(&(pD->nmcd.rc), RGB(200, 100, 100));//绘制树控件背景
*pResult = CDRF_NOTIFYITEMDRAW;
//将*pResult赋值CDRF_NOTIFYITEMDRAW,则下一个NM_CUSTOMDRAW通知已将dwDrawStage设置为CDDS_ITEMPREPAINT。
break;
case CDDS_ITEMPREPAINT://绘制项之前
pD->clrText = RGB(255, 255, 255);//指定项文本颜色
pD->clrTextBk = RGB(200, 100, 100);//指定项文本背景色
if (pD->nmcd.uItemState & CDIS_SELECTED)//选中状态
{
pD->clrTextBk = RGB(100, 100, 220);//指定项文本背景色
dc.FillSolidRect(&(pD->nmcd.rc), RGB(100, 100, 220)); //绘制项背景颜色
}
if (pD->nmcd.uItemState & CDIS_HOT)//热点状态
{
pD->clrTextBk = RGB(220, 120, 120);//指定项文本背景色
dc.FillSolidRect(&(pD->nmcd.rc), RGB(200, 100, 100));//绘制项背景颜色
}
if (pD->nmcd.uItemState & CDIS_FOCUS)//项具有焦点状态
{
pD->clrTextBk = RGB(120, 120, 240);//指定项文本背景色
dc.FillSolidRect(&(pD->nmcd.rc), RGB(120, 120, 240));//绘制项背景颜色
}
*pResult = 0;
break;
}
dc.Detach();
}
}
绘制结果:
自定义绘制示例2://更改树控件字体
void CMFCApplication1Dlg::OnNMCustomdrawTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMCUSTOMDRAW pNMCD = reinterpret_cast<LPNMCUSTOMDRAW>(pNMHDR);
LPNMTVCUSTOMDRAW pD = reinterpret_cast<LPNMTVCUSTOMDRAW>(pNMHDR);
if (pD->nmcd.hdr.idFrom == IDC_TREE1)//IDC_TREE1为树控件标识
{
CDC dc; dc.Attach(pD->nmcd.hdc);
switch (pD->nmcd.dwDrawStage)
{
case CDDS_PREPAINT://在绘制周期开始之前
*pResult = CDRF_NOTIFYITEMDRAW;
//将*pResult赋值CDRF_NOTIFYITEMDRAW,则下一个NM_CUSTOMDRAW通知已将dwDrawStage设置为CDDS_ITEMPREPAINT。
break;
case CDDS_ITEMPREPAINT://绘制项之前
dc.SelectObject(&font);//字体font需预先声明并创建
*pResult = CDRF_NEWFONT;
break;
}
dc.Detach();
}
}
NM_DBLCLK
通知父窗口,用户在树控件内双击了鼠标左键。
处理函数声明:
afx_msg void OnNMDblclkTree1(NMHDR* pNMHDR, LRESULT* pResult);
消息映射:
ON_NOTIFY(NM_DBLCLK, IDC_TREE1, &CMFCApplication1Dlg::OnNMDblclkTree1)
处理函数定义:
void CMFCApplication1Dlg::OnNMDblclkTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
// TODO: 在此添加控件通知处理程序代码
*pResult = 0;
}
参数pNMHDR
pNMHDR->code;//UINT 通知代码,为NM_DBLCLK
int n = (int)(pNMHDR->code);//n==NM_DBLCLK==-3
pNMHDR->hwndFrom;//HWND 发送通知的树控件的窗口句柄
pNMHDR->idFrom;//UINT_PTR 发送通知的树控件的标识
参数pResult
*pResult = 1;
返回非零以防止默认处理。
*pResult = 0;
返回零以允许默认处理。
NM_KILLFOCUS
通知父窗口,树控件失去输入焦点。
处理函数声明:
afx_msg void OnNMKillfocusTree1(NMHDR* pNMHDR, LRESULT* pResult);
消息映射:
ON_NOTIFY(NM_KILLFOCUS, IDC_TREE1, &CMFCApplication1Dlg::OnNMKillfocusTree1)
处理函数定义:
void CMFCApplication1Dlg::OnNMKillfocusTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
*pResult = 0;
}
参数pNMHDR
pNMHDR->code;//UINT 通知代码,为NM_KILLFOCUS
int n = (int)(pNMHDR->code);//n==NM_KILLFOCUS==-8
pNMHDR->hwndFrom;//HWND 发送通知的树控件的窗口句柄
pNMHDR->idFrom;//UINT_PTR 发送通知的树控件的标识
参数pResult
返回值被忽略。
NM_OUTOFMEMORY
通知父窗口,由于没有足够的可用内存,无法完成操作。此通知代码以 WM_NOTIFY 消息的形式发送。
处理函数声明:
afx_msg void OnNMOutofmemoryTree1(NMHDR* pNMHDR, LRESULT* pResult);
消息映射:
ON_NOTIFY(NM_OUTOFMEMORY, IDC_TREE1, &CMFCApplication1Dlg::OnNMOutofmemoryTree1)
处理函数定义:
void CMFCApplication1Dlg::OnNMOutofmemoryTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
*pResult = 0;
}
参数pNMHDR
pNMHDR->code;//UINT 通知代码,为NM_OUTOFMEMORY
int n = (int)(pNMHDR->code);//n==NM_OUTOFMEMORY==-1
pNMHDR->hwndFrom;//HWND 发送通知的树控件的窗口句柄
pNMHDR->idFrom;//UINT_PTR 发送通知的树控件的标识
参数pResult
NM_RCLICK
通知父窗口,用户在控件中单击了鼠标右键。 此通知代码以WM_NOTIFY消息的形式发送。
处理函数声明:
afx_msg void OnNMRClickTree1(NMHDR* pNMHDR, LRESULT* pResult);
消息映射:
ON_NOTIFY(NM_RCLICK, IDC_TREE1, &CMFCApplication1Dlg::OnNMRClickTree1)
处理函数定义:
void CMFCApplication1Dlg::OnNMRClickTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
// TODO: 在此添加控件通知处理程序代码
*pResult = 0;
}
参数pNMHDR
pNMHDR->code;//UINT 通知代码,为NM_RCLICK
int n = (int)(pNMHDR->code);//n==NM_RCLICK==-5
pNMHDR->hwndFrom;//HWND 发送通知的树控件的窗口句柄
pNMHDR->idFrom;//UINT_PTR 发送通知的树控件的标识
参数pResult
*pResult = 1;
返回非零以防止默认处理。
*pResult = 0;
返回零以允许默认处理。
NM_SETFOCUS
通知父窗口,树控件获得输入焦点。此通知代码以WM_NOTIFY消息的形式发送。
处理函数声明:
afx_msg void OnNMSetfocusTree1(NMHDR* pNMHDR, LRESULT* pResult);
消息映射:
ON_NOTIFY(NM_SETFOCUS, IDC_TREE1, &CMFCApplication1Dlg::OnNMSetfocusTree1)
处理函数定义:
void CMFCApplication1Dlg::OnNMSetfocusTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
// TODO: 在此添加控件通知处理程序代码
*pResult = 0;
}
参数pNMHDR
pNMHDR->code;//UINT 通知代码,为NM_SETFOCUS
int n = (int)(pNMHDR->code);//n==NM_SETFOCUS==-7
pNMHDR->hwndFrom;//HWND 发送通知的树控件的窗口句柄
pNMHDR->idFrom;//UINT_PTR 发送通知的树控件的标识
参数pResult
返回值被忽略。
TVN_BEGINDRAG
通知父窗口,树控件开始左键拖放操作。此通知代码以WM_NOTIFY消息的形式发送。
具有TVS_DISABLEDRAGDROP样式的树控件不会发送此通知代码。
处理函数声明:
afx_msg void OnTvnBegindragTree1(NMHDR* pNMHDR, LRESULT* pResult);
消息映射:
ON_NOTIFY(TVN_BEGINDRAG, IDC_TREE1, &CMFCApplication1Dlg::OnTvnBegindragTree1)
处理函数定义:
void CMFCApplication1Dlg::OnTvnBegindragTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
*pResult = 0;
}
参数pNMHDR
pNMHDR->code;//UINT 通知代码,为TVN_BEGINDRAG
int n = (int)(pNMHDR->code);//n==TVN_BEGINDRAG==-456
pNMHDR->hwndFrom;//HWND 发送通知的树控件的窗口句柄
pNMHDR->idFrom;//UINT_PTR 发送通知的树控件的标识
参数pResult
返回值被忽略。
TVN_BEGINLABELEDIT
通知父窗口,树控件项文本的编辑开始。此通知代码以WM_NOTIFY消息的形式发送。
处理函数声明:
afx_msg void OnTvnBeginlabeleditTree1(NMHDR* pNMHDR, LRESULT* pResult);
消息映射:
ON_NOTIFY(TVN_BEGINLABELEDIT, IDC_TREE1, &CMFCApplication1Dlg::OnTvnBeginlabeleditTree1)
处理函数定义:
void CMFCApplication1Dlg::OnTvnBeginlabeleditTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMTVDISPINFO pTVDispInfo = reinterpret_cast<LPNMTVDISPINFO>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
*pResult = 0;
}
参数pNMHDR
pNMHDR->code;//UINT 通知代码,为TVN_BEGINLABELEDIT
int n = (int)(pNMHDR->code);//n==TVN_BEGINLABELEDIT==-459
pNMHDR->hwndFrom;//HWND 发送通知的树控件的窗口句柄
pNMHDR->idFrom;//UINT_PTR 发送通知的树控件的标识
参数pResult
*pResult = 1;
返回非零,取消项文本编辑。
*pResult = 0;
返回零,完成项文本编辑。
TVN_BEGINRDRAG
通知父窗口,开始树控件项的右键拖动。此通知代码以WM_NOTIFY消息的形式发送。
处理函数声明:
afx_msg void OnTvnBeginrdragTree1(NMHDR* pNMHDR, LRESULT* pResult);
消息映射:
ON_NOTIFY(TVN_BEGINRDRAG, IDC_TREE1, &CMFCApplication1Dlg::OnTvnBeginrdragTree1)
处理函数定义:
void CMFCApplication1Dlg::OnTvnBeginrdragTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
*pResult = 0;
}
参数pNMHDR
pNMHDR->code;//UINT 通知代码,为TVN_BEGINRDRAG
int n = (int)(pNMHDR->code);//n==TVN_BEGINRDRAG==-457
pNMHDR->hwndFrom;//HWND 发送通知的树控件的窗口句柄
pNMHDR->idFrom;//UINT_PTR 发送通知的树控件的标识
参数pResult
返回值被忽略。
TVN_DELETEITEM
通知父窗口,树控件正在删除项。此通知代码以WM_NOTIFY消息的形式发送。
处理函数声明:
afx_msg void OnTvnDeleteitemTree1(NMHDR* pNMHDR, LRESULT* pResult);
消息映射:
ON_NOTIFY(TVN_DELETEITEM, IDC_TREE1, &CMFCApplication1Dlg::OnTvnDeleteitemTree1)
处理函数定义:
void CMFCApplication1Dlg::OnTvnDeleteitemTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
*pResult = 0;
}
参数
pNMTreeView->hdr;//NMHDR结构
pNMTreeView->hdr.code;//UINT 通知代码。为TVN_DELETEITEM
pNMTreeView->hdr.hwndFrom;//HWND 发送通知的树控件的窗口句柄
pNMTreeView->hdr.idFrom;//UINT_PTR 发送通知的树控件的标识
pNMTreeView->action;//UINT 操作标志
pNMTreeView->itemOld;//TVITEM结构 旧项状态的信息,为被删除项的句柄
pNMTreeView->itemOld.hItem;//HTREEITEM 被删除项的句柄
pNMTreeView->itemNew;//TVITEM结构 新项状态的信息,不使用此参数
pNMTreeView->ptDrag;//POINT 发送通知时,鼠标的客户端坐标
参数pResult
返回值被忽略。
TVN_ENDLABELEDIT
通知父窗口,树控件项文本编辑结束。此通知代码以WM_NOTIFY消息的形式发送。
要发送此通知,要求树控件具有TVS_EDITLABELS样式。
处理函数声明:
afx_msg void OnTvnEndlabeleditTree1(NMHDR* pNMHDR, LRESULT* pResult);
消息映射:
ON_NOTIFY(TVN_ENDLABELEDIT, IDC_TREE1, &CMFCApplication1Dlg::OnTvnEndlabeleditTree1)
处理函数定义:
void CMFCApplication1Dlg::OnTvnEndlabeleditTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMTVDISPINFO pTVDispInfo = reinterpret_cast<LPNMTVDISPINFO>(pNMHDR);
*pResult = 0;
}
参数pNMHDR
pTVDispInfo->hdr;//NMHDR结构
pTVDispInfo->hdr.code;//UINT 通知代码。为TVN_ENDLABELEDIT
pTVDispInfo->hdr.hwndFrom;//HWND 发送通知的树控件的窗口句柄
pTVDispInfo->hdr.idFrom;//UINT_PTR 发送通知的树控件的标识
pTVDispInfo->item;//TVITEM结构
pTVDispInfo->item.hItem;//HTREEITEM 完成文本编辑的项的句柄
pTVDispInfo->item.pszText;//LPWSTR 新的项文本
参数pResult
*pResult = 1;
返回TRUE,将已编辑的文本设置为项文本。
*pResult = 0;
返回FALSE,拒绝已编辑的文本,恢复为原来的文本。
示例
void CMFCApplication1Dlg::OnTvnEndlabeleditTree1(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTVDISPINFO pTVDispInfo = reinterpret_cast<LPNMTVDISPINFO>(pNMHDR);
if (pTVDispInfo->hdr.idFrom == IDC_TREE1)//如果通知由IDC_TREE1树控件发出
{
*pResult = 1;
}
else
*pResult = 0;
}
TVN_GETDISPINFO
通知父窗口,树控件请求显示或排序项所需的信息。此通知代码以WM_NOTIFY消息的形式发送。
树控件在以下3种情况下,发出此通知:
1.项的TVITEM结构的pszText成员是LPSTR_TEXTCALLBACK值。
2.项的TVITEM结构的iImage或iSelectedImage成员是I_IMAGECALLBACK值。
3.项的TVITEM结构的cChildren成员是I_CHILDRENCALLBACK值。
函数声明:
afx_msg void OnTvnGetdispinfoTree1(NMHDR* pNMHDR, LRESULT* pResult);
消息映射:
ON_NOTIFY(TVN_GETDISPINFO, IDC_TREE1, &CMFCApplication1Dlg::OnTvnGetdispinfoTree1)
函数定义:
void CMFCApplication1Dlg::OnTvnGetdispinfoTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMTVDISPINFO pTVDispInfo = reinterpret_cast<LPNMTVDISPINFO>(pNMHDR);
*pResult = 0;
}
参数pNMHDR
pTVDispInfo;//NMTVDISPINFO结构
pTVDispInfo->hdr;//NMHDR结构
pTVDispInfo->item;//TVITEM结构
pTVDispInfo->item.mask;//UINT NMTVDISPINFO结构掩码
pTVDispInfo->item.hItem;//HTREEITEM 项的句柄
pTVDispInfo->item.state;//UINT 一组位标志和图像列表索引,用于指示项的状态。
pTVDispInfo->item.stateMask;//UINT 项状态掩码
pTVDispInfo->item.pszText;//LPTSTR 指向存储项文本字符串缓冲区的指针
pTVDispInfo->item.cchTextMax;//int 缓冲区的大小,以字符为单位
pTVDispInfo->item.iImage;//int 项的图像的索引
pTVDispInfo->item.iSelectedImage;//int 项选中时的图像索引
pTVDispInfo->item.cChildren;//int 指示项是否含有子项
pTVDispInfo->item.lParam;//LPARAM 项关联的数值
参数pResult
返回值被忽略。
示例
HTREEITEM h1, h2, h3, h4;
h1=tree.InsertItem(L"A", 0, 0); h2=tree.InsertItem(L"B", 0, 0);
h3=tree.InsertItem(L"C", 0, 0); h4=tree.InsertItem(L"D", 0, 0);//初始化树控件
1.更改项属性:
TVITEM tvItem1;
tvItem1.mask = TVIF_HANDLE | TVIF_TEXT;
tvItem1.hItem = h1;//指定第1项句柄
tvItem1.pszText = LPSTR_TEXTCALLBACK;
tree.SetItem(&tvItem1);//设置第1项文本为LPSTR_TEXTCALLBACK值
TVITEM tvItem2;
tvItem2.mask= TVIF_HANDLE | TVIF_TEXT;
tvItem2.hItem = h2;//指定第2项句柄
tvItem2.pszText = LPSTR_TEXTCALLBACK;
tree.SetItem(&tvItem2);//设置第2项文本为LPSTR_TEXTCALLBACK值
2.添加TVN_GETDISPINFO通知的响应函数,在函数中指定项文本:
void CMFCApplication1Dlg::OnTvnGetdispinfoTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMTVDISPINFO pTVDispInfo = reinterpret_cast<LPNMTVDISPINFO>(pNMHDR);
if (pTVDispInfo->hdr.idFrom == IDC_TREE1 && pTVDispInfo->item.hItem == h1)
{
pTVDispInfo->item.pszText = L"ABCD";//指定第1项的文本
}
if (pTVDispInfo->hdr.idFrom == IDC_TREE1 && pTVDispInfo->item.hItem==h2)
{
pTVDispInfo->item.pszText = L"1234";//指定第2项的文本
}
*pResult = 0;
}
TVN_GETINFOTIP
由具有TVS_INFOTIP样式(“信息提示”属性为TRUE)的树控件发送到父窗口。请求在工具提示中显示其他文本信息。通知代码以WM_NOTIFY消息的形式发送。
处理函数声明:
afx_msg void OnTvnGetInfoTipTree1(NMHDR* pNMHDR, LRESULT* pResult);
消息映射:
ON_NOTIFY(TVN_GETINFOTIP, IDC_TREE1, &CMFCApplication1Dlg::OnTvnGetInfoTipTree1)
处理函数定义:
void CMFCApplication1Dlg::OnTvnGetInfoTipTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMTVGETINFOTIP pGetInfoTip = reinterpret_cast<LPNMTVGETINFOTIP>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
*pResult = 0;
}
参数pGetInfoTip
pGetInfoTip->hdr;//NMHDR结构
pGetInfoTip->hdr.code;//UINT 通知代码,为TVN_GETINFOTIP
pGetInfoTip->hdr.hwndFrom;//HWND 发送通知的树控件的窗口句柄
pGetInfoTip->hdr.idFrom;//UINT_PTR 发送通知的树控件的标识
pGetInfoTip->hItem;//HTREEITEM 请求提示信息的树控件项的句柄
pGetInfoTip->pszText;//LPWSTR 请求提示信息的树控件项的文本缓冲区的指针
pGetInfoTip->cchTextMax;//int 文本缓冲区的大小,以字符为单位
pGetInfoTip->lParam;//LPARAM 项关联的数值
参数pResult
忽略返回值。
示例
HTREEITEM h1, h2, h3, h4;//将项句柄声明为全局变量
h1=tree.InsertItem(L"A", 0, 0); h2=tree.InsertItem(L"B", 0, 0);
h3=tree.InsertItem(L"C", 0, 0); h4=tree.InsertItem(L"D", 0, 0);
void CMFCApplication1Dlg::OnTvnGetInfoTipTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMTVGETINFOTIP pGetInfoTip = reinterpret_cast<LPNMTVGETINFOTIP>(pNMHDR);
if (pGetInfoTip->hdr.idFrom == IDC_TREE1 && pGetInfoTip->hItem == h1)
{
pGetInfoTip->pszText = _T("提示文本内容1");
}
if (pGetInfoTip->hdr.idFrom == IDC_TREE1 && pGetInfoTip->hItem == h2)
{
pGetInfoTip->pszText = _T("提示文本内容2");
}
*pResult = 0;
}
TVN_ITEMCHANGED
通知父窗口,树控件项属性已更改。此通知代码以WM_NOTIFY消息的形式发送。
处理函数声明:
afx_msg void OnTvnItemChangedTree1(NMHDR* pNMHDR, LRESULT* pResult);
消息映射:
ON_NOTIFY(TVN_ITEMCHANGED, IDC_TREE1, &CMFCApplication1Dlg::OnTvnItemChangedTree1)
处理函数定义:
void CMFCApplication1Dlg::OnTvnItemChangedTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
NMTVITEMCHANGE* pNMTVItemChange = reinterpret_cast<NMTVITEMCHANGE*>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
*pResult = 0;
}
参数
pNMTVItemChange->hdr;//NMHDR结构
pNMTVItemChange->hdr.code;//UINT 通知代码,为TVN_ITEMCHANGED
pNMTVItemChange->hdr.hwndFrom;//HWND 发送通知的树控件的窗口句柄
pNMTVItemChange->hdr.idFrom;//UINT_PTR 发送通知的树控件的标识
pNMTVItemChange->hItem;//HTREEITEM 已更改属性的项的句柄
pNMTVItemChange->uChanged;//UINT 指定属性。唯一受支持的属性是状态属性,值为TVIF_STATE
pNMTVItemChange->uStateOld;//UINT 项以前的状态标志
pNMTVItemChange->uStateNew;//UINT 项新的状态标志
pNMTVItemChange->lParam;//LPARAM 与项关联的数值
参数pResult
*pResult = 0;
返回FALSE以接受更改。
*pResult = 1;
返回TRUE以阻止更改。
处理函数会为每个发生属性更改的项调用。
TVN_ITEMCHANGING
通知父窗口,树控件项属性即将更改。此通知代码以WM_NOTIFY消息的形式发送。
处理函数声明:
afx_msg void OnTvnItemChangingTree1(NMHDR* pNMHDR, LRESULT* pResult);
消息映射:
ON_NOTIFY(TVN_ITEMCHANGING, IDC_TREE1, &CMFCApplication1Dlg::OnTvnItemChangingTree1)
处理函数定义:
void CMFCApplication1Dlg::OnTvnItemChangingTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
NMTVITEMCHANGE* pNMTVItemChange = reinterpret_cast<NMTVITEMCHANGE*>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
*pResult = 0;
}
参数
pNMTVItemChange->hdr;//NMHDR结构
pNMTVItemChange->hdr.code;//UINT 通知代码,为TVN_ITEMCHANGING
pNMTVItemChange->hdr.hwndFrom;//HWND 发送通知的树控件的窗口句柄
pNMTVItemChange->hdr.idFrom;//UINT_PTR 发送通知的树控件的标识
pNMTVItemChange->hItem;//HTREEITEM 即将更改属性的项的句柄
pNMTVItemChange->uChanged;//UINT 指定属性。唯一受支持的属性是状态属性,值为TVIF_STATE
pNMTVItemChange->uStateOld;//UINT 项以前的状态标志
pNMTVItemChange->uStateNew;//UINT 项新的状态标志
pNMTVItemChange->lParam;//LPARAM 与项关联的数值
参数pResult
*pResult = 0;
返回FALSE以接受更改。
*pResult = 1;
返回TRUE以阻止更改。
处理函数会为每个发生属性更改的项调用。
TVN_ITEMEXPANDED
通知父窗口,树控件含有子项的项,已展开或折叠子项列表。此通知以WM_NOTIFY消息的形式发送。
处理函数声明:
afx_msg void OnTvnItemexpandedTree1(NMHDR* pNMHDR, LRESULT* pResult);
消息映射:
ON_NOTIFY(TVN_ITEMEXPANDED, IDC_TREE1, &CMFCApplication1Dlg::OnTvnItemexpandedTree1)
处理函数定义:
void CMFCApplication1Dlg::OnTvnItemexpandedTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
*pResult = 0;
}
参数
pNMTreeView->hdr;//NMHDR结构
pNMTreeView->hdr.code;//UINT 通知代码,为TVN_ITEMEXPANDED
pNMTreeView->hdr.hwndFrom;//HWND 发送通知的树控件的窗口句柄
pNMTreeView->hdr.idFrom;//UINT_PTR 发送通知的树控件的标识
pNMTreeView->action;//UINT 操作标志。展开为TVE_EXPAND,折叠为TVE_COLLAPSE
pNMTreeView->itemOld;//TVITEM结构 发生展开或折叠的项的旧状态信息
pNMTreeView->itemNew;//TVITEM结构 发生展开或折叠的项的新状态信息
pNMTreeView->ptDrag;//POINT 鼠标的客户端坐标。此参数始终为CPoint(0,0)
参数pResult
返回值被忽略。
TVN_ITEMEXPANDING
通知父窗口,树控件含有子项的项,即将展开或折叠子项列表。此通知以WM_NOTIFY消息的形式发送。
处理函数声明:
afx_msg void OnTvnItemexpandingTree1(NMHDR* pNMHDR, LRESULT* pResult);
消息映射:
ON_NOTIFY(TVN_ITEMEXPANDING, IDC_TREE1, &CMFCApplication1Dlg::OnTvnItemexpandingTree1)
处理函数定义:
void CMFCApplication1Dlg::OnTvnItemexpandingTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
*pResult = 0;
}
参数
pNMTreeView->hdr;//NMHDR结构
pNMTreeView->hdr.code;//UINT 通知代码,为TVN_ITEMEXPANDING
pNMTreeView->hdr.hwndFrom;//HWND 发送通知的树控件的窗口句柄
pNMTreeView->hdr.idFrom;//UINT_PTR 发送通知的树控件的标识
pNMTreeView->action;//UINT 操作标志。展开为TVE_EXPAND,折叠为TVE_COLLAPSE
pNMTreeView->itemOld;//TVITEM结构 发生展开或折叠的项的旧状态信息。此参数不包含项信息
pNMTreeView->itemNew;//TVITEM结构 发生展开或折叠的项的新状态信息
pNMTreeView->ptDrag;//POINT 鼠标的客户端坐标。此参数始终为CPoint(0,0)
参数pResult
*pResult = 1;
返回TRUE以防止子项列表展开或折叠。
*pResult = 0;
返回FALSE完成子项列表展开或折叠。
TVN_KEYDOWN
通知父窗口,树控件具有焦点时,用户按下了一个键。此通知代码以WM_NOTIFY消息的形式发送。
处理函数声明:
afx_msg void OnTvnKeydownTree1(NMHDR* pNMHDR, LRESULT* pResult);
消息映射:
ON_NOTIFY(TVN_KEYDOWN, IDC_TREE1, &CMFCApplication1Dlg::OnTvnKeydownTree1)
处理函数定义:
void CMFCApplication1Dlg::OnTvnKeydownTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMTVKEYDOWN pTVKeyDown = reinterpret_cast<LPNMTVKEYDOWN>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
*pResult = 0;
}
参数
pTVKeyDown->hdr;//NMHDR结构
pTVKeyDown->hdr.code;//UINT 通知代码,为TVN_KEYDOWN
pTVKeyDown->hdr.hwndFrom;//HWND 发送通知的树控件的窗口句柄
pTVKeyDown->hdr.idFrom;//UINT_PTR 发送通知的树控件的标识
pTVKeyDown->wVKey;//WORD 虚拟键代码
pTVKeyDown->flags;//UINT 始终为零
参数pResult
*pResult = 0;
如果按下的是字符键,返回零,则该字符将继续用作树控件键盘接口输入字符。
*pResult = 1;
如果按下的是字符键,返回非零,该字符不会用作树控件键盘接口输入字符。
对于其它键,将忽略返回值。
示例
void CMFCApplication1Dlg::OnTvnKeydownTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMTVKEYDOWN pTVKeyDown = reinterpret_cast<LPNMTVKEYDOWN>(pNMHDR);
if (pTVKeyDown->hdr.idFrom == IDC_TREE1)
{
switch (pTVKeyDown->wVKey)
{
case 65: //按下了A键
MessageBox(_T("A"));
break;
case 66: //按下了B键
MessageBox(_T("B"));
break;
}
}
*pResult = 1;
}
TVN_SELCHANGED
通知父窗口,树控件项选择已改变,此通知代码以WM_NOTIFY消息的形式发送。
处理函数声明:
afx_msg void OnTvnSelchangedTree1(NMHDR* pNMHDR, LRESULT* pResult);
消息映射:
ON_NOTIFY(TVN_SELCHANGED, IDC_TREE1, &CMFCApplication1Dlg::OnTvnSelchangedTree1)
处理函数定义:
void CMFCApplication1Dlg::OnTvnSelchangedTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
*pResult = 0;
}
参数
pNMTreeView->hdr;//NMHDR结构
pNMTreeView->hdr.code;//UINT 通知代码。为TVN_SELCHANGED
pNMTreeView->hdr.hwndFrom;//HWND 发送通知的控件的窗口句柄
pNMTreeView->hdr.idFrom;//UINT_PTR 发送通知的控件的标识
pNMTreeView->itemNew;//TVITEM结构 包含新选中项的信息。只有结构的mask,hItem,state和lParam成员才有效。
pNMTreeView->itemNew.hItem;//HTREEITEM 新选中项的句柄
pNMTreeView->itemOld;//TVITEM结构 包含原来的选中项的信息。只有结构的mask,hItem,state和lParam成员才有效。
参数pResult
返回值被忽略。
示例
void CMFCApplication1Dlg::OnTvnSelchangedTree1(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
if(pNMTreeView->hdr.idFrom == IDC_TREE1)
{
CTreeCtrl* pTree = (CTreeCtrl*)FromHandle(pNMTreeView->hdr.hwndFrom);//获取树控件的指针
CString str=pTree->GetItemText(pNMTreeView->itemNew.hItem);//获取新选中项的文本
}
*pResult = 0;
}
TVN_SELCHANGING
通知父窗口,树控件项选择即将改变。此通知代码以WM_NOTIFY消息的形式发送。
处理函数声明:
afx_msg void OnTvnSelchangingTree1(NMHDR* pNMHDR, LRESULT* pResult);
消息映射:
ON_NOTIFY(TVN_SELCHANGING, IDC_TREE1, &CMFCApplication1Dlg::OnTvnSelchangingTree1)
处理函数定义:
void CMFCApplication1Dlg::OnTvnSelchangingTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
*pResult = 0;
}
参数
pNMTreeView->hdr;//NMHDR结构
pNMTreeView->hdr.code;//UINT 通知代码,为TVN_SELCHANGING
pNMTreeView->hdr.hwndFrom;//HWND 发送通知的树控件的窗口句柄
pNMTreeView->hdr.idFrom;//UINT_PTR 发送通知的树控件的标识
pNMTreeView->action;//UINT 操作标志。展开为TVE_EXPAND,折叠为TVE_COLLAPSE
pNMTreeView->itemOld;//TVITEM结构 先前选中项的信息
pNMTreeView->itemNew;//TVITEM结构 新选中项的信息
参数pResult
*pResult = 1;
返回TRUE以防止选择更改。
*pResult = 0;
返回FALSE完成选择更改。
TVN_SINGLEEXPAND
由具有TVS_SINGLEEXPAND样式(或“单个展开”属性为TRUE)的树控件发送到父窗口,通过鼠标单击改变了选中项。此通知代码以WM_NOTIFY消息的形式发送。
TVS_SINGLEEXPAND样式即为:展开选中的项,折叠未选中的项。
处理函数声明:
afx_msg void OnTvnSingleExpandTree1(NMHDR* pNMHDR, LRESULT* pResult);
消息映射:
ON_NOTIFY(TVN_SINGLEEXPAND, IDC_TREE1, &CMFCApplication1Dlg::OnTvnSingleExpandTree1)
处理函数定义:
void CMFCApplication1Dlg::OnTvnSingleExpandTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
*pResult = 0;
}
参数
pNMTreeView->hdr;//NMHDR结构
pNMTreeView->hdr.code;//UINT 通知代码,为TVN_SINGLEEXPAND
pNMTreeView->hdr.hwndFrom;//HWND 发送通知的树控件的窗口句柄
pNMTreeView->hdr.idFrom;//UINT_PTR 发送通知的树控件的标识
pNMTreeView->action;//UINT 操作标志。始终为1000
pNMTreeView->itemOld;//TVITEM结构 先前选中项的信息
pNMTreeView->itemNew;//TVITEM结构 新选中项的信息
参数pResult
*pResult = 0;
发生默认行为。即展开选中的项,折叠未选中的项。
*pResult = TVNRET_SKIPOLD;
不折叠未选中的项。
*pResult = TVNRET_SKIPNEW;
不展开选中的项。
十七 树控件样式
样式常量 16进制值 10进制值 说明
TVS_CHECKBOXES 0x0100 256
启用复选框。
TVS_DISABLEDRAGDROP 0x0010 16
禁止树控件发送TVN_BEGINDRAG通知代码。
TVS_EDITLABELS 0x0008 8
允许用户编辑树控件项的标签(项文本)。
TVS_FULLROWSELECT 0x1000 4096
整行选择。
TVS_HASBUTTONS 0x0001 1
显示父项旁边的加号(+)和减号( - )按钮。
TVS_HASLINES 0x0002 2
使用线条显示项的层次结构。
TVS_INFOTIP 0x0800 2048
通过发送TVN_GETINFOTIP通知获取工具提示信息
TVS_LINESATROOT 0x0004 4
使用行连接树控件根目录中的项。
TVS_NOHSCROLL 0x8000 32768
禁用控件中的水平滚动条。
TVS_NONEVENHEIGHT 0x4000 16384
使用TVM_SETITEMHEIGHT消息将项的高度设置为奇数高度。
TVS_NOSCROLL 0x2000 8192
禁用控件中的水平和垂直滚动条。
TVS_NOTOOLTIPS 0x0080 128
禁用工具提示。
TVS_RTLREADING 0x0040 64
树控件文本将以与父窗口中文本相反的方向读取。
TVS_SHOWSELALWAYS 0x0020 32
当树控件失去焦点时,使选定的项保持选中状态。
TVS_SINGLEEXPAND 0x0400 1024
选中某项时,展开该项。
TVS_TRACKSELECT 0x0200 512
启用热跟踪。
十八 树控件扩展样式
样式常量 16进制值 10进制值 说明
TVS_EX_AUTOHSCROLL 0x0020 32
删除水平滚动条并根据鼠标位置自动水平滚动。
TVS_EX_DIMMEDCHECKBOXES 0x0200 512
如果控件具有TVS_CHECKBOXES样式,则包括灰色复选框状态。
TVS_EX_DOUBLEBUFFER 0x0004 4
双缓冲。
TVS_EX_DRAWIMAGEASYNC 0x0400 1024
检索日历网格信息。
TVS_EX_EXCLUSIONCHECKBOXES 0x0100 256
如果控件具有TVS_CHECKBOXES样式,则包括排除复选框状态。
TVS_EX_FADEINOUTEXPANDOS 0x0040 64
当鼠标移开或进入鼠标悬停状态时,淡入淡出expando按钮。
TVS_EX_MULTISELECT 0x0002 2
不支持。不使用。
TVS_EX_NOINDENTSTATE 0x0008 8
不要缩进expando按钮的树状视图。
TVS_EX_NOSINGLECOLLAPSE 0x0001 1
不折叠项。
TVS_EX_PARTIALCHECKBOXES 0x0080 128
如果控件具有TVS_CHECKBOXES样式,则包括部分复选框状态。
TVS_EX_RICHTOOLTIP 0x0010 16
允许在树控件中使用多格式工具提示(使用图标和文本自定义绘制)。
十九 树控件项状态
状态常量 16进制值 10进制值 说明
TVIS_BOLD 0x0010 16
该项为粗体。
TVIS_CUT 0x0004 4
该项被选择为剪切和粘贴操作的一部分.
TVIS_DROPHILITED 0x0008 8
该项选择为拖放目标。
TVIS_EXPANDED 0x0020 32
该项的子项已展开.
TVIS_EXPANDEDONCE 0x0040 64
该项曾经展开(子项至少展开一次)。
TVIS_EXPANDPARTIAL 0x0080 128
展开该项的部分。
TVIS_SELECTED 0x0002 2
该项被选中。
TVIS_OVERLAYMASK 0x0F00 3840
用于指定项的叠加图像索引的位的掩码。
TVIS_STATEIMAGEMASK 0xF000 61440
用于指定项的状态图像索引的位的掩码。
TVIS_USERMASK 0xF000 61440
与TVIS_STATEIMAGEMASK相同。
0 0x0000 0
不包含以上所有状态。
二十 TVITEM结构掩码
掩码常量 16进制值 10进制值 说明
TVIF_CHILDREN 0x0040 64
cChildren成员有效。
TVIF_DI_SETITEM 0x1000 4096
由控件保留信息。
TVIF_HANDLE 0x0010 16
hItem成员有效。
TVIF_IMAGE 0x0002 2
iImage成员有效。
TVIF_PARAM 0x0004 4
lParam成员有效。
TVIF_SELECTEDIMAGE 0x0020 32
iSelectedImage成员有效。
TVIF_STATE 0x0008 8
state和stateMask成员有效。
TVIF_TEXT 0x0001 1
pszText和cchTextMax成员有效。
二十一 树控件键盘接口
当树控件具有焦点,用户按下字符键时,会选中项文本以该字符开头的项;按向下箭头键,会向下移动选择;按向上箭头键,向上移动选择。
当某项具有焦点且包含子项,按向右箭头键,展开子项;按向左箭头键,关闭子项的显示。
当按Ctrl+Page Down时,向下滚动树控件。
当按Ctrl+Page Up时,向上滚动树控件。
当按Ctrl+End时,滚动到树控件的末尾。
当按Ctrl+Home时,滚动到树控件的开头。