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());

	}
}
posted @ 2024-09-11 05:43  Darkexpeller  阅读(272)  评论(0)    收藏  举报