Search code examples
c++winapiwin32gui

WinAPI - button cannot be clicked


I want to make a panel, which groups buttons by itself:

HWND my_panel = CreateWindow(
    "STATIC",
    "",
    WS_VISIBLE | WS_CHILD | WS_BORDER,
    30,
    100,
    300,
    300,
    main_window, // main dialog
    NULL,
    ( HINSTANCE ) GetWindowLong( main_window, GWL_HINSTANCE ),
    NULL
);

Then I add a button to this panel:

HWND button_in_a_group = CreateWindow(
    "BUTTON",
    "Hello world",
    WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
    20,
    20,
    50,
    50,
    my_panel, // as a child for above
    NULL,
    ( HINSTANCE ) GetWindowLong( main_window, GWL_HINSTANCE ),
    NULL
);

When I click the button, it doesn't send a WM_COMMAND but WM_PARENTNOTIFY to callback function. Then, if I press Enter, it works - WM_COMMAND is sent by the button.

How to enable mouse click on nested button, and why nested windows doesn't work as expected?


Solution

  • Messages are sent to parent window. In this case the static windows is the button's parent. So the main window is not receiving button messages, except WM_PARENTNOTIFY.

    You can subclass the static window:

    SetWindowSubclass(my_panel, ChildProc, 0, 0);
    

    Define a ChildProc to catch the button messages. See also Subclassing Controls

    The button also requires an identifier as follows:

    CreateWindow("BUTTON", "Hello world", ... my_panel, HMENU(BUTTON_ID) ...);
    

    WM_COMMAND message is sent to ChildProc when button is clicked. The BN_CLICKED notification carries BUTTON_ID

    Note, SetWindowSubclass needs additional header and library:

    #include <CommCtrl.h>
    #pragma comment(lib, "Comctl32.lib") //Visual Studio option for adding libraries
    ...
    LRESULT CALLBACK ChildProc(HWND hwnd, UINT msg, 
        WPARAM wParam, LPARAM lParam, UINT_PTR, DWORD_PTR)
    {
        switch(msg) {
        case WM_COMMAND:
            switch(LOWORD(wParam)) {
            case BUTTON_ID:
                MessageBox(0, "hello world", 0, 0);
                break;
            }
            break;
        case WM_NCDESTROY:
            RemoveWindowSubclass(hwnd, ChildProc, 0);
            break;
        }
        return DefSubclassProc(hwnd, msg, wParam, lParam);
    }