【问题标题】:WM_COMMAND unabled to fulfil request unless clicked outside of application window,除非在应用程序窗口外单击,否则 WM_COMMAND 无法完成请求,
【发布时间】:2021-01-09 05:31:59
【问题描述】:

目前正在创建一个仅输出物理方程 + 一些历史和数学背景的应用程序。我遇到了这个问题,我使用WS_EX_CLIENTEDGE 来整理这些术语的列表,当我在屏幕上单击所述术语时,期望出现一个定义,直到我单击它才输出任何内容在应用程序窗口之外(Visual Studio、调试终端等)

Cursed gif

我想明确表示,由于 GUI 美学,我不想使用按钮。

普通的 WINAPI 应用程序创建

int main(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
    const wchar_t CLASS_NAME[] = L"Application";
    WNDCLASS window = { 0 };
    MSG msg = { 0 };

    window.lpfnWndProc = WindowProc;
    window.lpszClassName = CLASS_NAME;
    window.hInstance = hInstance;

    RegisterClass(&window);

    HWND hWnd = CreateWindow(CLASS_NAME, L"PhysicsBox", WS_VISIBLE | WS_OVERLAPPEDWINDOW, 100, 100, 600, 500, NULL, NULL, NULL, NULL);
    ShowWindow(hWnd, nCmdShow);
    //aMessageBox = CreateWindowW(L"edit", L" ", WS_VISIBLE | WS_CHILD | WS_BORDER, 165, 150, 400, 300, hWnd, NULL, NULL, NULL);

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


    return 0;
}

Juicy 窗口程序

LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_CREATE:
        aListBox(hWnd);
        break;
    case WM_COMMAND:
        if (SendMessage(hList, LB_GETSEL, FORCE, 0))
        {
            CreateWindowW(L"static", L"Simple Text", WS_VISIBLE | WS_CHILD | WS_BORDER | SS_CENTER, 200, 100, 100, 100, hWnd, NULL, NULL, NULL);
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0); break;
    default:
        return DefWindowProc(hWnd, uMsg, wParam, lParam);

    }
}

创建列表的 void 函数

void aListBox(HWND hWnd)
{
    hList = CreateWindowEx(WS_EX_CLIENTEDGE, L"ListBox", L" ", WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_AUTOVSCROLL, 3, 4, 150, 300, hWnd, (HMENU)ID_LISTBOX, 0, 0);
    SendMessageW(hList, LB_ADDSTRING, FORCE, (LPARAM)L"Force");
    SendMessageW(hList, LB_ADDSTRING, WORK, (LPARAM)L"Work");
    SendMessageW(hList, LB_ADDSTRING, POWER, (LPARAM)L"Power");
    SendMessageW(hList, LB_ADDSTRING, EFFICENCY, (LPARAM)L"Efficency");
    SendMessageW(hList, LB_ADDSTRING, POTENTIALENERGY, (LPARAM)L"Potential Energy");
    SendMessageW(hList, LB_ADDSTRING, HOOKESLAW, (LPARAM)L"Hooke's Law");

}

注意:放置在“aListBox(HWND hWnd)”SendMessageW 参数中的 MSG('s) 是按数字顺序排列的(从 0 开始)。所以 FORCE = 0,WORK = 1,依此类推。如果有帮助,hList 也是一个全局变量:P

【问题讨论】:

    标签: c++ windows winapi


    【解决方案1】:

    创建的列表框没有LBS_NOTIFY 样式,因此不会向父窗口发送LBN_SELCHANGE 通知。将aListBox 中的第一行更改为以下内容可解决此问题。

    hList = CreateWindowEx(WS_EX_CLIENTEDGE, L"ListBox", L" ", WS_CHILD | LBS_NOTIFY | WS_VISIBLE | WS_VSCROLL | ES_AUTOVSCROLL, 3, 4, 150, 300, hWnd, (HMENU)ID_LISTBOX, 0, 0);
    

    此外,WindowProc 不会在所有代码路径上都返回结果,并且不会为它不处理的所有消息调用DefWindowProc。下面更正了这些问题。

    LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        switch (uMsg)
        {
        case WM_CREATE:
            aListBox(hWnd);
            return 0;
        case WM_COMMAND:
            if (SendMessage(hList, LB_GETSEL, FORCE, 0))
            {
                HWND hText = CreateWindowW(L"static", L"Simple Text", WS_VISIBLE | WS_CHILD | WS_BORDER | SS_CENTER, 200, 100, 100, 100, hWnd, NULL, NULL, NULL);
                ShowWindow(hText, SW_SHOW);
                return 0;
            }
            break;
        case WM_DESTROY:
            PostQuitMessage(0); 
            return 0;
        }
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    

    代码还有其他问题,例如WindowProc 不会检查WM_COMMAND 通知代码,并且会愉快地一遍又一遍地创建新窗口,但假设这是仅用于展示特定的最小代码问题中的问题。


    [ EDIT ] OP 在运行 没有 LBS_NOTIFY 样式位时描述的行为大多是偶然的,因为 WM_COMMAND 没有检查 WPARAM通知代码。发生的情况是,在应用程序窗口外单击会导致列表框发送LBN_KILLFOCUS 通知(无论LBS_NOTIFY 是如何发送的)。 那个通知是触发WindowProc中的WM_COMMAND代码的通知,当FORCE项目被选中时创建静态控件。

    【讨论】:

      猜你喜欢
      • 2021-04-07
      • 2011-09-06
      • 1970-01-01
      • 1970-01-01
      • 2017-01-10
      • 1970-01-01
      • 2013-02-13
      • 2017-11-23
      • 2022-10-02
      相关资源
      最近更新 更多