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 + -
显示快捷键?