• Qt实现鼠标左键拖动无标题栏窗体右下角改变窗体大小及移动窗体


    目录

    1.问题的提出

    2.实现方法

    3.存在的问题


    1.问题的提出

    一般情况下,当去掉窗体标题栏时,按住鼠标左键就无法实现拖动窗体;当去掉窗体标题栏时,窗体四周的边框也去掉了,此时按住鼠标左键拖动窗体四周边沿,无法实现鼠标拖动改变窗体大小。如下为Qt实现去掉窗体标题栏的代码:

    1. setWindowFlag(Qt::FramelessWindowHint); // 去掉标题栏

    现在的问题是:

    • 在去掉窗体标题栏的情况下,如何按住鼠标左键,实现鼠标拖动改变窗体大小?
    • 在去掉窗体标题栏的情况下,如何在窗体上按住鼠标左键,实现移动窗体?

    2.实现方法

    Qt中有个QSizeGrip类,可以很好解决1节提到的问题,关于该类的具体用法,参见Qt Assistant。

    下面直接上代码:

    .h文件如下:

    1. #pragma once
    2. #include
    3. #include "ui_QtGuiApplication2.h"
    4. class QtGuiApplication2 : public QWidget
    5. {
    6. Q_OBJECT
    7. public:
    8. QtGuiApplication2(QWidget *parent = Q_NULLPTR);
    9. private: // virtual
    10. void mousePressEvent(QMouseEvent* event) override;
    11. void mouseReleaseEvent(QMouseEvent* event) override;
    12. void mouseMoveEvent(QMouseEvent* event) override;
    13. private:
    14. Ui::QtGuiApplication2Class ui;
    15. bool m_bLeftMousePressed{ false }; // 鼠标左键是否被按下
    16. QPoint m_lastPoint; // 鼠标上次按下的点
    17. };

    .cpp文件如下:

    1. #include "QtGuiApplication2.h"
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. QtGuiApplication2::QtGuiApplication2(QWidget *parent)
    8. : QWidget(parent)
    9. {
    10. ui.setupUi(this);
    11. setWindowFlag(Qt::FramelessWindowHint); // 去掉标题栏
    12. QVBoxLayout* pMainWnd = new QVBoxLayout(this);
    13. setLayout(pMainWnd);
    14. auto pFrame = new QFrame(this);
    15. pFrame->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    16. pMainWnd->addWidget(pFrame);
    17. QHBoxLayout* pBottomLayout = new QHBoxLayout(this);
    18. pMainWnd->addLayout(pBottomLayout);
    19. // 加一个水平弹簧,为了把后面的QSizeGrip挤到最右边
    20. auto horizontalSpacer = new QSpacerItem(193, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
    21. pBottomLayout->addItem(horizontalSpacer);
    22. // 创建QSizeGrip对象,该对象就是用来调整窗体大小的
    23. auto pSizeGrip = new QSizeGrip(this);
    24. pSizeGrip->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
    25. pBottomLayout->addWidget(pSizeGrip); // 将QSizeGrip对象加入窗体右下角
    26. // 也可以加入一个状态栏来实现拖动窗体右下角改变窗体大小
    27. //auto pStatusBar = new QStatusBar(this);
    28. //pStatusBar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
    29. //pBottomLayout->addWidget(pStatusBar);
    30. }
    31. // 鼠标左键按下,准备移动窗体
    32. void QtGuiApplication2::mousePressEvent(QMouseEvent* event)
    33. {
    34. if (Qt::LeftButton != event->button())
    35. {
    36. return;
    37. }
    38. m_lastPoint = event->globalPos();
    39. m_bLeftMousePressed = true;
    40. }
    41. // 移动窗体结束
    42. void QtGuiApplication2::mouseReleaseEvent(QMouseEvent* event)
    43. {
    44. if (Qt::LeftButton != event->button())
    45. {
    46. return;
    47. }
    48. m_bLeftMousePressed = false;
    49. }
    50. // 开始移动窗体
    51. void QtGuiApplication2::mouseMoveEvent(QMouseEvent* event)
    52. {
    53. auto curMousePt = event->globalPos(); // 注意:这里记录是窗体在屏幕上的坐标位置
    54. auto offsetPt = curMousePt - m_lastPoint; // 计算和上次移动点的坐标差值
    55. move(pos() + offsetPt);
    56. m_lastPoint = curMousePt; // 记录本次窗体所在位置,以便下次计算位置
    57. }

    效果如下:

    图1

    QSizeGrip对象在窗体中的位置如下:

    图2

    说明:

    • Qt中的QDialog和QStatusBar类封装了 QSizeGrip对象,故上面代码也可以插入QStatusBar类到右下角来实现 QSizeGrip对象调整大小功能,即注释掉29~31行代码,取消34~36注释,实现同样功能。
    • Qt中的QDialog和QStatusBar类提供了setSizeGripEnabled(bool)方法用来设置是否启用QSizeGrip对象,默认是启用的,即右下角QSizeGrip对象是可见的。

    3.存在的问题

           从图1可以看到,当按住鼠标左键拖动右下角的QSizeGrip对象以改变窗体大小,此时窗体大小确实改变了,但窗体也随之被移动了,也就是既改变了窗体大小也移动了窗体。原因是QSizeGrip对象必须响应鼠标移动事件才能改变窗体大小,与此同时窗体响应鼠标事件被移动。如何只保证改变窗体大小,而不移动窗体呢?此时必须从QSizeGrip类派生出自己的子类,代码如下:

    mySizeGrip.h:

    1. #pragma once
    2. #include
    3. namespace Ui { class CMySizeGrip; };
    4. class CMySizeGrip : public QSizeGrip
    5. {
    6. Q_OBJECT
    7. public:
    8. CMySizeGrip(QWidget *parent = Q_NULLPTR);
    9. ~CMySizeGrip();
    10. private: // virtual
    11. void mousePressEvent(QMouseEvent* event) override;
    12. void mouseReleaseEvent(QMouseEvent* event) override;
    13. void mouseMoveEvent(QMouseEvent* event) override;
    14. private:
    15. Ui::CMySizeGrip *ui;
    16. QPoint m_lastPoint; // 鼠标上次按下的点
    17. QWidget* m_pParent; // 父窗体,也就是要调节大小的窗体
    18. };

    mySizeGrip.cpp:

    1. #include "mySizeGrip.h"
    2. #include "ui_mySizeGrip.h"
    3. #include
    4. #include
    5. CMySizeGrip::CMySizeGrip(QWidget *parent)
    6. : QSizeGrip(parent)
    7. {
    8. m_pParent = parent;
    9. ui = new Ui::CMySizeGrip();
    10. ui->setupUi(this);
    11. }
    12. CMySizeGrip::~CMySizeGrip()
    13. {
    14. delete ui;
    15. }
    16. void CMySizeGrip::mousePressEvent(QMouseEvent* event)
    17. {
    18. if (Qt::LeftButton != event->button())
    19. {
    20. return;
    21. }
    22. m_lastPoint = event->globalPos();
    23. }
    24. void CMySizeGrip::mouseReleaseEvent(QMouseEvent* event)
    25. {
    26. }
    27. void CMySizeGrip::mouseMoveEvent(QMouseEvent* event)
    28. {
    29. auto curMousePt = event->globalPos();
    30. auto offset = curMousePt - m_lastPoint;
    31. m_lastPoint = curMousePt;
    32. // 调整父窗体大小
    33. m_pParent->resize(m_pParent->size().width() + offset.x(), m_pParent->size().height() + offset.y());
    34. }

    将前面第29行的:

    auto pSizeGrip = new QSizeGrip(this);

    改为:

    auto pSizeGrip = new CMySizeGrip(this);

  • 相关阅读:
    设计表时,如何选择正确的数据类型
    【C++庖丁解牛】vector容器的简易模拟实现(C++实现)(最后附源码)
    事 件 流
    Linux权限的理解
    Chapter20: Machine Learning for In Silico ADMET Prediction
    Hadoop编程——第三章:(2)Linux文件系统基础知识
    除了等保2.0,还有哪些法规涉及云计算数据安全?
    SAS学习5(复习一些基本的统计学概念、sas中关于统计函数的一些语句)
    200. 岛屿数量
    LeetCode 1422. 分割字符串的最大得分
  • 原文地址:https://blog.csdn.net/danshiming/article/details/127787104