Winapi Can';t使用TreeView_展开展开TreeView项

Winapi Can';t使用TreeView_展开展开TreeView项,winapi,treeview,Winapi,Treeview,我想让树视图的项目在项目展开时动态创建其子项。根据,我编写了以下代码: #define WIN32_LEAN_AND_MEAN #include <Windows.h> #include <windowsx.h> #include <CommCtrl.h> #pragma comment(lib, "ComCtl32.Lib") #pragma comment(linker, "\"/manifestdependency:type='win32' name

我想让树视图的项目在项目展开时动态创建其子项。根据,我编写了以下代码:

#define WIN32_LEAN_AND_MEAN

#include <Windows.h>
#include <windowsx.h>
#include <CommCtrl.h>

#pragma comment(lib, "ComCtl32.Lib")
#pragma comment(linker, "\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")

LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL MainWindow_OnCreate(HWND hWnd, LPCREATESTRUCT lpCreateStruct);
void MainWindow_OnDestroy(HWND hWnd);
void MainWindow_OnCommand(HWND hWnd, int id, HWND hWndCtl, UINT codeNotify);
LRESULT MainWindow_OnNotify(HWND hWnd, int idFrom, NMHDR *pnmhdr);

#define ID_TREEVIEW 100
#define ID_EXPAND 101

HTREEITEM root_item;

int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
{
    WNDCLASSEX wcex = { sizeof(wcex) };

    wcex.lpfnWndProc = WindowProc;
    wcex.hInstance = hInstance;
    LoadIconMetric(NULL, IDI_APPLICATION, LIM_LARGE, &wcex.hIcon);
    wcex.hCursor = static_cast<HCURSOR>(LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED));
    wcex.lpszClassName = TEXT("MainWindow");
    LoadIconMetric(NULL, IDI_APPLICATION, LIM_SMALL, &wcex.hIconSm);

    RegisterClassEx(&wcex);

    HWND hWnd = CreateWindowEx(0, wcex.lpszClassName, TEXT("TreeView Test"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND_DESKTOP, NULL, hInstance, NULL);
    ShowWindow(hWnd, nCmdShow);

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return msg.wParam;
}

LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        HANDLE_MSG(hWnd, WM_CREATE, MainWindow_OnCreate);
        HANDLE_MSG(hWnd, WM_DESTROY, MainWindow_OnDestroy);
        HANDLE_MSG(hWnd, WM_NOTIFY, MainWindow_OnNotify);
        HANDLE_MSG(hWnd, WM_COMMAND, MainWindow_OnCommand);
    default:
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
}

BOOL MainWindow_OnCreate(HWND hWnd, LPCREATESTRUCT lpCreateStruct)
{
    HWND h_treeview = CreateWindowEx(WS_EX_CLIENTEDGE, WC_TREEVIEW, TEXT("TreeView"), WS_CHILD | WS_VISIBLE | TVS_HASBUTTONS | TVS_LINESATROOT, 10, 10, 400, 400, hWnd, reinterpret_cast<HMENU>(ID_TREEVIEW), GetModuleHandle(NULL), NULL);

    TVINSERTSTRUCT tvis = { TVI_ROOT, TVI_LAST, { TVIF_TEXT | TVIF_CHILDREN } };
    tvis.item.pszText = TEXT("Root");
    tvis.item.cChildren = 1;
    root_item = TreeView_InsertItem(h_treeview, &tvis);

    CreateWindow(WC_BUTTON, TEXT("Expand"), WS_CHILD | WS_VISIBLE, 420, 10, 75, 23, hWnd, reinterpret_cast<HMENU>(ID_EXPAND), GetModuleHandle(NULL), NULL);

    return TRUE;
}

void MainWindow_OnDestroy(HWND hWnd)
{
    PostQuitMessage(0);
}

