【问题标题】:WinAPI - button cannot be clickedWinAPI - 无法单击按钮
【发布时间】:2018-04-10 06:05:21
【问题描述】:

我想做一个面板,它自己对按钮进行分组:

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
);

然后我在这个面板中添加一个按钮:

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
);

当我单击按钮时,它不会向回调函数发送WM_COMMAND 而是WM_PARENTNOTIFY。然后,如果我按 Enter 键,它就会起作用 - WM_COMMAND 由按钮发送。

如何在嵌套按钮上启用鼠标单击,以及为什么嵌套窗口不能按预期工作?

【问题讨论】:

  • 回调函数 ?按钮将消息发送到父窗口,而不是某些功能

标签: c++ winapi win32gui


【解决方案1】:

消息被发送到父窗口。在这种情况下,静态窗口是按钮的父级。所以主窗口没有收到按钮消息,除了WM_PARENTNOTIFY

你可以继承静态窗口:

SetWindowSubclass(my_panel, ChildProc, 0, 0);

定义一个ChildProc 来捕获按钮消息。另见Subclassing Controls

按钮还需要一个标识符,如下所示:

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

WM_COMMAND 消息在单击按钮时发送到ChildProcBN_CLICKED 通知带有BUTTON_ID

注意,SetWindowSubclass 需要额外的头文件和库:

#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);
}

【讨论】:

  • STATIC 控件还需要WS_EX_CONTROLPARENT extended window style 以便键盘导航起作用。可以说更好的解决方案是根本不引入子/父关系,并使框架和按钮成为兄弟。它只是更容易管理,并且不会改变感知的视觉表现。
  • 我尝试了SetWindowLongPtr( my_panel, GWLP_WNDPROC, ( LONG_PTR ) DlgMain );,因为SetWindowSubclass 没有编译。它有效 - 但现在 my_panel 似乎是隐形的。我错过了什么? ShowWindow 无效。
  • 您可能错过了标头和库。查看更新答案。
  • @BarmakShemirani 完美,但我必须在#include &lt;windows.h&gt; 之前#define _WIN32_WINNT 0x0501。值得指出的是,这需要 ComCtl32.dll 的 5.81 或更新版本。
  • 是的,0x0501 适用于 Windows XP,而 ComCtl32.dll 5.81 早在那时就已经可用。将其设为最低目标是合理的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-28
  • 1970-01-01
  • 2020-07-30
  • 2020-12-05
相关资源
最近更新 更多