Qt实战 10行代码实现无边框窗口的拖动

目录

为什么要写这篇再简单不过的文章?

错误的实现方式


为什么要写这篇再简单不过的文章?

  1. 帮助新手快速上手实现无边框窗口的拖动
  2. 作者在实践中遇到了窗口在多屏显示器间拖动,窗口飞掉的问题
  3. 今天分享的实现方式,不仅能解决第2条中的问题,而且代码量更少

错误的实现方式

这里以实现步骤来简单说明:

  1. 鼠标按下时,记录鼠标的全局坐标curPos
  2. 鼠标移动时,获取鼠标的全局坐标tmpPos
  3. tmpPos减去curPos得到移动距离delta,然后,调用move(pos() + delta)
  4. 将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%,就不会存在上面的问题,可是我们也不能寄希望于用户按照我们的期望去设置啊。

错误就分析这么多吧,下面我们介绍正确的实现方式。

简单且正确的实现方式

先说逻辑:

  1. 鼠标按下时,记录鼠标的局部坐标pt2Topleft,这个坐标就是相对于窗口左上角的向量
  2. 鼠标移动时,获取鼠标的全局坐标tmpPos
  3. 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())的方式,决定是否进行窗口的拖动。

如果觉得对大家有用,不妨帮忙点赞收藏关注,一键三连!

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值