Qt6 在 Windows 中使用 nativeEvent WM_NCCALCSIZE 绘制问题

问题描述 投票:0回答:1

我在Windows平台上工作。如果我同时使用 qt 窗口标志和 windows api 来获得无框窗口,例如:

this->setWindowFlags(this->windowFlags() | Qt::FramelessWindowHint);

SetWindowLong((HWND) this->winId(), GWL_STYLE, style | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CAPTION | CS_DBLCLKS | WS_THICKFRAME | WS_OVERLAPPED);

然后我使用 WM_NCCALCSIZE 告诉 Windows 客户端矩形大小,例如:

/* get border x-size */
int tx = getResizeBorderThickness(hWnd);
/* get border y-size */
int ty = getResizeBorderThickness(hWnd, false);
/* sub real client size with border size */
rect->top += ty;
rect->bottom -= ty;
rect->left += tx;
rect->right -= tx;

PyQt/Qt<=6.4.2(probably)
时工作正常。

结果_img_PyQt6.4.2

result_img_C++ Qt6.3.2

使用时你会得到一个错误的绘制窗口

PyQt/Qt6.6.1

结果_img_PyQt6.6.1

result_img_C++ Qt6.6.1

C++ 测试代码在这里

#include "mainwindow.h"
#include <QGuiApplication>
#include <QWindow>
#include "ui_mainwindow.h"
#include <Windows.h>
#include <dwmapi.h>

#pragma comment(lib, "user32.lib")
#pragma comment(lib, "dwmapi.lib")

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    this->setWindowFlags(this->windowFlags() | Qt::FramelessWindowHint);
    auto style = GetWindowLong((HWND) this->winId(), GWL_STYLE);
    SetWindowLong((HWND) this->winId(),
                  GWL_STYLE,
                  style | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CAPTION | CS_DBLCLKS | WS_THICKFRAME
                      | WS_OVERLAPPED);
    SetWindowPos((HWND) this->winId(),
                 HWND_TOP,
                 0,
                 0,
                 0,
                 0,
                 SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
    this->showMaximized();
}

MainWindow::~MainWindow()
{
    delete ui;
}

bool isMaximized(HWND hWnd)
{
    WINDOWPLACEMENT windowPlacement;
    windowPlacement.length = sizeof(WINDOWPLACEMENT);
    bool ret = GetWindowPlacement(hWnd, &windowPlacement);
    if (!ret) {
        return false;
    }

    return windowPlacement.showCmd == SW_MAXIMIZE;
}

QWindow *findWindow(HWND hWnd)
{
    if (!hWnd)
        return nullptr;
    auto windows = QGuiApplication::topLevelWindows();
    if (windows.size() == 0)
        return nullptr;
    int id = int(hWnd);
    foreach (auto w, windows) {
        if (int(w->winId()) == id) {
            return w;
        }
    }
    return nullptr;
}

int getResizeBorderThickness(HWND hWnd, bool hor = true)
{
    auto window = findWindow(hWnd);
    if (!window) {
        return 0;
    }
    auto frame = hor ? SM_CXSIZEFRAME : SM_CYSIZEFRAME;
    auto size = GetSystemMetrics(frame) + GetSystemMetrics(92);
    if (size > 0)
        return size;
    int res = 0;
    DwmIsCompositionEnabled(&res);
    auto thickness = res ? 8 : 4;
    return int(thickness * window->devicePixelRatio());
}

bool MainWindow::nativeEvent(const QByteArray &eventType, void *message, qintptr *result)
{
    if (eventType != "windows_generic_MSG") {
        return false;
    }
    MSG *msg = (MSG *) message;
    if (msg->hwnd == nullptr)
        return false;
    switch (msg->message) {
    case WM_NCCALCSIZE: {
        auto isMax = ::isMaximized(msg->hwnd);
        auto setRectMax = [](HWND hWnd, LPRECT rect) {
            int tx = getResizeBorderThickness(hWnd);
            int ty = getResizeBorderThickness(hWnd, false);
            rect->top += ty;
            rect->bottom -= ty;
            rect->left += tx;
            rect->right -= tx;
        };
        if (msg->wParam) {
            LPNCCALCSIZE_PARAMS rect = (LPNCCALCSIZE_PARAMS) (msg->lParam);
            if (isMax) {
                setRectMax(msg->hwnd, rect->rgrc);
            }
        } else {
            LPRECT rect = (LPRECT) (msg->lParam);
            if (isMax) {
                setRectMax(msg->hwnd, rect);
            }
        }
        *result = msg->wParam ? 0 : WVR_REDRAW;
        return true;
    }
    }
    return false;
}

同时使用

Qt::FramelessWindowHint
SetWindowLong
时会出现此问题,但删除
SetWindLong
调用会丢失窗口动画 有没有办法在使用PyQt6.6.2/Qt6.6.2时达到与6.4.2版本相同的效果,同时保留
SetWindowLong
调用

c++ windows qt winapi pyqt6
1个回答
0
投票

这是一个错误QTBUG-120196

添加并合并补丁

© www.soinside.com 2019 - 2024. All rights reserved.