子窗口会继承父窗口或者所有者窗口的一些样式。
当我们使用 CreateWindowExW 创建窗口后,指定其 HwndParent 参数时,或者通过 SetWindowLongPtr(vd->Hwnd, GWLP_HWNDPARENT, (LONG_PTR)vd->HwndParent); 指定所有者窗口时,子窗口将从父窗口/所有者窗口拷贝部分样式和扩展样式。
例如,当所有者窗口具有 WS_EX_TOPMOST 样式时候,其创建的子窗口将具有 WS_EX_TOPMOST 样式。
所以,当你发现你的 WS_POPUP 样式的窗口默认具有 WS_EX_TOPMOST 时候,不要觉得奇怪。可能是你设置了所有者窗口。
此问题发生在 ImGui 的 win32 后端逻辑中,作者错误地设置所有者窗口,导致当 win32 平台窗口设置 WS_EX_TOPMOST 样式时,无法控制在多视口中的新窗口的样式。
修复方法,在 SetWindowPos 中加入一个控制开关 ConfigViewportsNoTopmost:
static void ImGui_ImplWin32_SetWindowPos(ImGuiViewport* viewport, ImVec2 pos)
{ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;IM_ASSERT(vd->Hwnd != 0);RECT rect = { (LONG)pos.x, (LONG)pos.y, (LONG)pos.x, (LONG)pos.y };if (viewport->Flags & ImGuiViewportFlags_OwnedByApp)ImGui_ImplWin32_UpdateWin32StyleFromWindow(viewport); // Not our window, poll style before usingImGuiIO gIO = ImGui::GetIO();if (gIO.ConfigViewportsNoTopmost)vd->DwExStyle &= ~WS_EX_TOPMOST;::AdjustWindowRectEx(&rect, vd->DwStyle, FALSE, vd->DwExStyle);if(gIO.ConfigViewportsNoTopmost)::SetWindowPos(vd->Hwnd, HWND_NOTOPMOST, rect.left, rect.top, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);else::SetWindowPos(vd->Hwnd, nullptr, rect.left, rect.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
}
ConfigViewportsNoTopmost 添加到 ImGuiIO 结构中即可,这样就可以在代码中设置了:
// Setup Dear ImGui context
// 设置 ImGui 的上下文
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls 启用键盘控制
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls 启用手柄控制
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking 启用 docking 停靠模式
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows 启用多视口平台窗口
io.ConfigFlags |= ImGuiConfigFlags_TransparentBackbuffers; // Enable transparent backbuffer support
io.ConfigViewportsNoAutoMerge = true;.....io.ConfigViewportsNoTopmost = true; // 这是新增的控制多视口窗口不置顶
好了,分享就到这里结束了。