LRESULT MainWindow_OnNotify(HWND hWnd, int idFrom, NMHDR *pnmhdr)
{
    switch (pnmhdr->code)
    {
    case TVN_ITEMEXPANDING:
        {
            LPNMTREEVIEW pnmtv = reinterpret_cast<LPNMTREEVIEW>(pnmhdr);
            if (pnmtv->action == TVE_EXPAND)
            {
                LPCTSTR items[] = { TEXT("Item 1"), TEXT("Item 2"), TEXT("Item 3") };
                for (LPCTSTR item : items)
                {
                    TVINSERTSTRUCT tvis = { pnmtv->itemNew.hItem, TVI_LAST, { TVIF_TEXT } };
                    tvis.item.pszText = const_cast<LPTSTR>(item);
                    TreeView_InsertItem(pnmhdr->hwndFrom, &tvis);
                }
            }
            break;
        }
    case TVN_ITEMEXPANDED:
        {
            LPNMTREEVIEW pnmtv = reinterpret_cast<LPNMTREEVIEW>(pnmhdr);
            if (pnmtv->action == TVE_COLLAPSE)
            {
                TreeView_Expand(pnmhdr->hwndFrom, pnmtv->itemNew.hItem, TVE_COLLAPSE | TVE_COLLAPSERESET);
            }
            break;
        }
    }
    return 0;
}

