使用 Qt 实现自定义拖动窗口

文章目录

如何在 Qt 中实现无标题栏窗口的拖动

在许多桌面应用程序中,我们经常需要自定义窗口外观,包括去掉标题栏,使窗口看起来更加现代和美观。然而,去掉标题栏也意味着失去了通过标题栏拖动窗口的功能。在这篇博客中,我将介绍如何在 Qt 中实现鼠标拖动无标题栏窗口的功能。

准备工作

首先,我们需要创建一个基于 QWidget 或 QDialog 的自定义窗口类。在这个类中,我们将重写鼠标事件处理函数:mousePressEvent、mouseMoveEvent 和 mouseReleaseEvent,以实现拖动功能。

创建自定义窗口类

让我们从创建一个基本的 Qt 应用程序开始,并定义一个 DraggableWidget 类。下面是一个基于 QWidget 的示例:

cpp 复制代码
#include <QApplication>
#include <QWidget>
#include <QMouseEvent>
#include <QDebug>

class DraggableWidget : public QWidget
{
    Q_OBJECT

public:
    DraggableWidget(QWidget *parent = nullptr) : QWidget(parent), isDragging(false)
    {
        // 设置无标题栏窗口
        setWindowFlag(Qt::FramelessWindowHint);
        setAttribute(Qt::WA_DeleteOnClose);
        resize(400, 300); // 设置窗口大小
    }

protected:
    void mousePressEvent(QMouseEvent *event) override
    {
        if (event->button() == Qt::LeftButton) { // 检查是否按下了鼠标左键
            isDragging = true; // 设置拖动状态为真,表示开始拖动
            dragPosition = event->globalPos() - frameGeometry().topLeft(); // 记录鼠标按下时的全局位置与窗口左上角位置的差值
            event->accept(); // 接受事件,防止事件进一步传播
        }
        return QWidget::mousePressEvent(event); // 调用基类的 mousePressEvent 以确保默认行为被执行
    }

    void mouseMoveEvent(QMouseEvent *event) override
    {
        if (isDragging && (event->buttons() & Qt::LeftButton)) { // 检查是否正在拖动并且左键仍然按下
            move(event->globalPos() - dragPosition); // 计算并设置窗口的新位置
            event->accept(); // 接受事件,防止事件进一步传播
        }
        return QWidget::mouseMoveEvent(event); // 调用基类的 mouseMoveEvent 以确保默认行为被执行
    }

    void mouseReleaseEvent(QMouseEvent *event) override
    {
        if (event->button() == Qt::LeftButton) { // 检查是否释放了鼠标左键
            isDragging = false; // 设置拖动状态为假,表示停止拖动
            event->accept(); // 接受事件,防止事件进一步传播
        }
        return QWidget::mouseReleaseEvent(event); // 调用基类的 mouseReleaseEvent 以确保默认行为被执行
    }

private:
    bool isDragging; // 是否正在拖动
    QPoint dragPosition; // 记录拖动时鼠标位置和窗口左上角位置的差值
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    DraggableWidget window;
    window.show();

    return app.exec();
}
使用 QDialog 实现拖动功能

如果您的窗口类是基于 QDialog,实现方式类似。下面是一个基于 QDialog 的示例:

cpp 复制代码
#include "startdialog.h"
#include "ui_startdialog.h"
#include <QMouseEvent>
#include <QDebug>

StartDialog::StartDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::StartDialog)
{
    ui->setupUi(this);
    setWindowFlag(Qt::FramelessWindowHint);
    setAttribute(Qt::WA_DeleteOnClose);
    ui->lineEditPwd->setEchoMode(QLineEdit::Password);

    initialize();
}

StartDialog::~StartDialog()
{
    delete ui;
}

