如何在 C++ 中将多个单选按钮分为 3 组?

how to group many radio buttons into 3 groups in C++?

我的目标是创建 5 组单选按钮(我知道它与标题相矛盾,但你仍然明白这一点)仅使用 Win32 API(所以没有 window 形式供用户选择在这里)。

我尝试使用 groupbox 和 SetWindowLongPtr 的组合,但它仍然没有按预期工作(请注意,我使用 GWLP_WNDPROC 作为索引)。如果我对一个组框使用 SetWindowLongPtr,那么该组框就消失了,其他一切都按预期工作。

我可以使用“虚拟”分组框,但它会降低我的代码效率。有些人可能会建议使用 WS_GROUP 但它仅适用于有 2 组单选按钮的情况(我认为)。而且我也不喜欢使用资源,所以这个问题有什么解决办法,还是我只能坚持使用“虚拟”组框?

最小可重复样本:

#include <Windows.h>
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wp, LPARAM lp)
{
    switch (uMsg)
    {
    default:
        return DefWindowProc(hwnd, uMsg, wp, lp);
    }
}
int WINAPI wWinMain(HINSTANCE hinst, HINSTANCE hiprevinst, PWSTR nCmdLine, int ncmdshow)
{
    const wchar_t CLASS_NAME[] = L"Sample";

    WNDCLASS wc = { };

    wc.lpfnWndProc = WndProc;
    wc.hInstance = hinst;
    wc.lpszClassName = CLASS_NAME;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);


    RegisterClass(&wc);
    HWND hwnd = CreateWindowEx(
        0,
        CLASS_NAME,
        L"Sample window",
        WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,            // Window style


        CW_USEDEFAULT, CW_USEDEFAULT, 800, 600,

        NULL,
        NULL,
        hinst,
        NULL);
    HWND groupbox = CreateWindowEx(0, L"Button", L"Groupbox", WS_VISIBLE | WS_CHILD | BS_GROUPBOX, 10, 10, 100, 100, NULL, NULL, hinst, NULL);
    HWND radiobutton1 = CreateWindowEx(0, L"Button", L"Groupbox", WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON, 10, 10, 60, 60, groupbox, NULL, hinst, NULL);
    SetWindowLongPtr(groupbox, GWLP_WNDPROC, (LONG)WndProc);
    SendMessage(groupbox, NULL, NULL, TRUE);
    ShowWindow(hwnd, ncmdshow);
    MSG msg;
    while (GetMessage(&msg, NULL, NULL, NULL))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return 0;
}

由于我删除了太多必要的功能,出于某种原因,您需要转到任务管理器并终止名为“Autoclicker”的进程才能再次重新编译它

确保处理 WM_DESTROY 否则 window 将无法正常关闭。

单选按钮、所有子对话框项和所有子 windows 应在父 window 的 WM_CREATE 部分中创建。他们需要父 window.

HWND 句柄

SetWindowLongPtr(.. GWLP_WNDPROC ...) 是一种用于子类化的旧方法。您的用法不正确。反正你不需要它。

不清楚 SendMessage(groupbox, NULL, NULL, TRUE); 应该做什么。

只需添加单选按钮,确保第一个单选按钮已添加 WS_TABSTOP|WS_GROUP,如下所示

LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wp, LPARAM lp)
{
    switch (uMsg)
    {
    case WM_CREATE:
    {
        HINSTANCE hinst = GetModuleHandle(0);

        auto add = [&](const wchar_t* name, 
            int id, int x, int y, int w, int h, bool first = false)
        {
            DWORD style = WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON;
            if (first) style |= WS_GROUP | WS_TABSTOP;
            return CreateWindowEx(0, L"Button", name, style,
                x, y, w, h, hwnd, (HMENU)id, hinst, NULL);
        };

        HWND groupbox1 = CreateWindowEx(0, L"Button", L"Groupbox1",
          WS_VISIBLE | WS_CHILD | BS_GROUPBOX, 2, 2, 250, 120, hwnd, NULL, hinst, NULL);
        HWND radio1 = add(L"radio1", 1, 10, 30, 200, 20, true);
        HWND radio2 = add(L"radio2", 2, 10, 51, 200, 20);
        HWND radio3 = add(L"radio3", 3, 10, 72, 200, 20);
        HWND radio4 = add(L"radio4", 4, 10, 93, 200, 20);

        HWND groupbox2 = CreateWindowEx(0, L"Button", L"Groupbox2",
          WS_VISIBLE | WS_CHILD | BS_GROUPBOX, 280, 2, 250, 120, hwnd, NULL, hinst, NULL);
        HWND radio11 = add(L"radio1", 11, 300, 30, 200, 20, true);
        HWND radio12 = add(L"radio2", 12, 300, 51, 200, 20);
        HWND radio13 = add(L"radio3", 13, 300, 72, 200, 20);
        HWND radio14 = add(L"radio4", 14, 300, 93, 200, 20);

        return 0;
    }

    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;

    default:
        return DefWindowProc(hwnd, uMsg, wp, lp);
    }
}
int WINAPI wWinMain(HINSTANCE hinst, HINSTANCE hiprevinst, PWSTR nCmdLine, int ncmdshow)
{
    const wchar_t CLASS_NAME[] = L"Sample";
    WNDCLASS wc = { };
    wc.lpfnWndProc = WndProc;
    wc.hInstance = hinst;
    wc.lpszClassName = CLASS_NAME;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    RegisterClass(&wc);
    HWND hwnd = CreateWindowEx(0, CLASS_NAME, L"Sample window",
        WS_OVERLAPPEDWINDOW, 0, 0, 800, 600,
        NULL, NULL, hinst, NULL);
    ShowWindow(hwnd, ncmdshow);
    MSG msg;
    while (GetMessage(&msg, NULL, NULL, NULL))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return 0;
}