C++ 用驱动器上的目录和文件填充TreeView

C++ 用驱动器上的目录和文件填充TreeView,c++,winapi,treeview,directory,subdirectory,C++,Winapi,Treeview,Directory,Subdirectory,我的win32 api项目中有一个树视图。 我想用驱动器上的目录和文件填充树视图。使用一个函数,我获得所有可用的驱动器,然后以驱动器号作为参数调用此函数: bool ListDirectoryContents(const char *sDir) { WIN32_FIND_DATA fdFile; HANDLE hFind = 0; vector<string> FileNames; char sPath[2048]; sprintf(sPat

我的win32 api项目中有一个树视图。 我想用驱动器上的目录和文件填充树视图。使用一个函数,我获得所有可用的驱动器,然后以驱动器号作为参数调用此函数:

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;
}
bool ListDirectoryContents(const char*sDir)
{
WIN32_FIND_数据文件;
句柄hFind=0;
矢量文件名;
char sPath[2048];
sprintf(sPath,“%s\\*.*”,sDir);
if((hFind=FindFirstFile(sPath,&fdFile))==无效的句柄值)
{
printf(“未找到路径:[%s]\n”,sDir);
返回false;
}
做
{
如果(strcmp(fdFile.cFileName,“.”)=0和&strcmp(fdFile.cFileName,“…”)!=0)
{
sprintf(sPath,“%s%s”,sDir,fdFile.cFileName);
if((fdFile.dwFileAttributes和文件属性目录))
{
if((fdFile.dwFileAttributes&FILE\u attributes\u HIDDEN)=0)
{
//目录
Additemtree(hwndTree,sPath,2);
//文件名。插入(sPath);
//ListDirectoryContents(sPath);//递归
}
}
其他的
{
if((fdFile.dwFileAttributes&FILE\u attributes\u HIDDEN)=0)
{
//档案
//Additemtree(hwndTree,sPath,2);
文件名。推回(sPath);
}
}
}
}
while(FindNextFile(hFind,&fdFile));
FindClose(hFind);
对于(向量::迭代器文件名=文件名.begin();文件名!=文件名.end();++FileName)
{
AddItemToTree(HwnTree,(char*)文件名->c_str(),2);
}
返回true;
}
我使用的文件名向量首先列出目录,然后列出文件

函数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;
}
HTREEITEM AddItemToTree(HWND-hwndTree,char*text,int-nLevel)
{
TVINSERTSTRUCT tvins;
静态HTREEITEM hPrev=(HTREEITEM)TVI_优先;
静态HTREEITEM hRootItem=NULL;
静态HTREEITEM hPrevLev2Item=NULL;
//tvi.mask=TVIF_TEXT | TVIF_IMAGE | TVIF_PARAM;
tvi.mask=TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIS_stateMagemask;
tvi.iImage=AddIconToTree(hwndTree,文本);
tvi.iSelectedImage=tvi.iImage;
tvi.pszText=GetFileNameFromPath(text);
tvins.hInsertAfter=hPrev;
tvins.item=tvi;
如果(nLevel==1)
{
tvins.hParent=TVI_根;
}
else if(nLevel==2)
{
tvins.hParent=hRootItem;
}
其他的
{
tviSetup;
tviSetup.hItem=hPrev;
tviSetup.mask=TVIF_参数;
TviItem*tviLocal=&tviSetup;
TreeView_GetItem(HwnTree、tviLocal);
如果(nLevel>tviLocal->LPRAM)
{
tvins.hParent=hPrev;
}
其他的
{
HTREEITEM hPrevLocal=TreeView\u GetParent(hwndTree,hPrev);
tviLocal->hItem=hPrevLocal;
TreeView_GetItem(HwnTree、tviLocal);
for(int i=nLevel;i lParam;)
{
HTREEITEM hPrevLocalTemp=TreeView_GetParent(hwndTree,hPrevLocal);
hPrevLocal=hPrevLocalTemp;
tviLocal->hItem=hPrevLocal;
TreeView_GetItem(HwnTree、tviLocal);
}
tviLocal->mask=TVIF\u文本;
TreeView_GetItem(HwnTree、tviLocal);
tvins.hParent=hPrevLocal;
}
}
hPrev=(HTREEITEM)SendMessage(hwndTree,TVM_插入项,0,(lpram)(lptvisertstruct)和tvins);
如果(hPrev==0)
{
返回false;
}
如果(nLevel==1)
{
hRootItem=hPrev;
}
返回hPrev;
}
问题是,如果我在
ListDirectoryContents
函数中使用递归调用,则需要很长时间才能填充树视图中的所有目录和文件

所以我认为它可以像这样工作:

  • 首先,我要添加根(所有驱动器,如C:\、D:\…)
  • 我会在驱动器中找到所有子目录和文件,并将它们添加为驱动器根目录的子目录和文件
  • 然后,如果我展开根节点,它将找到以前找到的驱动器子目录的所有子目录,依此类推
但是问题来了,我如何在某个地方插入一些项目?我的意思是
AddItemToTree
函数中的第三个参数是什么

有没有更简单的方法用目录填充TreeView?
提前谢谢大家

通常,执行此操作的方法根本不是使用
nLevel
参数,而是使用
hItemParent
参数

也就是说,当您调用
AddItemToTree
时,您将向函数传递与父项对应的
HTREEITEM
。当您插入新项目时,这将传递给
tvins.hParent
成员

因此,当您当前拥有
nLevel==1
时,您将拥有
AddItemToTree(HwnTree,“text”,TVI_ROOT)

要在展开子文件夹时填充它,需要一个监视通知的
WM_NOTIFY
处理程序

当您收到此消息时,它会告诉您展开了哪个项,这是您要传递给
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);
    }
案例WMU通知:
if(((LPNMHDR)lParam)->code==TVN\u ITEMEXPANDED)
{
//找出阅读的路径,然后。。。
AddItemToTree(hwndTree,((LPNMTREEVIEW)lParam)->itemNew.hItem;
}

还有一个
TVN\u itemsexpanding
通知,在节点展开之前触发,而
TVN\u itemsexpanded
在节点展开之后触发<例如,code>TVN\u itemsexpanding可以取消扩展,但是
TVN\u itemsexpanded
不能。根据应用程序的特殊需要,
TVN\u itemsexpansing
可能是填充子节点的更好选择