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號