我在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
调用
这是一个错误QTBUG-120196
添加并合并补丁