У меня есть TreeView в моем проекте Win32 API.
Я хочу заполнить это TreeView каталогами и файлами на дисках. Используя одну функцию, я получаю все доступные диски и затем вызываю эту функцию с буквами дисков в качестве параметра:
bool ListDirectoryContents(const char *sDir)
{
WIN32_FIND_DATA fdFile;
HANDLE hFind = 0;
vector<string> FileNames;
char sPath[2048];
sprintf(sPath, "%s\\*.*", sDir);
if((hFind = FindFirstFile(sPath, &fdFile)) == INVALID_HANDLE_VALUE)
{
printf("Path not found: [%s]\n", sDir);
return false;
}
do
{
if(strcmp(fdFile.cFileName, ".") != 0 && strcmp(fdFile.cFileName, "..") != 0)
{
sprintf(sPath, "%s%s", sDir, fdFile.cFileName);
if((fdFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
if((fdFile.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) == 0)
{
// Directories
AddItemToTree(hwndTree, sPath, 2);
//FileNames.insert(sPath);
//ListDirectoryContents(sPath); // Recursion
}
}
else
{
if((fdFile.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) == 0)
{
//Files
//AddItemToTree(hwndTree, sPath, 2);
FileNames.push_back(sPath);
}
}
}
}
while(FindNextFile(hFind, &fdFile));
FindClose(hFind);
for(vector<string>::iterator FileName = FileNames.begin(); FileName != FileNames.end(); ++FileName)
{
AddItemToTree(hwndTree, (char*)FileName->c_str(), 2);
}
return true;
}
Вектор для FileNames, который я использую, чтобы сначала перечислить каталоги, а затем файлы.
Функция AddItemToTree:
HTREEITEM AddItemToTree(HWND hwndTree, char *text, int nLevel)
{
TVINSERTSTRUCT tvins;
static HTREEITEM hPrev = (HTREEITEM)TVI_FIRST;
static HTREEITEM hRootItem = NULL;
static HTREEITEM hPrevLev2Item = NULL;
//tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_PARAM;
tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIS_STATEIMAGEMASK;
tvi.iImage = AddIconToTree(hwndTree, text);
tvi.iSelectedImage = tvi.iImage;
tvi.pszText = GetFileNameFromPath(text);
tvins.hInsertAfter = hPrev;
tvins.item = tvi;
if(nLevel == 1)
{
tvins.hParent = TVI_ROOT;
}
else if(nLevel == 2)
{
tvins.hParent = hRootItem;
}
else
{
TVITEM tviSetup;
tviSetup.hItem = hPrev;
tviSetup.mask = TVIF_PARAM;
TVITEM * tviLocal = &tviSetup;
TreeView_GetItem(hwndTree, tviLocal);
if(nLevel > tviLocal->lParam)
{
tvins.hParent = hPrev;
}
else
{
HTREEITEM hPrevLocal = TreeView_GetParent(hwndTree, hPrev);
tviLocal->hItem = hPrevLocal;
TreeView_GetItem(hwndTree, tviLocal);
for(int i = nLevel; i <= tviLocal->lParam;)
{
HTREEITEM hPrevLocalTemp = TreeView_GetParent(hwndTree, hPrevLocal);
hPrevLocal = hPrevLocalTemp;
tviLocal->hItem = hPrevLocal;
TreeView_GetItem(hwndTree, tviLocal);
}
tviLocal->mask = TVIF_TEXT;
TreeView_GetItem(hwndTree, tviLocal);
tvins.hParent = hPrevLocal;
}
}
hPrev = (HTREEITEM)SendMessage(hwndTree, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins);
if(hPrev == 0)
{
return false;
}
if(nLevel == 1)
{
hRootItem = hPrev;
}
return hPrev;
}
Проблема в том, что если бы я использовал рекурсивный вызов в ListDirectoryContents
функция, это займет очень много времени, чтобы заполнить все каталоги и файлы в TreeView.
Поэтому я подумал, что это может работать так:
Но тут возникает проблема, как я могу вставить какой-то предмет в определенное место? Я имею в виду, что будет третьим параметром в AddItemToTree
функционировать?
Есть ли более простой способ заполнить TreeView с каталогами?
Спасибо всем заранее!
Обычно то, как вы это делаете, не nLevel
параметр на всех, но с hItemParent
параметр.
То есть когда звонишь AddItemToTree
Вы бы передали функцию HTREEITEM
соответствующий родительскому элементу. Это было бы накормлено до tvins.hParent
член при вставке нового элемента.
Итак, где у вас есть nLevel == 1
вы бы AddItemToTree(hwndTree, "text", TVI_ROOT)
,
Чтобы заполнить дочернюю папку, когда она развернута, вам нужно WM_NOTIFY
обработчик, который следит за TVN_ITEMEXPANDED
уведомление.
Когда вы получаете это сообщение, оно говорит вам, какой элемент раскрыт — и это параметр, который вы должны передать AddItemToTree
,
case WM_NOTIFY:
if (((LPNMHDR)lParam)->code == TVN_ITEMEXPANDED)
{
// work out the path to read, and then ...
AddItemToTree(hwndTree, <path>, ((LPNMTREEVIEW)lParam)->itemNew.hItem);
}