VS开发之使用树视图

有时候我们需要将数据分为很多个分支来展示,那么使用列表视图很显然是不合适的,所以我们就可以使用树形结构的视图。今天用树视图来实现一个膳食宝塔,当点击某个分支时将其详细数据显示到窗口上。

目录

1.消息映射

2.初始化图像列表

2.1创建图像列表

2.2添加图像

2.3绑定图像列表

3.初始化树视图

3.1设置项数据

3.2添加项

3.3初始化

4.响应选中分支


1.消息映射

我们不自绘只需要处理两个消息WM_INITDIALOGWM_NOTIFY。我们在WM_INITDIALOG消息中对树视图初始化,在WM_NOTIFY消息中处理展开分支的消息。如果需要自绘,那么需要映射NM_CUSTOMDRAW消息。

public:
	BEGIN_MSG_MAP(CTreeDlg)
		MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
		MESSAGE_HANDLER(WM_NOTIFY, OnNotify)
		END_MSG_MAP()

public:
	LRESULT OnInitDialog(UINT msg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
	LRESULT OnNotify(UINT msg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);

2.初始化图像列表

可以通过图像列表为每个分支的项绑定两个图像,用于项被选中和未被选中时显示。如果不需要则无需初始化。

2.1创建图像列表

通过ImageList_Create()函数创建图像列表。

	HIMAGELIST himl;

	//创建图标列表
	himl = ImageList_Create(40, 40, ILC_COLORDDB, 6, 0);
	if (himl == NULL)
		return FALSE;

注意:如果绘制的图标颜色不对(透明图标绘制出来是黑色的背景),那么可能是图标位深不够,可以将ILC_COLORDDB标志改为ILC_COLOR32。

2.2添加图像

先加载我们需要使用到的图标,使用LoadIcon()方法或者LoadIamge()方法都可以。

icon = LoadIcon(CNWSModule::Get().GetModuleInstance(), MAKEINTRESOURCE(IDI_TREEROOT));
//icon = (HICON)LoadImage(NULL, L"..\\..\\..\\DeliDoc\\图标\\树根目录图标.ico", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE | LR_VGACOLOR);

ImageList_AddIcon(himl, icon);
DestroyIcon(icon);

然后将图标添加到图像列表。本次添加的是图标,那么就使用ImageList_ReplaceIcon()函数,也可以使用ImageList_AddIcon。如果需要添加图像,可以使用ImageList_Add()函数来添加图像。

因为图标是加载的并不是创建的,所以不要求必须手动销毁它。当不再需要图标资源时,系统会自动释放该资源。手动销毁提前释放内存也没有问题。

ImageList_AddIcon(himl, icon);
DestroyIcon(icon);

2.3绑定图像列表

向树视图发送TVM_SETIMAGELIST消息来绑定图像列表。如果图像列表句柄为空,那么则是从树视图删除绑定的图像列表。

	//将图标列表绑定到树视图
	SendMessage(hwndTV, TVM_SETIMAGELIST, TVSIL_NORMAL, (LPARAM)himl);

3.初始化树视图

3.1设置项数据

树视图项是一个TVINSERTSTRUCT结构体。其中hParent成员指定该分支的父分支,item成员指定该分支的属性,分支的属性是一个TVITEM结构体。


	//树视图项的信息
	TVITEM tvi = { 0 };
	HTREEITEM hPrev = TVI_FIRST;
	tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
	tvi.pszText = (LPWSTR)lpszItem;
	tvi.cchTextMax = lstrlen(lpszItem) + 1;
	tvi.iImage = iconIndex;
	tvi.iSelectedImage = iconIndex;

	//树视图项
	TVINSERTSTRUCT treeItem = { 0 };
	treeItem.hParent = itemParent;
	treeItem.hInsertAfter = TVI_LAST;
	treeItem.item = tvi;

3.2添加项

向树视图发送TVM_INSERTITEM消息来插入指定的项。如果插入成功该消息会返回该分支的句柄。我们可以通过返回的分支句柄来添加该分支的子分支。

HTREEITEM hPrev = (HTREEITEM)SendMessage(hwndTV, TVM_INSERTITEM, 0, (LPARAM)&treeItem);

为了方便我们初始化树视图,我们一般会将其封装为一个函数:

HTREEITEM AddItemToTree(HWND hwndTV, LPCWSTR lpszItem, HTREEITEM itemParent, int iconIndex)
{
	if (hwndTV == NULL)
		return NULL;

	//树视图项的信息
	TVITEM tvi = { 0 };
	HTREEITEM hPrev = TVI_FIRST;
	tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
	tvi.pszText = (LPWSTR)lpszItem;
	tvi.cchTextMax = lstrlen(lpszItem) + 1;
    //图像列表如果已经初始化,可以指定项被选中和未被选中的图像索引。
	tvi.iImage = iconIndex;            //未选中
	tvi.iSelectedImage = iconIndex;    //选中

	//树视图项
	TVINSERTSTRUCT treeItem = { 0 };
	treeItem.hParent = itemParent;
	treeItem.hInsertAfter = TVI_LAST;
	treeItem.item = tvi;

	//插入树视图项
	hPrev = (HTREEITEM)SendMessage(hwndTV, TVM_INSERTITEM, 0, (LPARAM)&treeItem);
	return hPrev;
}

3.3初始化

1)添加树视图的根部,其他分支都是在根部的基础上进行延展。

HTREEITEM hPrev = NULL, firstTree = NULL, secondTree = NULL;
hPrev = AddItemToTree(treeView, L"膳食宝塔", TVI_ROOT, i);

2)添加分支

    firstTree = AddItemToTree(treeView, L"第三层", hPrev, i);
    secondTree = AddItemToTree(treeView, L"动物性肉", firstTree, i);
    AddItemToTree(treeView, L"禽类", secondTree, i);
    AddItemToTree(treeView, L"畜类", secondTree, i);
    AddItemToTree(treeView, L"水产类", secondTree, i);

3)图像列表有无的区别

带图像列表效果图:

不带:

4.响应选中分支

当我们选中分支会收到TVN_SELCHANGED通知,该通知会以WM_NOTIFY消息发送到父窗口。

LRESULT CTreeDlg::OnNotify(UINT msg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	LPNMTREEVIEW lpHdr = (LPNMTREEVIEW)lParam;
	if (lpHdr->hdr.code == TVN_SELCHANGED)
	{
		WCHAR deptName[50] = { 0 };
		//获取当前选中分支名
		TVITEM vTtem = { 0 };
		vTtem.mask = TVIF_TEXT;
		vTtem.hItem = lpHdr->itemNew.hItem;
		vTtem.cchTextMax = 50;
		vTtem.pszText = deptName;
		SendDlgItemMessage(IDC_TESTTREE, TVM_GETITEM, 0, (LPARAM)&vTtem);

		HWND groupHwnd = GetDlgItem(IDC_DETAILGROUP);
		HWND treeHwnd = GetDlgItem(IDC_TESTTREE);
		auto i = m_towerMap.find(deptName);
		if (i != m_towerMap.end())
		{
			::ShowWindow(groupHwnd, SW_SHOW);
			DrawItemText(groupHwnd, treeHwnd, deptName);
		}
		return TRUE;
	}
	return FALSE;
}

效果图:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值