如何使创建的没有 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 已经可见,不需要重新绘制。

只需调用ShowWindowThere should be no need to explicitly set WS_VISIBLE yourself because ShowWindow already does it。您不需要强行重新绘制控件。

此外,如果您发现某些需要显式使您的控件无效,只需执行 InvalidateRect(hCtl, NULL) 就足够了,而不必理会 GetClientRectMapWindowRect

要使子控件可见,请像这样调用 SetWindowPos

SetWindowPos(hCtl, 0, 0, 0, 0, 0, 
  SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);

您调用 MapWindowRectInvalidateRectUpdateRect 等的代码应删除。

也许您遇到的真正问题是您创建了宽度和高度为零的静态控件。