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

相关推荐
BD_Marathon1 分钟前
SQL学习指南——创建和填充数据库
数据库·sql
TDengine (老段)2 分钟前
TDengine RPC 通信层深度解析 — 协议格式、连接管理与重试机制
大数据·数据库·rpc·架构·时序数据库·tdengine·涛思数据
ComputerInBook2 分钟前
C++ 17 相比 C++ 14 新增之特征
开发语言·c++·c++ 17
hanbr2 分钟前
Qt 进阶开发:主窗口、对话框、布局与常用控件全解析
qt
KaMeidebaby2 分钟前
卡梅德生物技术快报|噬菌体筛选全流程技术方案:弧菌抑菌菌株筛选、特性鉴定与效果测试
前端·数据库·其他·百度·新浪微博
蜀道山老天师3 分钟前
从零搭建 Prometheus 监控 MySQL:含二进制安装、授权、exporter 配置全流程
运维·数据库·mysql·adb·云原生·prometheus
yubin12855709234 分钟前
mysql正则函数REGEXP
android·数据库·mysql
我命由我123457 分钟前
Android Framework P2 - 开机启动 Zygote 进程、Zygote 的预加载机制
android·java·开发语言·python·java-ee·intellij-idea·zygote
JAVA面经实录91710 分钟前
Java Codex 企业标准Prompt库
java·开发语言·prompt
Evand J16 分钟前
【MATLAB例程】5个UAV 分布式围捕编队运动仿真 —— 基于PID控制
开发语言·分布式·matlab