拖放具体分为以下几个事件:

  • QEvent::DragEnter
    当拖动文件进入到窗口/控件中时,触发该事件,它对应的子类是QDragEnterEvent

  • QEvent::DragLeave
    当拖动文件离开窗口/控件时,触发该事件,它对应的子类是QDragLeaveEvent

  • QEvent::DragMove
    当拖动文件在窗口/控件中移动时,触发该事件,它对应的子类是QDragMoveEvent

  • QEvent::Drop
    当拖动文件在窗口/控件中释放时,触发该事件,它对应的子类是QDropEvent

本节通过一个向QTextEdit中拖放文本文件的案例,来讲解拖放事件
122.gif

1. 自定义控件TextEditX

自定义一个标签控件TextEditX,让它继承自QTextEdit,然后重写拖放相关的函数。

1.1 添加 TextEditX 类

首先,在左侧项目文件名上右键,选择 “Add New…”,选择 “cpp Class”,先继承自QWidget,如下:
image-20260820104546551

然后,把父类由QWidget修改为QTextEdit,如下:

// texteditx.h
#include <QTextEdit>

class TextEditX : public QTextEdit {
    Q_OBJECT
public:
    explicit TextEditX(QWidget *parent = nullptr);

signals:
};

// texteditx.cpp
#include "texteditx.h"

TextEditX::TextEditX(QWidget *parent) : QTextEdit{parent}
{
}

1.2 重写拖放函数

首先,来到textedit.h,声明4个拖放函数,如下::

#include <QDragEnterEvent>
#include <QDragLeaveEvent>
#include <QDragMoveEvent>
#include <QDropEvent>

class TextEditX : public QTextEdit {

protected:
    void dragEnterEvent(QDragEnterEvent *e);
    void dragMoveEvent(QDragMoveEvent *e);
    void dragLeaveEvent(QDragLeaveEvent *e);
    void dropEvent(QDropEvent *e);
};

然后,来到textedit.cpp 实现这4个函数(这里仅仅是加一句打印):

TextEditX::TextEditX(QWidget *parent) : QTextEdit{parent}
{
    this->setAcceptDrops(true);
}

void TextEditX::dragEnterEvent(QDragEnterEvent *e)
{
    qDebug() << "dragEnterEvent";

    // 判断是正常的文件,表明用户可以在这个窗口部件上拖放对象。
    // 默认情况下,窗口部件是不接受拖动的。Qt会自动改变光标来向用户说明这个窗口部件是不是有效的放下点
    e->acceptProposedAction();
}

void TextEditX::dragMoveEvent(QDragMoveEvent *e)
{
    qDebug() << "dragMoveEvent";
}

void TextEditX::dragLeaveEvent(QDragLeaveEvent *e)
{
    qDebug() << "dragLeaveEvent";
}

void TextEditX::dropEvent(QDropEvent *e)
{
    qDebug() << "dropEvent";
}

1.3 将 TextEditX 显示到界面

来到drag_widget.cpp,在构造函数中添加 TextEditX 控件,如下:

#include "texteditx.h"

DragWidget::DragWidget(QWidget* parent) : QWidget{parent}
{
    QVBoxLayout* verticalLayout = new QVBoxLayout(this);
    verticalLayout->setSpacing(0);
    verticalLayout->setContentsMargins(10, 10, 10, 10);

    // 添加一个TextEdit
    TextEditX* textEdit = new TextEditX(this);
    textEdit->setPlaceholderText("支持文件拖放的方式,来打开文件");
    verticalLayout->addWidget(textEdit);
}

此时,运行程序并拖放一个文本文件到TextEditX中,可以看到控制台依次打印如下:
image-20260820104615253

2. 实现打开文件功能

只需修改dropEvent() 函数,如下:

#include <QFile>
#include <QMimeData>

void TextEditX::dropEvent(QDropEvent* event)
{
    qDebug() << "dropEvent";
    QList<QUrl> urls = event->mimeData()->urls();
    if ( urls.isEmpty() ) {
        return;
    }

    // toLocalFile(): 将 file:///C:/path/to/file.txt 格式的 URL 转换为本地文件系统路径 C:/path/to/file.txt
    QString fileName = urls.first().toLocalFile();
    qDebug() << urls.first() << " : " << fileName;

    QFile file(fileName);
    if ( file.open(QIODevice::ReadOnly) ) {
        setPlainText(file.readAll());
    }
}

拖放一个桌面文件到TextEditX 中,效果如下:
image-20260820104638750

3. 实现鼠标滚轮放大字体

以上在TextEditX 中显示的文本,字体大小固定。接下来实现,通过鼠标滚轮来设置字体大小

首先,在texteditx.h中,声明鼠标滚轮滚动的事件wheelEvent(),如下:

class TextEditX : public QTextEdit
{
protected:
    void wheelEvent(QWheelEvent* e);
};

然后,实现wheelEvent()函数:

#include <QApplication>

void TextEditX::wheelEvent(QWheelEvent *e)
{
    // 可以通过angleDelta()方法来判断滚轮的滚动方向。
    // angleDelta()返回一个QPoint对象,其中x()表示水平滚动的角度,y()表示垂直滚动的角度。
    // 通常,我们主要关注垂直滚动方向。

    if (QApplication::keyboardModifiers() == Qt::ControlModifier) {  // ctrl键的判断
        if (e->angleDelta().y() > 0) {                               // scroll up
            this->zoomIn();
        } else {  // scroll down
            this->zoomOut();
        }
    }
    QTextEdit::wheelEvent(e);  // 调用基类的 wheelEvent 处理函数,确保其他默认行为正常
}