子窗口會繼承父窗口或者所有者窗口的一些樣式。
當我們使用?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; // 這是新增的控制多視口窗口不置頂
好了,分享就到這里結束了。