directorytree.cpp

来自「《突破Visual C++.NET编程实例五十讲+源文件,初学者学习的好东东!」· C++ 代码 · 共 315 行

CPP
315
字号

#include "stdafx.h"
#include "resource.h"
#include "DirectoryTree.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define MAX_DIR_LENGTH 1024


// CDirectoryTree

CDirectoryTree::CDirectoryTree()
{
	// 初始化成员变量
	m_szCurrentDir.Empty();
	m_cCurrentDrive = 'a';	// 最初标志

	// 初始化图标ID
	n_TreeIconClosed    = 0;
	n_TreeIconClosedSel = 1;
	n_TreeIconOpen      = 2;
	n_TreeIconOpenSel   = 3;
}

CDirectoryTree::~CDirectoryTree()
{
}


BEGIN_MESSAGE_MAP(CDirectoryTree, CTreeCtrl)
	//{{AFX_MSG_MAP(CDirectoryTree)
	ON_NOTIFY_REFLECT(NM_DBLCLK, OnDblclk)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


// CDirectoryTree 消息映射函数

BOOL CDirectoryTree::Initialize()
{
	//读取目录结构,并高亮显示当前目录
	HTREEITEM       hTreeItem;				
	HTREEITEM       hTreeParent;			
	DWORD           dwRes = 0;				
	TV_INSERTSTRUCT tvstruct;				
	int             nNumNodes = 0;			
	int             i = 0;					
	char            szPath[MAX_DIR_LENGTH];	
	char            szSeps[] = "\\";		
	char *          token;					
	if ('a' != m_cCurrentDrive)
	{
		CString s;
		s.Format("%c:", m_cCurrentDrive);
		SetCurrentDirectory(s);
		DeleteAllItems();
	}

	// 获取当前目录,并高亮显示
	dwRes = GetCurrentDirectory(MAX_DIR_LENGTH, szPath);
	if (0 == dwRes)
	{
		LPVOID lpMsgBuf;
		FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
					  NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
					  (LPTSTR) &lpMsgBuf, 0, NULL);
		MessageBox((LPTSTR)lpMsgBuf, "GetLastError", MB_OK|MB_ICONERROR);
		LocalFree(lpMsgBuf);
		return FALSE;
	}

	// 保存当前路径和盘符
	m_szCurrentDir = szPath;
	m_cCurrentDrive = szPath[0];

	// 填充从盘符到当前目录的目录树
	hTreeParent = TVI_ROOT;
	token =  _tcstok(szPath, szSeps);
	while (token)
	{
		// 在目录树中增加项
		tvstruct.hParent = hTreeParent;
		tvstruct.hInsertAfter = TVI_LAST;
		tvstruct.item.iImage = n_TreeIconOpen;
		tvstruct.item.iSelectedImage = n_TreeIconOpenSel;
		tvstruct.item.pszText = token;
		tvstruct.item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT;
		hTreeItem = InsertItem(&tvstruct);
		hTreeParent = hTreeItem;
		nNumNodes++;	// 节点数量

		token = _tcstok(NULL, szSeps);
	}

	// 自动展开目录树
	hTreeParent = hTreeItem = NULL;
	hTreeItem   = GetRootItem();
	for (i=0; i<nNumNodes; i++)
	{
		hTreeParent = hTreeItem;
		Expand(hTreeParent, TVE_EXPAND);
		hTreeItem = GetChildItem(hTreeParent);
	}
	SelectItem(hTreeParent);
	AddDirsToTree(m_szCurrentDir, hTreeParent);

	return TRUE;
}


void CDirectoryTree::AddDirsToTree(CString szStart, HTREEITEM htParent)
{
	//列举子目录,并增加到目录树
	CString         szStartDir;		
	BOOL            bFound;			
	HANDLE          hFile;			
	WIN32_FIND_DATA stFindData;		
	HTREEITEM       hTreeItem;		
	TV_INSERTSTRUCT tvstruct;		

	// 在目录名后增加*.*
	//szStartDir.Format("%s\\*.*", szStart);
	int len = strlen(szStart) - 1;
	if(szStart[len] != '\\')
		szStartDir.Format("%s\\*.*", szStart);
	else
		szStartDir.Format("%s*.*", szStart);

	// 检查目录是否为空
	hFile = FindFirstFile((LPCTSTR)szStartDir, &stFindData);
	if (INVALID_HANDLE_VALUE == hFile)
	{
		MessageBox("FindFirstFile() returned INVALID_HANDLE_VALUE", "DEBUG", MB_OK);
		return;
	}

	// 循环检查目录中的每一项,若为子目录,则增加到目录树
	while (INVALID_HANDLE_VALUE != hFile)
	{
		if (stFindData.dwFileAttributes & /*FILE_ATTRIBUTE_ARCHIVE*/FILE_ATTRIBUTE_DIRECTORY)
		{
			if ((0 == strcmp(stFindData.cFileName, ".")) || (0 == strcmp(stFindData.cFileName, "..")))
				;	// 跳过"." 和 ".."
			else
			{
				// 增加到目录树
				tvstruct.hParent = htParent;
				tvstruct.hInsertAfter = TVI_SORT;
				tvstruct.item.iImage = n_TreeIconClosed;
				tvstruct.item.iSelectedImage = n_TreeIconClosedSel;
				tvstruct.item.pszText = stFindData.cFileName;
				tvstruct.item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT;
				hTreeItem = InsertItem(&tvstruct);
			}
		}

		bFound = FindNextFile(hFile, &stFindData);
		if (!bFound)
			break;
	}
	FindClose(hFile);

	// 展开目录树
	Expand(htParent, TVE_EXPAND);

	return;
}

