如何使创建的没有 WS_VISIBLE 的 Win32 控件可见?
How to make a Win32 control created without WS_VISIBLE visible?
假设 hCtl
是在 没有 WS_VISIBLE 标志的情况下创建的控件的句柄,例如:
HWND hCtl = CreateWindowEx(0, WC_STATIC, L"some text",
WS_CHILD | SS_NOTIFY, // no WS_VISIBLE flag
0, 0, 0, 0, hWndParent, (HMENU)IDC_STATIC1, g_hInst, 0);
是否有比以下更直接的方式使其可见?
void make_visible(HWND hCtl, HWND hWndParent) {
SetWindowLongPtr(hCtl, GWL_STYLE,
GetWindowLongPtr(hCtl, GWL_STYLE) | WS_VISIBLE);
RECT rc{};
GetClientRect(hCtl, &rc);
MapWindowRect(hCtl, hWndParent, &rc);
InvalidateRect(hWndParent, &rc, TRUE);
UpdateWindow(hWndParent);
//ShowWindow(hCtl, SW_SHOW); // no use: does not update window
//SetWindowPos(hCtl, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); // no use: does not update window
}
使 window 可见的正常方法只是函数 ShowWindow。无需处理标志等。通常您使用 SW_SHOW
作为 child window 的参数。检查其他值并使用您认为合适的值。
如果 window 有一个可见的矩形并且没有被另一个 window 覆盖,它将显示出来。甚至不需要 UpdateWindow 调用。 window 将出现在下一个绘制周期中。如果您的控件的大小为 0,0,0,0(创建时),它将永远不会显示。
如果 window 在不同的线程上,则还有一个 ShowWindowAsync 函数可用于避免阻塞。
顺便说一句:我不明白你试图使 parent window 区域无效的原因。如果有 child window 剪辑 (WS_CLIPCHILDREN
) 它没有效果。
我认为您的问题是您自己明确设置了 WS_VISIBLE
样式,然后 然后 调用 ShowWindow
,这让 Windows 感到困惑相信 window 已经可见,不需要重新绘制。
只需调用ShowWindow
。 There should be no need to explicitly set WS_VISIBLE
yourself because ShowWindow
already does it。您不需要强行重新绘制控件。
此外,如果您发现某些需要显式使您的控件无效,只需执行 InvalidateRect(hCtl, NULL)
就足够了,而不必理会 GetClientRect
和 MapWindowRect
。
要使子控件可见,请像这样调用 SetWindowPos
:
SetWindowPos(hCtl, 0, 0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);
您调用 MapWindowRect
、InvalidateRect
、UpdateRect
等的代码应删除。
也许您遇到的真正问题是您创建了宽度和高度为零的静态控件。
假设 hCtl
是在 没有 WS_VISIBLE 标志的情况下创建的控件的句柄,例如:
HWND hCtl = CreateWindowEx(0, WC_STATIC, L"some text",
WS_CHILD | SS_NOTIFY, // no WS_VISIBLE flag
0, 0, 0, 0, hWndParent, (HMENU)IDC_STATIC1, g_hInst, 0);
是否有比以下更直接的方式使其可见?
void make_visible(HWND hCtl, HWND hWndParent) {
SetWindowLongPtr(hCtl, GWL_STYLE,
GetWindowLongPtr(hCtl, GWL_STYLE) | WS_VISIBLE);
RECT rc{};
GetClientRect(hCtl, &rc);
MapWindowRect(hCtl, hWndParent, &rc);
InvalidateRect(hWndParent, &rc, TRUE);
UpdateWindow(hWndParent);
//ShowWindow(hCtl, SW_SHOW); // no use: does not update window
//SetWindowPos(hCtl, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); // no use: does not update window
}
使 window 可见的正常方法只是函数 ShowWindow。无需处理标志等。通常您使用 SW_SHOW
作为 child window 的参数。检查其他值并使用您认为合适的值。
如果 window 有一个可见的矩形并且没有被另一个 window 覆盖,它将显示出来。甚至不需要 UpdateWindow 调用。 window 将出现在下一个绘制周期中。如果您的控件的大小为 0,0,0,0(创建时),它将永远不会显示。
如果 window 在不同的线程上,则还有一个 ShowWindowAsync 函数可用于避免阻塞。
顺便说一句:我不明白你试图使 parent window 区域无效的原因。如果有 child window 剪辑 (WS_CLIPCHILDREN
) 它没有效果。
我认为您的问题是您自己明确设置了 WS_VISIBLE
样式,然后 然后 调用 ShowWindow
,这让 Windows 感到困惑相信 window 已经可见,不需要重新绘制。
只需调用ShowWindow
。 There should be no need to explicitly set WS_VISIBLE
yourself because ShowWindow
already does it。您不需要强行重新绘制控件。
此外,如果您发现某些需要显式使您的控件无效,只需执行 InvalidateRect(hCtl, NULL)
就足够了,而不必理会 GetClientRect
和 MapWindowRect
。
要使子控件可见,请像这样调用 SetWindowPos
:
SetWindowPos(hCtl, 0, 0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);
您调用 MapWindowRect
、InvalidateRect
、UpdateRect
等的代码应删除。
也许您遇到的真正问题是您创建了宽度和高度为零的静态控件。