VC中实现带有背景位图的树型控件
当前许多应用程序都在使用树型控件时为其添加了背景位图,增强的控件的魅力,然而对于Visual C++编程爱好者来说,使用Visual C++MFC提供的树型控件(CTreeCtrl)本身就是一个难点,至于如何使该控件能够带有背景位图,那就更加是一个令人困惑的问题了。本实例对CTreeCtrl类进行了增强,不仅使它带有背景位图,而且解决了在点击树型控件时背景位图闪动的问题,另外,通过在对话框中使用该控件来显示三级目录,演示了树型控件的基本使用方法。下图为程序编译后的运行效果图:
![]() 图一、带背景图的树型控件效果图 |
一、实现方法
在实现树型控件的背景位图之前,我们首先介绍一下树型控件的基本使用方法。树形控件在系统中大量被使用,例如Windows资源管理器就是一个典型的例子。树形控件可以用于树形的结构,其中有一个根接点(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表示的结点的后面,返回值为当前创建的结点的句柄。
如果你希望在每个结点前添加一个小图标,就必需先调用CTreeCtrl类的成员函数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为结点被选中时所使用图片序号。
此外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;
对于Visual C++ MFC提供的标准树型控件CTreeCtrl来说,并不支持背景位图,所以如果需要实现背景位图就需要先让其在内存CDC对象上对TREEVIEW缺省绘图,然后在选择背景位图,与缺省位图合成,即采用贴图的方式,把标准的TREEVIEW窗口贴在底图上。这个操作在内存中完成。同时为了避免闪烁,必须重载OnItemexpanding()和OnItemexpanded()这两个函数。SetRedraw函数主要保证其不要在子节点弹出时重画,而是在子节点已经扩展后重画。为此,例程中定义了一个CTreeCtrl类的子类CmyTreeCtrl,并重载了以下几个成员函数:
BOOL CMyTreeCtrl::SetBKImage(LPCTSTR LpszResource)
void CMyTreeCtrl::OnPaint()
void CMyTreeCtrl::OnItemexpanding(NMHDR* pNMHDR, LRESULT* pResult)
void CMyTreeCtrl::OnItemexpanded(NMHDR* pNMHDR, LRESULT* pResult)
BOOL CMyTreeCtrl::OnEraseBkgnd(CDC* pDC)
二、编程步骤
1、 启动Visual C++6.0,生成一个基于对话框的项目Tree,在框架上放置一个树形控制件,其ID标志符为:IDC_TREE1;
2、 创建CmyTreeCtrl类后,使用CLASSWIZARD为其添加消息映射:
ON_NOTIFY_REFLECT(TVN_ITEMEXPANDED,OnItemexpanded) ON_NOTIFY_REFLECT(TVN_ITEMEXPANDING, OnItemexpanding)
消息响应函数:
afx_msg void OnItemexpanded(NMHDR* pNMHDR, LRESULT* pResult);
afx_msg void OnItemexpanding(NMHDR* pNMHDR, LRESULT* pResult);
3、 将树型控件与CmyTreeCtrl类建立关联,在对话框中添加变量CMyTreeCtrl m_CtrlTree;
4、 制作一个准备作为树形控件背景的位图;
5、 修改对话框的初始化函数BOOL CTreeDlg::OnInitDialog();
6、 添加代码,编译运行程序。
三、实现代码
/////////////////////////////////////////////////
#if !defined(AFX_TREEDLG_H__D82DB384_F574_44A7_96DA_6EC9068E22B1__INCLUDED_)
#define AFX_TREEDLG_H__D82DB384_F574_44A7_96DA_6EC9068E22B1__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
/////////////////////////////////////////// CTreeDlg dialog
#include "MyTreeCtrl.h"
class CTreeDlg : public CDialog
{
// Construction
public:
CTreeDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CTreeDlg)
enum { IDD = IDD_TREE_DIALOG };
CMyTreeCtrl m_CtrlTree;
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CTreeDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
HICON m_hIcon;
// Generated message map functions
//{{AFX_MSG(CTreeDlg)
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
#endif
////////////////////////////////// MyTreeCtrl.cpp : implementation file
#include "StdAfx.h"
#include "Tree.h"
#include "MyTreeCtrl.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
////////////////////////////// CMyTreeCtrl
CMyTreeCtrl::CMyTreeCtrl()
{}
CMyTreeCtrl::~CMyTreeCtrl()
{}
BEGIN_MESSAGE_MAP(CMyTreeCtrl, CTreeCtrl)
//{{AFX_MSG_MAP(CMyTreeCtrl)
ON_WM_PAINT()
ON_WM_ERASEBKGND()
ON_NOTIFY_REFLECT(TVN_ITEMEXPANDED, OnItemexpanded)
ON_NOTIFY_REFLECT(TVN_ITEMEXPANDING, OnItemexpanding)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CMyTreeCtrl message handlers
BOOL CMyTreeCtrl::SetBKImage(LPCTSTR LpszResource)
{
// if this is not the first call then delete gdi objects
if( m_bitmap.m_hObject != NULL )
m_bitmap.DeleteObject();
HBITMAP hbmp = (HBITMAP)::LoadImage(AfxGetInstanceHandle(),
LpszResource, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION|LR_LOADFROMFILE);
if( hbmp == NULL )
return FALSE;
m_bitmap.Attach( hbmp );
return TRUE;
}
LRESULT CMyTreeCtrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
// TODO: Add your specialized code here and/or call the base class
return CTreeCtrl::WindowProc(message, wParam, lParam);
}
void CMyTreeCtrl::OnPaint()
{
CPaintDC dc(this); // device context for painting
CRect rcclient;
GetClientRect(&rcclient);
// create a compatible memory dc
CDC memdc;
memdc.CreateCompatibleDC(&dc);
CBitmap bitmap;
bitmap.CreateCompatibleBitmap(&dc, rcclient.Width(), rcclient.Height());
memdc.SelectObject( &bitmap );
CWnd::DefWindowProc(WM_PAINT, (WPARAM)memdc.m_hDC , 0);
CDC maskdc;
maskdc.CreateCompatibleDC(&dc);
CBitmap maskbitmap;
maskbitmap.CreateBitmap(rcclient.Width(), rcclient.Height(), 1, 1, NULL);
maskdc.SelectObject( &maskbitmap );
maskdc.BitBlt( 0, 0, rcclient.Width(), rcclient.Height(), &memdc,
rcclient.left, rcclient.top, SRCCOPY);
CBrush brush;
brush.CreatePatternBrush(&m_bitmap);
dc.FillRect(rcclient, &brush);
memdc.SetBkColor(RGB(0,0,0));
memdc.SetTextColor(RGB(255,255,255));
memdc.BitBlt(rcclient.left, rcclient.top, rcclient.Width(), rcclient.Height(), &maskdc, rcclient.left, rcclient.top, SRCAND);
dc.SetBkColor(RGB(255,255,255));
dc.SetTextColor(RGB(0,0,0));
dc.BitBlt(rcclient.left, rcclient.top, rcclient.Width(), rcclient.Height(), &maskdc, rcclient.left, rcclient.top, SRCAND);
dc.BitBlt(rcclient.left, rcclient.top, rcclient.Width(), rcclient.Height(), &memdc, rcclient.left, rcclient.top,SRCPAINT);
brush.DeleteObject();
}
BOOL CMyTreeCtrl::OnEraseBkgnd(CDC* pDC)
{
// TODO: Add your message handler code here and/or call default
return TRUE;
}
void CMyTreeCtrl::OnItemexpanded(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
// TODO: Add your control notification handler code here
Invalidate();
SetRedraw(TRUE);
*pResult = 0;
}
void CMyTreeCtrl::OnItemexpanding(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
// TODO: Add your control notification handler code here
SetRedraw(FALSE);
*pResult = 0;
}
///////////////////////////////////////////////////////
BOOL CTreeDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu-> AppendMenu(MF_SEPARATOR);
pSysMenu-> AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
// TODO: Add extra initialization here
m_CtrlTree.SetBKImage("IDB_BITMAP1");
SetIcon(m_hIcon, FALSE); // Set small icon
TVINSERTSTRUCT tvInsert;
tvInsert.hParent = NULL;
tvInsert.hInsertAfter = NULL;
tvInsert.item.mask = TVIF_TEXT;
tvInsert.item.pszText = _T("Visual C++编程实例");
HTREEITEM hCountry = m_CtrlTree.InsertItem(&tvInsert);
HTREEITEM hPA = m_CtrlTree.InsertItem(TVIF_TEXT,
_T("文章中心"), 0, 0, 0, 0, 0, hCountry, NULL);
HTREEITEM hWA = m_CtrlTree.InsertItem(_T("代码中心"),0, 0, hCountry, hPA);
m_CtrlTree.InsertItem(_T("全屏幕程序的实现"), hPA, TVI_SORT);
m_CtrlTree.InsertItem(_T("实现窗口的任意分割"), hPA, TVI_SORT);
m_CtrlTree.InsertItem(_T("实现菜单的自绘"), hPA, TVI_SORT);
m_CtrlTree.InsertItem(_T("实现全屏幕显示的代码"), hWA, TVI_SORT);
m_CtrlTree.InsertItem(_T("窗口任意分割的代码"), hWA, TVI_SORT);
m_CtrlTree.InsertItem(_T("菜单自绘代码"), hWA, TVI_SORT);
m_CtrlTree.Expand(hCountry,TVE_EXPAND);
return TRUE; // return TRUE unless you set the focus to a control
}
四、小结
到此为止,本例通过实现树形控件的背景位图介绍了一些树视图控件编程方法,包括树视图控件的建立、节点值的赋予等。当然,它应用的方面很广,使用方法也很多。这里仅仅是涉及到了构建树视图控件的基本框架,读者朋友们可以在此基础上,可进行扩展,从而完成更强大的功能,感兴趣的读者不妨自己扩展该控件试试。
VC中实现带有背景位图的树型控件的更多相关文章
- 如何在VC中显示透明背景位图
简单的调用系统API. Windows NT/2000/XP: Included in Windows 2000 and later.Windows 95/98/Me: Included in Win ...
- 强大的Js树型控件Dtree使用详解
http://www.lmwlove.com/ac/ID868 在学习文章之前,要学会看官方网站http://destroydrop.com/javascripts/tree.从官方页面你能知道:dt ...
- Js树型控件Dtree使用
dtree地址:http://destroydrop.com/javascripts/tree/ Key features Unlimited number of levels 无限级 Can be ...
- C# 中带有中国农历的日期选择控件
开源一款自己刚开始接触 C# 时开发的带有农历信息的日期选择控件,记得那时还是在2010年的寒假期间做的这个东西.刚开始接触 C# 时,使用WinForm来开发桌面程序,觉得简直是简单又迅速,由于 C ...
- 如何在网页中浏览和编辑DWG文件 梦想CAD控件
如何在网页中浏览和编辑DWG文件 梦想CAD控件 www.mxdraw.com 梦想绘图控件5.2 是国内最强,最专业的CAD开发组件(控件),不需要AutoCAD就能独立运行.控件使用VC 201 ...
- VC/MFC 工具栏上动态添加组合框等控件的方法
引言 工具条作为大多数标准的Windows应用程序的一个重要组成部分,使其成为促进人机界面友好的一个重要工具.通过工具条极大方便了用户对程序的操作,但是在由Microsoft Visual C++开发 ...
- MVC4加载zTree树小控件
前言: 第一次学习使用MVC框架,找了个练手项目,加载zTree树小控件.下面我就一步步说明我这次练手的经历以记录.如果有什么错误,希望各位大神帮忙指正,谢谢. 第一步: 利用VS2010新建一个MV ...
- PIE SDK图层树伙伴控件示例
1. 功能简介 TocControl控件的主要作用是显示当前加载的图层有哪些.采用什么样的符号等,目的是使用户对当前加载的数据和结构有一个总体的把握.与之相关联的伙伴控件有MapControl,Pa ...
- 老李推荐:第14章9节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-遍历控件树查找控件
老李推荐:第14章9节<MonkeyRunner源码剖析> HierarchyViewer实现原理-遍历控件树查找控件 poptest是国内唯一一家培养测试开发工程师的培训机构,以学员 ...
随机推荐
- Mvc Webapi+Fiddler调试 (WebAPI 一)
Fiddler Fiddler是一个http协议调试代理工具,它能够记录并检查所有你的电脑和互联网之间的http通讯,设置断点,查看所有的“进出”Fiddler的数据(指cookie,html,js, ...
- 表格(table) 插件:支持当前行增行、删除。使用事件委托
最近做一个项目,需要对表格进行增行和删行. 研究了一下jquery操作dom的方法和事件委托原理,下面是我编写的例子,源码传上,欢迎高手指点. 功能: 支持在指定行下面增行: 支持删行指定行: 增行. ...
- 安卓使用spinner控件和pull解析实现全国省市县的三级联动
实现该功能主要有两个难点: 1.XML文件的Pull解析.由于XML文件的结构较为复杂,所以解析时要注意,划分XML文件的结构,根据结构建立相应的和集合.本例中需要建立三个类和三个对象.三个类分别为, ...
- 用sql语句按周、按月、按季、按年统
原文地址:http://hi.baidu.com/%BD%F0%D3%F1kl_y/blog/item/1c368ffba9388476024f5645.html --按mySql语法统计按周,月,季 ...
- 10-2[RF] OOB validation
main idea: 在使用bootstrap生成gi的训练集时,会有一部分数据没有被选中,使用这一部分数据(OOB)进行validation. 1.数据没有被选中的概率 假设训练集大小为N,使用bo ...
- paip.c++ qt 共享库dll的建立
paip.c++ qt 共享库dll的建立 作者Attilax , EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog.csdn.net/at ...
- 日本語N1文法まとめ
1.v连用形+ものの:虽然~但是(201212-32) -(の)かというと/かといえば(201412-38)a动词ます辞書形・た形/イ形+~ な形語幹/名+~a,"至于是否・・・・・・&qu ...
- checkbox和radio的样式美化问题
如果你下定决心要改变现有的默认的checkbox和radio的样式,那么我目前有两种办法: 1.自己动手写一个,也就是自己写代码实现将input的checkbox和radio默认的样式隐藏掉,使用绝对 ...
- C#的输入输出及基本类型
//输出 Console.WriteLine("摩西摩西"); Console.Write("hollo");不带回车的 注意: 1.注意大小写敏感.(快捷键操 ...
- box-shadow属性
一.定义和用法 box-shadow属性 向框添加一个或多个阴影. 二.语法 box-shadow: h-shadow v-shadow blur spread color inset; h-shad ...