void StartDialog::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) { // 检查是否按下了鼠标左键
        mouse = true; // 设置拖动状态为真,表示开始拖动
        dragPosition = event->globalPos() - frameGeometry().topLeft(); // 记录鼠标按下时的全局位置与窗口左上角位置的差值
        event->accept(); // 接受事件,防止事件进一步传播
    }
    return QDialog::mousePressEvent(event); // 调用基类的 mousePressEvent 以确保默认行为被执行
}

void StartDialog::mouseReleaseEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) { // 检查是否释放了鼠标左键
        mouse = false; // 设置拖动状态为假,表示停止拖动
        event->accept(); // 接受事件,防止事件进一步传播
    }
    return QDialog::mouseReleaseEvent(event); // 调用基类的 mouseReleaseEvent 以确保默认行为被执行
}

void StartDialog::mouseMoveEvent(QMouseEvent *event)
{
    if (mouse && (event->buttons() & Qt::LeftButton)) { // 检查是否正在拖动并且左键仍然按下
        move(event->globalPos() - dragPosition); // 计算并设置窗口的新位置
        event->accept(); // 接受事件,防止事件进一步传播
    }
    return QDialog::mouseMoveEvent(event); // 调用基类的 mouseMoveEvent 以确保默认行为被执行
}
详细解释
  1. 设置无标题栏窗口:

    • 使用 setWindowFlag(Qt::FramelessWindowHint) 去掉窗口的标题栏。
    • 使用 setAttribute(Qt::WA_DeleteOnClose) 确保窗口关闭时释放资源。
  2. 实现拖动逻辑:

    • 在 mousePressEvent 中,检查鼠标左键按下事件,记录按下时的鼠标位置与窗口左上角位置的差值,并标记为拖动状态。
    • 在 mouseMoveEvent 中,检查是否在拖动状态,并根据当前鼠标位置计算窗口的新位置。
    • 在 mouseReleaseEvent 中,检查鼠标左键释放事件,停止拖动状态。
代码行解释
  • dragPosition = event->globalPos() - frameGeometry().topLeft();:计算鼠标按下时的全局位置和窗口左上角位置的差值,这个差值在拖动过程中保持不变,用于计算新的窗口位置。
  • move(event->globalPos() - dragPosition);:根据当前鼠标位置和记录的差值计算窗口的新位置,并移动窗口。
  • event->accept();:接受事件,防止事件进一步传播给其他控件或处理程序。
  • return QDialog::mousePressEvent(event); 和类似的 mouseReleaseEvent 以及 mouseMoveEvent:调用基类的事件处理函数,确保默认行为被执行。

小结

通过重写 mousePressEvent、mouseMoveEvent 和 mouseReleaseEvent 函数,我们可以在没有标题栏的窗口中实现拖动功能。这种方法在需要自定义窗口外观的应用程序中非常有用。

希望这篇博客能帮助您在 Qt 应用程序中实现拖动无标题栏窗口的功能。如果您有任何问题或建议,请在下方留言讨论。感谢您的阅读!

相关推荐
小羊没烦恼!4 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
伞伞悦读4 天前
【第38期】Python 模块与包详解:import、from、模块搜索路径、包结构和 __init__
开发语言·python
这个DBA有点耶4 天前
MVCC深入:Read View、版本链与快照读——InnoDB并发控制的内核
数据库·mysql·架构
DBA_G4 天前
从地面到云霄:GBase数据库在民航三大场景的落地实践
数据库
自由能燃气设备4 天前
商用全预混低氮冷凝锅炉免费方案vs付费方案对比+选型避坑指南
大数据·数据库·人工智能
C语言小火车4 天前
C/C++ 为什么需要编译器?
开发语言·c++
科创致远4 天前
科创致远 ESOP 系统核心效能与实战价值展示
大数据·数据库·人工智能·精益工程
霍霍的袁4 天前
【C++】map 和 set 的使用 | 从用法到底层
开发语言·c++·学习·visual studio
孙启超4 天前
【AI开发之Rust】第 11 课:智能指针与内部可变性
开发语言·后端·rust
此生决int4 天前
深入理解C++系列(20)——C++11(下)
开发语言·c++