原版《遍歷資料夾並建成目錄樹》使用固定層級變數 (`strHTFir`~`strHtFif`),導致目錄深度超過 5 層時無法正確顯示。本文提供通用遞迴解法,移除層級限制。
// 原版:硬編碼層級變數,switch-case 判斷深度
switch(CallNum) {
case 1: item = tree.InsertItem(title, 0, 0, NULL); break;
case 2: item = tree.InsertItem(title, 0, 0, strHTFir); break;
case 3: item = tree.InsertItem(title, 0, 0, strHTSec); break;
// ... 最多支援 5 層
default: item = tree.InsertItem(title, 0, 0, strHtFif); break;
}
缺點:維護困難、深度固定、程式碼重複、擴充性差。
void CFileTreeDlg::BrowseDir(CString strDir, HTREEITEM hParent)
{
CFileFind finder;
CString searchPath = strDir;
// 確保路徑結尾有反斜線
if (searchPath.Right(1) != _T("\\")) searchPath += _T("\\");
searchPath += _T("*.*");
BOOL bFound = finder.FindFile(searchPath);
while (bFound) {
bFound = finder.FindNextFile();
// 跳過 . 和 ..
if (finder.IsDots()) continue;
CString strTitle = finder.GetFileName();
HTREEITEM hItem = m_FileTree.InsertItem(strTitle, 0, 0, hParent);
if (finder.IsDirectory()) {
// 遞迴處理子目錄,傳入當前項目作為父節點
BrowseDir(finder.GetFilePath(), hItem);
}
// 檔案節點無需遞迴,直接插入即可
}
finder.Close();
}
BOOL CFileTreeDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// ... 圖示列表初始化 ...
// 根節點傳入 NULL,自動建立樹狀結構
BrowseDir(_T("成績表"), NULL);
return TRUE;
}
| 特性 | 原版 | 改進版 |
|---|---|---|
| 最大深度 | 5 層 (硬編碼) | 無限制 (受限於堆疊/記憶體) |
| 程式碼行數 | ~120 行 | ~30 行 |
| 維護性 | 差 (重複 switch-case) | 優 (單一遞迴邏輯) |
| 效能 | 相同 | 相同 |
| 記憶體用量 | 固定變數 | 遞迴堆疊框架 |
struct DirNode { CString path; HTREEITEM hParent; };
std::stack dirStack;
dirStack.push({_T("成績表"), NULL});
while (!dirStack.empty()) {
DirNode node = dirStack.top(); dirStack.pop();
CFileFind finder;
CString search = node.path;
if (search.Right(1) != _T("\\")) search += _T("\\");
search += _T("*.*");
BOOL found = finder.FindFile(search);
while (found) {
found = finder.FindNextFile();
if (finder.IsDots()) continue;
HTREEITEM hItem = m_FileTree.InsertItem(finder.GetFileName(), 0, 0, node.hParent);
if (finder.IsDirectory()) {
dirStack.push({finder.GetFilePath(), hItem});
}
}
}