VC中使用CTreeCtrl实现目录树

xiaoB.M. 发表于 2008-02-20 11:41:47

这是师姐给偶的寒假任务,前面一直没看,快开学了搞了一天也算实现了要的功能(其实就是修正别人的程序不能实现同步选取功能,选了父目录的话其他子目录也同样处于被选取状态)。

程序代码主要来自网络上的VCHelper程序。

这里还是从头叙述操作全过程,也好给自己留下深刻映像。
首先新建MFC工程,在对话框中添加CTreeCtrl控件,并关联变量Ctreectrl
 CTreeCtrl m_treectrl;
如果需要选择框,要将控件的复选框勾上。
并定义成员变量  HTREEITEM m_hTreeItemRoot,方便函数调用。

然后就是初始化目录树了。
这里主要分为三部:
设置树选项
添加硬盘目录
添加目录文件夹
SetTreeListStyle();
m_hTreeItemRoot = m_treectrl.InsertItem("我的电脑",NULL,NULL);///root就是节点的标题
GetLogicalDrives( m_hTreeItemRoot );
GetDriveDir( m_hTreeItemRoot );
m_treectrl.Expand( m_hTreeItemRoot, TVE_EXPAND );
各函数代码如下:
设置参数
void CVctestView::SetTreeListStyle()
{
 DWORD dwStyle = GetWindowLong( m_treectrl.m_hWnd, GWL_STYLE );
 dwStyle |= TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT;
 SetWindowLong( m_treectrl.m_hWnd, GWL_STYLE, dwStyle );
}
获取盘符
void CVctestView::GetLogicalDrives(HTREEITEM hParent)
{
 ASSERT( hParent );
 DWORD dwAllDriveStrings = GetLogicalDriveStrings( 0, NULL );
 ASSERT( dwAllDriveStrings >= 1 );
 LPTSTR lpDriveStrings = NULL;
 lpDriveStrings = new TCHAR[ dwAllDriveStrings + sizeof( _T( "" ) ) ];
 ASSERT( lpDriveStrings != NULL );
 // Save the original address for the drive strings...
 LPTSTR lpTmp = lpDriveStrings;
 GetLogicalDriveStrings( dwAllDriveStrings, lpDriveStrings );
 size_t szDriveString = lstrlen( lpDriveStrings );
 while ( szDriveString > 1 )
 {
  HTREEITEM tHTR = m_treectrl.InsertItem( lpDriveStrings, hParent );
  //m_treectrl.SetCheck(tHTR, 1);
  lpDriveStrings += szDriveString + 1;
  szDriveString
= lstrlen( lpDriveStrings );
 }
 lpDriveStrings = lpTmp;
 if ( lpDriveStrings )
 {
  delete lpDriveStrings;
  lpDriveStrings = NULL;
 }
 ASSERT( lpDriveStrings == NULL );
}
获取第一层目录
void CVctestView::GetDriveDir(HTREEITEM hItem)
{
 ASSERT( hItem );
 HTREEITEM hChild = m_treectrl.GetChildItem( hItem );
 while ( hChild )
 {
  CString strDir = m_treectrl.GetItemText( hChild );
  if ( strDir.Right( 1 ) != _T( "\" ) )
   strDir += _T( "\" );
  strDir += _T( "*.*" );
  CFileFind file;
  BOOL bContinue = file.FindFile( strDir );
  while ( bContinue )
  {
   bContinue = file.FindNextFile();
   if ( file.IsDirectory() && ! file.IsDots() )
   {
    HTREEITEM tHTR = m_treectrl.InsertItem( file.GetFileName(), hChild );
    m_treectrl.SetCheck( tHTR, m_treectrl.GetCheck(hChild));
   }
  }
  GetDriveDir( hChild );
  hChild = m_treectrl.GetNextItem( hChild, TVGN_NEXT );
 }
}

前面函数添加完后应该可以显示第一层目录了。
本来可以一次性用递归把所有目录生成,不过测试了一下发现这样
时间要太长,所以接下来的目录就用添加事件响应来完成了。
添加时间函数:
void CVctestView::OnItemexpandedTree1(NMHDR* pNMHDR, LRESULT* pResult) 
代码如下:
void CVctestView::OnItemexpandedTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
 NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
 // TODO: Add your control notification handler code here
 TVITEM tvItem = pNMTreeView->itemNew;
 if ( tvItem.hItem == m_hTreeItemRoot )
    return;
 
 HTREEITEM hChild = m_treectrl.GetChildItem( tvItem.hItem );
 CString TMP = GetFullPath(hChild);
 while ( hChild )
 {
  AddSubDirectory( hChild );
  hChild = m_treectrl.GetNextItem( hChild, TVGN_NEXT );
 }
 
 UpdateCheck(tvItem.hItem,FALSE);
 *pResult = 0;
}

CString CVctestView::GetFullPath(HTREEITEM hItem)
{
 ASSERT( hItem );

 CString strTmp = _T( "" );
 CString strPath = _T( "" );

 while ( hItem != m_hTreeItemRoot )
 {
  strTmp = m_treectrl.GetItemText( hItem );
  if ( strTmp.Right( 1 ) != _T( "\" ) )
   strTmp += _T( "\" );
  strPath = strTmp + strPath;

  hItem = m_treectrl.GetParentItem( hItem );
 }

 return strPath;
}

这时候已经可以显示所有的目录系统了,不过还有一个缺点就是
选择框的不同步,也是这一天自己主要弄的。
最后的实现就是添加鼠标响应时间,只要用户点选了复选框则
更新响应的子目录项。
void CVctestView::OnClickTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
 // TODO: Add your control notification handler code here
 CPoint myPoint;
 UINT uFlag;
 GetCursorPos(&myPoint);
 m_treectrl.ScreenToClient(&myPoint);
 HTREEITEM hItem = m_treectrl.HitTest(myPoint, &uFlag);
  if ((hItem != NULL) &&
  ((TVHT_ONITEM & uFlag)
  && !(TVHT_ONITEMBUTTON & uFlag) && !(TVHT_ONITEMLABEL & uFlag)
  ))
//此处用HitTest来判断点击区域,不是右边的标识符也不是左边的+图标,则就认为是点了复选框
  {
   UpdateCheck(hItem,TRUE);
  }
 *pResult = 0;
}

更新选择状态的递归程序,由于左键点击事件在选择框被标志之前所以
这里要选择相反的状态。
void CVctestView::UpdateCheck(HTREEITEM p, BOOL Check)
{
 if (!p) return ;
 HTREEITEM hChildItem = m_treectrl.GetChildItem(p);
 while (hChildItem != NULL)
 {
  UpdateCheck(hChildItem,Check);
 // if(m_treectrl.GetCheck(p) && !Check
 //  || m_treectrl.GetCheck(p) && Check) m_treectrl.SetCheck( hChildItem, 1);
  m_treectrl.SetCheck(hChildItem,m_treectrl.GetCheck(p) ^ Check);
  hChildItem = m_treectrl.GetNextItem(hChildItem, TVGN_NEXT);
 }
}

关键词(Tag): vc ctreectrl 编程实例

收藏: QQ书签 del.icio.us 订阅: Google 抓虾

最新评论

发表评论

* 昵称

已经注册过? 请登录

新用户请先注册 以便能显示头像及追踪评论回复

Email
网址
* 评论
表情
 
 

分类小组论坛
杂谈, 娱乐、八卦, 文学、艺术, 体育, 旅游、同城, 象牙塔, 情感, 时尚、生活, 星座, 科技

请注意遵守中华人民共和国法律法规, 如威胁到本站生存, 将依法向有关部门报告, 同时本站的相关记录可能成为对您不利的证据.

相关法律法规
全国人大常委会关于维护互联网安全的决定
中华人民共和国计算机信息系统安全保护条例
中华人民共和国计算机信息网络国际联网管理暂行规定
计算机信息网络国际联网安全保护管理办法
计算机信息系统国际联网保密管理规定