目录
为什么要写这篇再简单不过的文章?
- 帮助新手快速上手实现无边框窗口的拖动
- 作者在实践中遇到了窗口在多屏显示器间拖动,窗口飞掉的问题
- 今天分享的实现方式,不仅能解决第2条中的问题,而且代码量更少
错误的实现方式
这里以实现步骤来简单说明:
- 鼠标按下时,记录鼠标的全局坐标curPos
- 鼠标移动时,获取鼠标的全局坐标tmpPos
- tmpPos减去curPos得到移动距离delta,然后,调用move(pos() + delta)
- 将tmpPos赋值给curPos
上述这种实现方式,在单屏情况下不存在任何问题,但是在多屏情况下,可能存在问题。
比如,我有2个显示器,分辨率都是3840*2160,为了使显示效果看着更舒服,将缩放设置为了200%。
使用event->globalPosition().toPoint()获取鼠标位置Pt时,从屏幕2的右边缘到屏幕1的左边缘,Pt会有一个跳跃。
- 屏幕2右上角的Pt为(1920, 0)
- 屏幕1右上角的Pt为(3840, 0)
因此,当我拖动窗口从屏幕2到屏幕1,或从屏幕1到屏幕2时,计算的移动距离delta,就会发生一个跳跃,导致窗口位置错误。
如果,屏幕的缩放比例设置为100%,就不会存在上面的问题,可是我们也不能寄希望于用户按照我们的期望去设置啊。
错误就分析这么多吧,下面我们介绍正确的实现方式。
简单且正确的实现方式
先说逻辑:
- 鼠标按下时,记录鼠标的局部坐标pt2Topleft,这个坐标就是相对于窗口左上角的向量
- 鼠标移动时,获取鼠标的全局坐标tmpPos
- tmpPos减去pt2Topleft得到就得到移动后窗口的位置,因此,调用move(tmpPos - pt2Topleft),就完成了窗口的移动。
下面是源代码
CustomWindow.h
#pragma once
#include <QWidget>
class CustomWindow : public QWidget
{
Q_OBJECT
public:
CustomWindow(QWidget *parent = nullptr);
~CustomWindow();
protected:
void mousePressEvent(QMouseEvent* e);
void mouseMoveEvent(QMouseEvent* e);
void mouseReleaseEvent(QMouseEvent* e);
private:
QPoint m_pt2Topleft;
bool m_pressed;
};
CustomWindow.cpp
#include "CustomWindow.h"
#include <QMouseEvent>
CustomWindow::CustomWindow(QWidget *parent)
: QWidget(parent)
{
setWindowFlags(Qt::FramelessWindowHint);
}
CustomWindow::~CustomWindow() {}
void CustomWindow::mousePressEvent(QMouseEvent *e)
{
if (Qt::LeftButton == e->button())
{
m_pressed = true;
m_pt2Topleft = e->pos();
}
}
void CustomWindow::mouseMoveEvent(QMouseEvent *e)
{
if (m_pressed)
{
QPoint tmpPos = e->globalPosition().toPoint();
move(tmpPos - m_pt2Topleft);
}
}
void CustomWindow::mouseReleaseEvent(QMouseEvent *e)
{
if (Qt::LeftButton == e->button())
{
m_pressed = false;
}
}
说明
这里的实现,鼠标拖动窗口的任何区域都可以对窗口进行拖动,如果大家想拖动标题栏时进行移动,可以放置一个QWidget作为标题栏,然后通过ui.header->geometry().contains(event->pos())的方式,决定是否进行窗口的拖动。
如果觉得对大家有用,不妨帮忙点赞收藏关注,一键三连!