我正在使用以下库调用将窗口更改为深色模式:
BOOL dark = TRUE;
DwmSetWindowAttribute(hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &dark, sizeof(dark));
这可行,但有一个小警告。标题栏不会更新,直到发生一些其他事件,例如最大化、失去焦点、调整大小等(但不移动窗口)。
我尝试过
UpdateWindow
和 RedrawWindow
上的大量标志组合,但没有成功。如何强制标题栏重绘?
编辑 我能够通过以编程方式调整窗口大小来强制重置,然后将其重置为之前的大小。但这似乎是一个糟糕的方法。一定有一个合适的解决方案。
这就是我在 Windows 10 上调用
DwmSetWindowAttribute
后触发标题栏重绘的方式(尚未在 Windows 11 上测试)。正如 OP 所提到的,触发 WM_NCPAINT 的常用方法似乎都不起作用。此方法的工作原理是更改然后恢复窗口宽度。它以尽可能不可见的方式实现这一点,并且适用于正常窗口和最大化窗口。它使窗口宽度更小而不是更大,以避免潜在的溢出到辅助监视器上。
if (IsWindowVisible(hwnd) && !IsIconic(hwnd)) {
// Get the current window rect.
RECT rect = {};
::GetWindowRect(hwnd, &rect);
if (IsZoomed(hwnd)) {
// Window is currently maximized.
WINDOWPLACEMENT placement = {};
GetWindowPlacement(hwnd, &placement);
// Remember the old restore rect.
const RECT oldrect = placement.rcNormalPosition;
// Change the restore rect to almost the same as the current
// maximized rect.
placement.rcNormalPosition = rect;
placement.rcNormalPosition.right -= 1;
SetWindowPlacement(hwnd, &placement);
// Restore and then re-maximize the window. Don't update in-between.
LockWindowUpdate(hwnd);
ShowWindow(hwnd, SW_SHOWNORMAL);
ShowWindow(hwnd, SW_SHOWMAXIMIZED);
LockWindowUpdate(nullptr);
// Put back the old restore rect.
placement.rcNormalPosition = oldrect;
SetWindowPlacement(hwnd, &placement);
} else {
// Window is currently normal. Change and then restore the window width.
// Use Defer functions to make the change less noticeable. Don't update
// in-between.
HDWP defer = BeginDeferWindowPos(2);
DeferWindowPos(defer, hwnd, NULL, 0, 0,
rect.right - rect.left - 1, rect.bottom - rect.top,
SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
DeferWindowPos(defer, hwnd, NULL, 0, 0, rect.right - rect.left,
rect.bottom - rect.top,
SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
LockWindowUpdate(hwnd);
EndDeferWindowPos(defer);
LockWindowUpdate(nullptr);
}
}