void CDirectoryTree::BuildPathFromTree(HTREEITEM htItem)
{
	//创建到选定项的完整路径,并设置m_szCurrentDir
	CString szFoo;
	CString szBar;
	HTREEITEM htItem1;
	HTREEITEM htItem2;

	szFoo = GetItemText(htItem);
	htItem1 = GetParentItem(htItem);
	while (NULL != htItem1)
	{
		szBar = GetItemText(htItem1);
		szFoo = szBar + "\\" + szFoo;
		htItem2 = GetParentItem(htItem1);
		htItem1 = htItem2;
	}

	// 拷贝新路径
	m_szCurrentDir = szFoo;

	// 给父窗口发送消息:路径已修改
	CWnd * pWnd = GetParent();
	if (pWnd)
		pWnd->PostMessage(WM_USER_PATHCHANGED);

	return;
}

void CDirectoryTree::DeleteChildren(HTREEITEM htItem/*路径尾*/)
{
	//删除刚展开的项的子项
	HTREEITEM hTreeChild1;	// A child of the item
	HTREEITEM hTreeChild2;	// A child of the item

	if (ItemHasChildren(htItem))
	{
		hTreeChild1 = GetChildItem(htItem);
		if (hTreeChild1)
		{
			if (ItemHasChildren(hTreeChild1))
			{
				hTreeChild2 = GetChildItem(hTreeChild1);
				while (hTreeChild2)
				{
					DeleteItem(hTreeChild2);
					hTreeChild2 = GetChildItem(hTreeChild1);
				}
			}

			DeleteItem(hTreeChild1);
		}
	}

	return;
}

void CDirectoryTree::DeletePeers(HTREEITEM htItem/*路径尾*/)
{
	//删除刚展开的项的同级项
	HTREEITEM hTreePeer;

	// 删除所有同级项
	hTreePeer = GetPrevSiblingItem(htItem);
	while (hTreePeer)
	{
		DeleteItem(hTreePeer);
		hTreePeer = GetPrevSiblingItem(htItem);
	}

	hTreePeer = GetNextSiblingItem(htItem);
	while (hTreePeer)
	{
		DeleteItem(hTreePeer);
		hTreePeer = GetNextSiblingItem(htItem);
	}

	return;
}

void CDirectoryTree::OnDblclk(NMHDR* pNMHDR, LRESULT* pResult) 
{
	//处理NM_DBLCLK消息(双击目录树中某项时发送)
	HTREEITEM hTreeItem;		// The item's Handle
	HTREEITEM hTreeChild;		// A child of the item
	UINT      uItemState;		// The item's current state
	int       nImage;			// The ID of the image in the list
	int       nSelImage;		// The ID of the selected image in the list

	// 获取双击项
	hTreeItem  = GetSelectedItem();
	uItemState = GetItemState(hTreeItem, TVIF_STATE);

	if (uItemState & TVIS_EXPANDED)
	{
		if (ItemHasChildren(hTreeItem))
		{
			hTreeChild = GetChildItem(hTreeItem);
			if (hTreeChild)
			{
				GetItemImage(hTreeChild, nImage, nSelImage);
				if ((nImage == n_TreeIconClosed) || 
					(nSelImage == n_TreeIconClosedSel))
				{
					*pResult = 1;
					return;
				}
			}
		}

		DeleteChildren(hTreeItem);
		BuildPathFromTree(hTreeItem);
		AddDirsToTree(m_szCurrentDir, hTreeItem);
	}
	else
	{
		SetItemImage(hTreeItem, 2, 3);

		DeletePeers(hTreeItem);
		BuildPathFromTree(hTreeItem);
		AddDirsToTree(m_szCurrentDir, hTreeItem);
	}

	*pResult = 1;
	return;
}

void CDirectoryTree::SetBitmapList(CImageList * pBmpList)
{
	SetImageList(pBmpList, TVSIL_NORMAL);
}

void CDirectoryTree::SetBitmapOrder(int nClosed = 0, int nClosedSel = 1, int nOpen = 2, int nOpenSel = 3)
{
	n_TreeIconClosed    = nClosed;
	n_TreeIconClosedSel = nClosedSel;
	n_TreeIconOpen      = nOpen;
	n_TreeIconOpenSel   = nOpenSel;
}

IMPLEMENT_DYNAMIC(CDirectoryTree, CTreeCtrl)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?