void MainWindow_OnCommand(HWND hWnd, int id, HWND hWndCtl, UINT codeNotify)
{
    if (id == ID_EXPAND)
    {
        TreeView_Expand(GetDlgItem(hWnd, ID_TREEVIEW), root_item, TVE_EXPAND);
    }
}
#定义WIN32_LEAN_和_MEAN
#包括
#包括
#包括
#pragma注释(lib,“ComCtl32.lib”)
#pragma注释(链接器“\”/manifestdependency:type='win32'name='Microsoft.Windows.Common Controls'version='6.0.0.0'processorArchitecture='*'publicKeyToken='6595b64144ccf1df'language='*'\“”)
LRESULT回调WindowProc(HWND-HWND、UINT-uMsg、WPARAM-WPARAM、LPARAM-LPARAM);
BOOL main window_OnCreate(HWND-HWND,LPCREATESTRUCT-LPCREATESTRUCT);
空主窗口(HWND HWND);
void main window_OnCommand(HWND HWND,int id,HWND hWndCtl,UINT code通知);
LRESULT主窗口通知(HWND HWND、int idFrom、NMHDR*pnmhdr);
#定义ID_树视图100
#定义ID_展开101
HTREEITEM根项目;
int WINAPI wWinMain(_In_HINSTANCE HINSTANCE,_In_opt_HINSTANCE HPPreInstance,_In_LPWSTR lpCmdLine,_In_int nCmdShow)
{
WNDCLASSEX wcex={sizeof(wcex)};
wcex.lpfnWndProc=WindowProc;
wcex.hInstance=hInstance;
LoadIconMetric(NULL、IDI_应用程序、LIM_LARGE和wcex.hIcon);
wcex.hCursor=static_cast(LoadImage(空,IDC_箭头,IMAGE_光标,0,0,LR_共享));
wcex.lpszClassName=文本(“主窗口”);
LoadIconMetric(NULL、IDI_应用程序、LIM_SMALL和wcex.hIconSm);
注册类别(&wcex);
HWND HWND=CreateWindowEx(0,wcex.lpszClassName,文本(“TreeView测试”),WS_重叠窗口,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,HWND_桌面,NULL,hInstance,NULL);
显示窗口(hWnd、nCmdShow);
味精;
while(GetMessage(&msg,NULL,0,0))
{
翻译信息(&msg);
发送消息(&msg);
}
返回msg.wParam;
}
LRESULT回调WindowProc(HWND HWND、UINT uMsg、WPARAM WPARAM、LPARAM LPARAM)
{
开关(uMsg)
{
HANDLE_MSG(hWnd、WM_CREATE、main window_OnCreate);
处理消息(hWnd、WM销毁、主窗口存储);
处理消息(hWnd、WM\U NOTIFY、主窗口\U OnNotify);
HANDLE_MSG(hWnd、WM_命令、主窗口_OnCommand);
违约:
返回DefWindowProc(hWnd、uMsg、wParam、lParam);
}
}
BOOL main window_OnCreate(HWND HWND,LPCREATESTRUCT LPCREATESTRUCT)
{
HWND h_treeview=CreateWindowEx(WS_EX_CLIENTEDGE,WC_treeview,TEXT(“treeview”),WS_CHILD,WS|u VISIBLE,TVS|u hasbutons,TVS|u LINESATROOT,10,10,400,400,HWND,reinterpret_cast(ID_treeview),GetModuleHandle(NULL),NULL);
TVISERTSTRUCT tvis={TVI_根,TVI_最后,{TVIF_文本| TVIF_子项};
tvis.item.pszText=文本(“根”);
tvis.item.cChildren=1;
root_item=TreeView_插入项(h_TreeView和tvis);
CreateWindow(WC_按钮,文本(“展开”),WS_CHILD|WS_可见,420,10,75,23,hWnd,reinterpret_cast(ID_展开),GetModuleHandle(NULL),NULL);
返回TRUE;
}
空主窗口存储区(HWND HWND)
{
PostQuitMessage(0);
}
LRESULT主窗口通知(HWND HWND、int idFrom、NMHDR*pnmhdr)
{
开关(pnmhdr->代码)
{
案例TVN_项目扩展:
{
LPNMTREEVIEW pnmtv=重新解释铸件(pnmhdr);
如果(pnmtv->action==TVE_EXPAND)
{
LPCTSTR项目[]={TEXT(“项目1”)、TEXT(“项目2”)、TEXT(“项目3”)};
用于(LPCTSTR项目:项目)
{
TVISERTSTRUCT tvis={pnmtv->itemNew.hItem,TVI_LAST,{TVIF_TEXT};
tvis.item.pszText=常量(项目);
树视图插入项(pnmhdr->hwndFrom和tvis);
}
}
打破
}
案例TVN_项目扩展:
{
LPNMTREEVIEW pnmtv=重新解释铸件(pnmhdr);
如果(pnmtv->action==TVE_COLLAPSE)
{
树视图展开(pnmhdr->hwndFrom,pnmtv->itemNew.hItem,TVE_COLLAPSERESET);
}
打破
}
}
返回0;
}
void main window_OnCommand(HWND HWND,int id,HWND hWndCtl,UINT codeNotify)
{
if(id==id\u扩展)
{
TreeView_展开(GetDlgItem(hWnd,ID_TreeView),根项目,TVE_展开);
}
}
代码创建了一个带有树视图和按钮的窗口。单击按钮时,应展开TreeView的根项目


我可以第一次展开根项。单击“展开”按钮或单击根项目旁边的“+”符号即可。但是如果我折叠了根项目,我不能再次单击“展开”按钮来展开它,而“+”符号仍然有效。我注意到,虽然我使用了
TVE\u COLLAPSERESET
标志来清除
TVIS\u EXPANDEDONCE
标志,但在调用
TreeView\u Expand
之前,它仍然有该标志。根据,我想我需要
TVIS\u EXPANDEDONCE
标志保持未设置。我哪里做错了?

使用
PostMessage
重置
TVE\u COLLAPSERESET
标志:

PostMessage(pnmhdr->hwndFrom, TVM_EXPAND, TVE_COLLAPSE | TVE_COLLAPSERESET, reinterpret_cast<LPARAM>(pnmtv->itemNew.hItem));
PostMessage(pnmhdr->hwndFrom,TVM_展开,TVE_折叠| TVE_折叠设置,重新解释(pnmtv->itemNew.hItem));

据我所知,TreeView会发送
TVN_ITEMEXPANDED
通知,将消息发送回TreeView,这可能会导致问题。我们可能需要将消息延迟到当前消息处理完毕。

我觉得这完全符合逻辑。您使用了TVE_CollapseSet,所以当TVIS_再次展开时,您应该让它再次展开。@HansPassant我的意思是,在我调用
MainWindow_OnCommand
中的
TreeView_Expand
之前,根项已经有了
TVIS_EXPANDEDONCE
标志,即使我在根项折叠时重置了它,我不知道什么时候定的。为了使代码正常工作,我必须在哪里进行更改?当您在生成通知时递归到其代码中时,TreeView会变得非常古怪。庸医喜欢那样的问题。通用的解决方案是等到以后,PostMessage()给你自己就可以做到这一点。@Han