可拖放图标示例

Draggable 图标示例展示了如何在同一应用程序的部件之间以及不同应用程序之间拖放图像数据。

在使用拖放的许多情况下,用户从一个特定的部件开始拖放,然后将有效载荷放到另一个部件上。在本例中,我们通过子类QLabel 来创建用作拖放源的标签,并将其放置在QWidgets 中,这些标签既是容器,也是拖放点。

此外,在进行拖放操作时,我们希望发送的不仅仅是图像。我们还希望发送有关用户在图像中点击位置的信息,以便用户将图像精确地放置在拖放目标上。这种详细程度意味着我们必须为数据创建自定义 MIME 类型。

DragWidget 类定义

我们用来显示图标的图标部件是QLabel 的子类:

class DragWidget : public QFrame
{
public:
    explicit DragWidget(QWidget *parent = nullptr);

protected:
    void dragEnterEvent(QDragEnterEvent *event) override;
    void dragMoveEvent(QDragMoveEvent *event) override;
    void dropEvent(QDropEvent *event) override;
    void mousePressEvent(QMouseEvent *event) override;
};

由于QLabel 类提供了我们对图标的大部分要求,因此我们只需重新实现QWidget::mousePressEvent() 以提供拖放功能。

DragWidget 类的实现

DragWidget 构造函数会在 widget 上设置一个属性,确保在关闭时将其删除:

DragWidget::DragWidget(QWidget *parent)
    : QFrame(parent)
{
    setMinimumSize(200, 200);
    setFrameStyle(QFrame::Sunken | QFrame::StyledPanel);
    setAcceptDrops(true);

    QLabel *boatIcon = new QLabel(this);
    boatIcon->setPixmap(QPixmap(":/images/boat.png"));
    boatIcon->move(10, 10);
    boatIcon->show();
    boatIcon->setAttribute(Qt::WA_DeleteOnClose);

    QLabel *carIcon = new QLabel(this);
    carIcon->setPixmap(QPixmap(":/images/car.png"));
    carIcon->move(100, 10);
    carIcon->show();
    carIcon->setAttribute(Qt::WA_DeleteOnClose);

    QLabel *houseIcon = new QLabel(this);
    houseIcon->setPixmap(QPixmap(":/images/house.png"));
    houseIcon->move(10, 80);
    houseIcon->show();
    houseIcon->setAttribute(Qt::WA_DeleteOnClose);
}

要实现从图标拖动,我们需要对鼠标按下事件采取行动。为此,我们需要重新实现QWidget::mousePressEvent() 并设置一个QDrag 对象。

void DragWidget::mousePressEvent(QMouseEvent *event)
{
    QLabel *child = static_cast<QLabel*>(childAt(event->position().toPoint()));
    if (!child)
        return;

    QPixmap pixmap = child->pixmap();

    QByteArray itemData;
    QDataStream dataStream(&itemData, QIODevice::WriteOnly);
    dataStream << pixmap << QPoint(event->position().toPoint() - child->pos());

由于我们将发送图标的像素图数据和用户在图标窗口小部件中点击的信息,因此我们构建了一个QByteArray ,并使用QDataStream 对细节进行打包。

为了实现互操作性,拖放操作使用 MIME 类型来描述其包含的数据。在 Qt XML 中,我们使用QMimeData 对象来描述这些数据:

    QMimeData *mimeData = new QMimeData;
    mimeData->setData("application/x-dnditemdata", itemData);

我们为此选择了一种非官方的 MIME 类型,并为 MIME 数据对象提供了QByteArray

拖放操作本身由QDrag 对象处理:

    QDrag *drag = new QDrag(this);
    drag->setMimeData(mimeData);
    drag->setPixmap(pixmap);
    drag->setHotSpot(event->position().toPoint() - child->pos());

在此,我们将数据传递给拖放对象,设置操作过程中光标旁将显示的像素图,并定义热点位置,将该像素图的位置置于光标下方。

示例项目 @ code.qt.io

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.