现在的位置: 首页 > 综合 > 正文

treeview

2014年10月07日 ⁄ 综合 ⁄ 共 4055字 ⁄ 字号 评论关闭

VC中使用CTreeCtrl实现目录树

vc++ MFC 2010-08-18 19:49:35 阅读61 评论0   字号: 订阅

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

程序代码主要来自网络上的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);
 }
}

【上篇】
【下篇】

抱歉!评论已关闭.