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

文章目录

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

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

准备工作

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

创建自定义窗口类

让我们从创建一个基本的 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:调用基类的事件处理函数,确保默认行为被执行。

小结

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

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

相关推荐
数据智能老司机1 小时前
CockroachDB权威指南——SQL调优
数据库·分布式·架构
数据智能老司机1 小时前
CockroachDB权威指南——应用设计与实现
数据库·分布式·架构
数据智能老司机2 小时前
CockroachDB权威指南——CockroachDB 模式设计
数据库·分布式·架构
数据智能老司机20 小时前
CockroachDB权威指南——CockroachDB SQL
数据库·分布式·架构
数据智能老司机21 小时前
CockroachDB权威指南——开始使用
数据库·分布式·架构
我不会编程55521 小时前
Python Cookbook-5.1 对字典排序
开发语言·数据结构·python
李少兄21 小时前
Unirest:优雅的Java HTTP客户端库
java·开发语言·http
松果猿21 小时前
空间数据库学习(二)—— PostgreSQL数据库的备份转储和导入恢复
数据库
CoderIsArt21 小时前
QT中已知4个坐标位置求倾斜平面与倾斜角度
qt·平面
无名之逆21 小时前
Rust 开发提效神器:lombok-macros 宏库
服务器·开发语言·前端·数据库·后端·python·rust