代码之家  ›  专栏  ›  技术社区  ›  VZ.

如何使用Win32 API在自定义弹出窗口中放置编辑控件?

  •  3
  • VZ.  · 技术社区  · 6 年前

    WS_CHILD )桌面的窗口,类似于真正的组合框使用的“组合框”窗口。这工作得很好,但编辑窗口似乎只是拒绝接受焦点,当它被放入这样的下拉窗口。例如,它被启用并对鼠标右键单击作出反应,但单击它或调用它 SetFocus() 失败(后者将最后一个错误设置为 ERROR_INVALID_PARAMETER ).

    因为这一点,也因为自定义弹出窗口在许多例子中的实现方式,包括Raymond Chen的 fakemenu sample WS_POPUP ,主应用程序窗口为所有者。当弹出窗口显示时,从所有者窗口窃取激活是一个已知的问题,但是可以通过返回 MA_NOACTIVATE WM_MOUSEACTIVATE 将焦点设置为自身,这将停用父窗口。

    我的问题是怎样才能防止这种情况发生?我知道这是可以做到的,因为WinForms ToolStripManager 允许在不停用父窗口的情况下编辑下拉列表中的文本,它还使用 弹出窗口的样式。但它是怎么做到的呢?

    1 回复  |  直到 6 年前
        1
  •  2
  •   Barmak Shemirani    6 年前

    有人在评论中提出了解决办法 WM_NCACTIVATE " 这应该如下面的示例所示。

    HostProc )将收到 WM\U激活 信息。主持人将寻找 "menuclass" DefWindowProc(hwnd, WM_NCACTIVATE, TRUE, lparam); 防止主机窗口的标题栏被绘制为非活动状态。

    你还需要处理 WM\U激活 在假菜单窗口中。当菜单窗口失去焦点时, 由接收 MenuProc ,此时菜单可以自动关闭。

    #include <windows.h>
    
    const wchar_t* menuclass = L"menuclass";
    
    LRESULT CALLBACK MenuProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
    {
        switch(msg)
        {
        case WM_CREATE:
            CreateWindow(L"Edit", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER, 10, 10, 160, 30,
                hwnd, NULL, NULL, NULL);
            break;
    
        case WM_NCACTIVATE:
        {
            if(!wparam)
            {
                //close the menu if its losing focus
                PostMessage(hwnd, WM_CLOSE, 0, 0);
    
                //tell parent to paint inactive, if user clicked on a different program
                POINT pt;
                GetCursorPos(&pt);
                HWND hit = WindowFromPoint(pt);
                HWND hparent = GetParent(hwnd);
                if(hit != hparent && !IsChild(hparent, hit))
                    DefWindowProc(hparent, WM_NCACTIVATE, FALSE, 0);
            }
            break;
        }
    
        case WM_LBUTTONDOWN:
            PostMessage(hwnd, WM_CLOSE, 0, 0);
            break;
        //also handles other mouse/key messages associated with a menu...
        }
    
        return DefWindowProc(hwnd, msg, wparam, lparam);
    }
    
    LRESULT CALLBACK HostProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
    {
        switch(msg)
        {
        case WM_NCACTIVATE:
            //paint the window as active when custom menu starts
            if(!wparam && FindWindow(menuclass, NULL))
                return DefWindowProc(hwnd, WM_NCACTIVATE, TRUE, lparam);
            break;
        case WM_RBUTTONUP:
        {
            //show the custom menu
            POINT pt;
            GetCursorPos(&pt);
            CreateWindow(menuclass, NULL, WS_VISIBLE | WS_POPUP | WS_BORDER,
                pt.x, pt.y, 200, 400, hwnd, 0, 0, 0);
            return 0;
        }
        case WM_DESTROY: 
            PostQuitMessage(0);
            return 0;
        }
    
        return DefWindowProc(hwnd, msg, wparam, lparam);
    }
    
    int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, LPTSTR, int)
    {
        WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };
        wcex.hInstance = hInstance;
        wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
        wcex.lpfnWndProc = HostProc;
        wcex.lpszClassName = L"hostwnd";
        RegisterClassEx(&wcex);
    
        wcex.lpfnWndProc = MenuProc;
        wcex.lpszClassName = menuclass;
        RegisterClassEx(&wcex);
    
        CreateWindow(L"hostwnd", L"Right click for menu ...", 
            WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0, 0, 600, 400, 0, 0, hInstance, 0);
    
        MSG msg;
        while(GetMessage(&msg, NULL, 0, 0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    
        return (int)msg.wParam;
    }