当前许多应用程序都在使用树型控件时为其添加了背景位图,增强的控件的魅力,然而对于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中实现带有背景位图的树型控件的更多相关文章

  1. 如何在VC中显示透明背景位图

    简单的调用系统API. Windows NT/2000/XP: Included in Windows 2000 and later.Windows 95/98/Me: Included in Win ...

  2. 强大的Js树型控件Dtree使用详解

    http://www.lmwlove.com/ac/ID868 在学习文章之前,要学会看官方网站http://destroydrop.com/javascripts/tree.从官方页面你能知道:dt ...

  3. Js树型控件Dtree使用

    dtree地址:http://destroydrop.com/javascripts/tree/ Key features Unlimited number of levels 无限级 Can be ...

  4. C# 中带有中国农历的日期选择控件

    开源一款自己刚开始接触 C# 时开发的带有农历信息的日期选择控件,记得那时还是在2010年的寒假期间做的这个东西.刚开始接触 C# 时,使用WinForm来开发桌面程序,觉得简直是简单又迅速,由于 C ...

  5. 如何在网页中浏览和编辑DWG文件 梦想CAD控件

    如何在网页中浏览和编辑DWG文件 梦想CAD控件 www.mxdraw.com 梦想绘图控件5.2  是国内最强,最专业的CAD开发组件(控件),不需要AutoCAD就能独立运行.控件使用VC 201 ...

  6. VC/MFC 工具栏上动态添加组合框等控件的方法

    引言 工具条作为大多数标准的Windows应用程序的一个重要组成部分,使其成为促进人机界面友好的一个重要工具.通过工具条极大方便了用户对程序的操作,但是在由Microsoft Visual C++开发 ...

  7. MVC4加载zTree树小控件

    前言: 第一次学习使用MVC框架,找了个练手项目,加载zTree树小控件.下面我就一步步说明我这次练手的经历以记录.如果有什么错误,希望各位大神帮忙指正,谢谢. 第一步: 利用VS2010新建一个MV ...

  8. PIE SDK图层树伙伴控件示例

    1.  功能简介 TocControl控件的主要作用是显示当前加载的图层有哪些.采用什么样的符号等,目的是使用户对当前加载的数据和结构有一个总体的把握.与之相关联的伙伴控件有MapControl,Pa ...

  9. 老李推荐:第14章9节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-遍历控件树查找控件

    老李推荐:第14章9节<MonkeyRunner源码剖析> HierarchyViewer实现原理-遍历控件树查找控件   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员 ...

随机推荐

  1. not valid for Running the scheme

    The run destination iPhone6 Plus is not valid for Running the scheme 'MyApp’. Phone6 Plus's iOS 8.0 ...

  2. PHP面试题之小杂鱼

    这里的题目都是比较老的,但是做笔试题时经常碰到,因为这些题目比较凌乱,考的知识点不好分类,就放一块了 /** * 题目:最少代码实现求3个数的最大值 * 三目运算符实现 */ function get ...

  3. chroot

    用途:更改命令的根目录. 语法:chroot Directory Command 描述: 注意:如果新根目录中的特殊文件具有与实际根目录不同的主要和次要设备号,则可能会覆盖文件系统. 只有具有 roo ...

  4. 通过实例深入理解lec和yacc

    本框架是一个lex/yacc完整的示例,包括详细的注释,用于学习lex/yacc程序基本的搭建方法,在linux/cygwin下敲入make就可以编译和执行.大部分框架已经搭好了,你只要稍加扩展就可以 ...

  5. Ubuntu root登陆

    分两步: 1.激活root 输入命令:sudo passwd,键入当前用户密码之后,为系统设置root密码:交互如下: jack@ubuntu:~$ sudo passwd[sudo] passwor ...

  6. Hibernate 、多表关联映射 - 多对多关系映射(many-to-many)

    hibernate.cfg.xml: <hibernate-configuration> <session-factory name="sessionFactory&quo ...

  7. C语言中的回调函数

    C语言中通过函数指针实现回调函数(Callback Function) ====== 首先使用typedef定义回调函数类型 ======  typedef void (*event_cb_t)(co ...

  8. Global.asax文件的说明

    每个应用程序可以包含一个特殊的目录(/bin)和两个特殊的文件(Web.config和Global.asax) Global.asax文件的使用: 作用:处理应用程序范围内的事件,声明应用程序范围的对 ...

  9. 创建SDE表空间

    创建空间数据存储类型为ST_Geometry的要素类有2种方法:1)使用SDE创建要素类从9.3 开始,默认创建的要素类都使用ST_Geometry存储空间数据,9.3 版本之前,可以通过配置dbtu ...

  10. Weblogic 部署注意事项

    Weblogic下部署服务注意事项: 1. 解决weblogic与hibernate的jar包冲突问题: 首 先找到该系统的DOMAIN_HOME(即你所建的域所在的位置)如:域empi的DOMAIN ...