使用 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 应用程序中实现拖动无标题栏窗口的功能。如果您有任何问题或建议,请在下方留言讨论。感谢您的阅读!

相关推荐
wowocpp3 分钟前
查看 磁盘文件系统格式 linux ubuntu blkid ext4
linux·数据库·ubuntu
一点媛艺2 小时前
Kotlin函数由易到难
开发语言·python·kotlin
姑苏风2 小时前
《Kotlin实战》-附录
android·开发语言·kotlin
奋斗的小花生3 小时前
c++ 多态性
开发语言·c++
魔道不误砍柴功3 小时前
Java 中如何巧妙应用 Function 让方法复用性更强
java·开发语言·python
闲晨3 小时前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
老猿讲编程4 小时前
一个例子来说明Ada语言的实时性支持
开发语言·ada
Chrikk5 小时前
Go-性能调优实战案例
开发语言·后端·golang
幼儿园老大*5 小时前
Go的环境搭建以及GoLand安装教程
开发语言·经验分享·后端·golang·go
canyuemanyue5 小时前
go语言连续监控事件并回调处理
开发语言·后端·golang