gpt4 book ai didi

c++ - 当 DPI 感知、全屏和无框时,在 WM_NCACTIVATE 上删除客户区

转载 作者:行者123 更新时间:2023-12-02 10:22:56 27 4
gpt4 key购买 nike

我正在编写一个需要 DPI 感知、无边界全屏顶级 OpenGL 窗口的程序。
该程序在 99% 的时间里只有这个主窗口。

我遇到的问题是当窗口变为非事件状态时,窗口的客户区被窗口删除。
这仅在 DPI 感知、全屏 时发生和 无边界(即零非客户区)。

我找到了一种解决方法,通过捕获 WM_NCACTIVATE 并返回 0 来阻止 Windows 处理 NC 重绘。如果非客户区为零,Windows 非客户端重绘过程似乎会删除客户区。

但是,当我创建一个 DialogBox(主 hWnd 的子级)时,它会导致主窗口变为非事件状态(显然)。
如果我从 WM_NCACTIVATE 返回 0,鼠标和键盘事件不会传递到对话框 proc,因此程序被锁定。
使用全局标志,我可以在创建对话框之前停用解决方法,然后在 WM_INITDIALOG 上重绘我的主 GL 屏幕,但这会导致我试图阻止的相当难看的屏幕闪烁。

所以我的问题是:如何在不抑制 WM_NCACTIVATE 的情况下防止 Windows 删除我的主 wnd 客户端?

交替:如何避免创建对话框时出现的窗口删除,延迟,然后重绘闪存?

供引用,
我用来创建主窗口、运行消息循环和绘制 GL 场景的代码基本上来自 HeNe 示例。
我知道这些都非常过时,但我发现它们很容易构建。

我已将 HeNe 代码更改为 WinMain() 并仅在程序需要时执行我的 OpenGL 绘图(在主循环之外和 WM_PAINT 之外)。
在 WM_PAINT 和 WM_NCPAINT 中重绘场景和 SwapBuffers() 并不能解决问题。

为了使窗口全屏,我使用 Raymond Chen 的代码:
https://devblogs.microsoft.com/oldnewthing/20100412-00/?p=14353
我还尝试了 c-smile 的代码来制作全屏,其行为与 Raymond Chen 的相同:
Windows 10, DPI scaling and fullscreen

作为记录,我使用的是 PerMonitor V2,但我使用哪种模式似乎并不重要。我尝试使用 API 和 list 文件进行设置。

VS2019 v142;开发工具包 10.0.18362.0

最佳答案

我为 Win10 上的 Qt 应用程序解决了这个问题。我的程序是 DPI 感知和无边界的,但不是全屏的。不过,我遇到了同样的问题:

  • 激活/停用窗口时会出现令人不快的闪烁
  • WM_NCACTIVATE WndProc 调用无条件返回 true 将修复闪烁,但会阻止对话框捕获输入
  • 在没有调用 WM_NCPAINT 的情况下发生闪烁;没有机会阻止重绘。

  • 为了解决这个问题,我不得不改变我删除非客户区的方式。以前我在创建窗口时使用了一个特定于 Qt 的函数,如下所示:
    setWindowFlag(Qt::FramelessWindowHint);
    我删除了它并为无条件返回 0 的 WM_NCCALCSIZE 调用添加了一个处理程序。这删除了非客户区,并且无论出于何种原因,尽管没有 WM_NCACTIVATE 处理程序,但不会导致激活时重绘。

    简而言之,我删除非客户端矩形的唯一方法是处理 WM_NCCALCSIZE。我不调用任何 WINAPI 函数。我不会覆盖 WM_NCACTIVATE,因为这样做会阻止对话框正常工作。

    这是我的完整的 WndProc。这是针对 Qt 应用程序的,但是 nativeEvent只是原生 WndProc 的一个薄包装。
    bool MainWindow::nativeEvent(const QByteArray& eventType, void* message, long* result)
    {
    MSG* msg = static_cast<MSG*>(message);
    LRESULT hitTestResult = 0;
    auto handled = DwmDefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam, result);
    if (handled)
    return true;

    static bool resizing = false;
    switch (msg->message)
    {
    case WM_NCHITTEST:
    *result = HitTestNCA(msg->hwnd, msg->wParam, msg->lParam, this);
    if (*result != HTNOWHERE)
    return true;
    return false;
    case WM_NCCALCSIZE:
    // Setting the result to zero removes the non-client rect. This is
    // a hardcoded Microsoft thing.
    *result = 0;
    return true;
    default:
    return false;
    }
    // Unreachable
    }

    关于c++ - 当 DPI 感知、全屏和无框时,在 WM_NCACTIVATE 上删除客户区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59297550/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com