QT无边框窗口------由屏幕缩放导致的移动bug
在写QT无边框窗口时,需要自己实现鼠标拖动窗口。初步的实现方式如下(原理为平面向量加减法):
void TitleBar::mousePressEvent(QMouseEvent* event)
{
event->ignore();//
BeginMove = true;//
//return;
qDebug() << mapToGlobal(this->pos());
if (event->button() == Qt::LeftButton)
{
MousePosWhenPress = event->globalPosition().toPoint();
WindowPosWhenPress = par->pos();
}
//qDebug() << 1;
}
void TitleBar::mouseMoveEvent(QMouseEvent* event)
{
if (this->underMouse()&& BeginMove)
{
par->move((WindowPosWhenPress +event->globalPos()- MousePosWhenPress));
}
}
在单屏幕上这个代码工作地很好。但是当跨越屏幕拖动时就会出现问题,把两块屏幕缩放改为100%后不再出现跨屏抖动问题,改回去任然出现。
此时应该考虑到是DPI缩放的问题,经过debug打印鼠标事件触发时的坐标发现:
- 当窗口中轴线跨越屏幕时会使窗口瞬移
- 当鼠标跨越屏幕时,event->globalPos()发生剧变(具体表现为在主屏幕左侧屏幕的右端,其横坐标值为-385。不同设备设置可能不同)
目前基本可以确定globalPos()返回的值是QT中的逻辑坐标,经过简单观察其值和真实坐标的商为0.8(对应125%缩放)
但在左侧副屏(event->globalPos().x()+385)/RealWindowPos=0.8,而385该值可能不固定,不可控。
因此还是建议使用win32API实现窗口拖动
完整代码如下
#ifndef TITLEBAR_H
#define TITLEBAR_H
#include <QGroupbox>
#include <QPushButton>
#include<iostream>
#include<qevent.h>
#include <Qt>
#include<qdebug.h>
#include<qwidget.h>
class close_button : public QPushButton
{
Q_OBJECT
public:
explicit close_button(QWidget *parent = nullptr);
bool event(QEvent* event);
QIcon* close_icon_leave;
QIcon* close_icon_Entry;
QWidget* par;
signals:
};
class TitleBar: public QGroupBox
{
Q_OBJECT
public:
close_button *CloseButton;
explicit TitleBar(QWidget *parent = nullptr);
void mouseMoveEvent(QMouseEvent* event);
void mousePressEvent(QMouseEvent* event);
QPoint MousePosWhenPress;
QWidget* par;
QPoint WindowPosWhenPress;
bool BeginMove;
signals:
}
...
void W32MoveWindow(int x,int y)
{
// 获取当前前台窗口的句柄
HWND hWnd = GetForegroundWindow();
if (hWnd != NULL) {
// 获取当前窗口的大小
RECT rect;
if (GetWindowRect(hWnd, &rect)) {
int width = rect.right - rect.left;
int height = rect.bottom - rect.top; // 当前高度
// 移动窗口但保持大小不变
SetWindowPos(hWnd,
HWND_TOP,
x, // 新的 x 坐标
y, // 新的 y 坐标
width, // 保持当前宽度
height, // 保持当前高度
SWP_NOACTIVATE | SWP_NOZORDER);
}
}
return ;
}
QPoint getGlobalWindowPos()
{
HWND hWnd = GetForegroundWindow();
if (hWnd != NULL)
{
RECT rect;
GetWindowRect(hWnd, &rect);
return QPoint(rect.left, rect.top);
}
}
QPoint getGlobalMousePos() {
POINT p;
if (GetCursorPos(&p)) {
return QPoint(p.x, p.y); // 将Win32 API的POINT转换为QPoint
}
return QPoint(0, 0); // 出错时返回一个默认值
}
void TitleBar::mousePressEvent(QMouseEvent* event)
{
event->ignore();//
BeginMove = true;//
//return;
qDebug() << "mapToGlobal(event->pos())";
qDebug() << mapToGlobal(event->pos());
if (event->button() == Qt::LeftButton)
{
MousePosWhenPress = getGlobalMousePos();
WindowPosWhenPress = getGlobalWindowPos();
}
}
void TitleBar::mouseMoveEvent(QMouseEvent* event)
{
event->ignore();
if (this->underMouse() && BeginMove)
{
QPoint globalMousePos = getGlobalMousePos();
QPoint sub = WindowPosWhenPress - MousePosWhenPress;
QPoint LogicPos=sub + globalMousePos;
Win32MoveWindow(LogicPos.x(), LogicPos.y());
}
}

浙公网安备 33010602011771号