QT5.14.2自带Examples:Draggable Icons

概要

Draggable Icons 示例演示如何在同一应用程序中的 widget 之间以及不同应用程序之间拖放图像数据。

  1. widget内部操作,只是MoveAction
  2. 拖拽到widget之外(application之内,或之间效果一样),会发生CopyAciton。
    在这里插入图片描述
    在本例中,我们使用QLabel创建用作拖拽源的图标,并将它们放在QWidget中,QWidget同时用作拖拽站点。此外,当拖放操作发生时,发送的不仅仅是图像。还需要发送有关用户在图像中单击的位置的信息,以便用户可以将其精确地放置在放置目标上。这种详细级别意味着我们必须为数据创建自定义的MIME类型。

实现步骤

main函数

#include <QApplication>
#include <QHBoxLayout>

#include "dragwidget.h"

int main(int argc, char *argv[])
{
    Q_INIT_RESOURCE(draggableicons);

    QApplication app(argc, argv);

    QWidget mainWidget;
    QHBoxLayout *horizontalLayout = new QHBoxLayout(&mainWidget);
    horizontalLayout->addWidget(new DragWidget);
    horizontalLayout->addWidget(new DragWidget);

    mainWidget.setWindowTitle(QObject::tr("Draggable Icons"));
    mainWidget.show();

    return app.exec();
}

DragWidget类

类定义
#ifndef DRAGWIDGET_H
#define DRAGWIDGET_H

#include <QFrame>

QT_BEGIN_NAMESPACE
class QDragEnterEvent;
class QDropEvent;
QT_END_NAMESPACE

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

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

#endif // DRAGWIDGET_H

类实现
#include <QtWidgets>

#include "dragwidget.h"

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);
}

void DragWidget::mousePressEvent(QMouseEvent *event)
{
    //返回widget坐标系中位置(x,y)处的可见子widget。
    QLabel *child = static_cast<QLabel*>(childAt(event->pos()));
    if (!child)
        return;
    //Qt为处理图像数据提供了四个类:QImage、QPixmap、QBitmap和QPicture。
    //QPixmap是为在屏幕上显示图像而设计和优化的
    QPixmap pixmap = *child->pixmap();

    QByteArray itemData;
    QDataStream dataStream(&itemData, QIODevice::WriteOnly);
    //itemData 存放图象数据和偏移量
    //event->pos() - child->pos()返回我们点击的位置,和图象原点位置的差
    //这样确保无论我们点击图象哪个位置,最后移动的距离都一致
    dataStream << pixmap << QPoint(event->pos() - child->pos());
    //QMimeData用于描述可以存储在剪贴板中并通过拖放机制传输的信息。
    QMimeData *mimeData = new QMimeData;
    mimeData->setData("application/x-dnditemdata", itemData);

	// //QDrag类支持基于MIME的拖放数据传输。
    QDrag *drag = new QDrag(this);
    drag->setMimeData(mimeData);
    drag->setPixmap(pixmap);
    //点击的偏移量:相对于指定pixmap的左上角坐标
    drag->setHotSpot(event->pos() - child->pos());

    //!start:在pixmap原有位置上,画出一个效果,表示正在被拖拽
    QPixmap tempPixmap = pixmap;
    QPainter painter;
    painter.begin(&tempPixmap);
    painter.fillRect(pixmap.rect(), QColor(127, 127, 127, 127));
    painter.end();

    child->setPixmap(tempPixmap);
    //!end:在pixmap原有位置上,画出一个效果,表示正在被拖拽

    //! start:被拖拽的效果
    //exec(支持的actions,默认的action)
    if (drag->exec(Qt::CopyAction | Qt::MoveAction, Qt::CopyAction) == Qt::MoveAction) {
        //如果是MoveAction,执行完拖拽则关闭
        //DropAction将在当前widget中创造新的pixmap
        child->close();
    } else {
        //不是MoveAction则必然是CopyAction
        child->show();//这条语句可以省略
        //CopyAction发生在另一个widgt,对于当前的pixmap需要更新一下
        child->setPixmap(pixmap);
    }
    //! end:被拖拽的效果
}

void DragWidget::dragEnterEvent(QDragEnterEvent *event)
{
    if (event->mimeData()->hasFormat("application/x-dnditemdata")) {
        if (event->source() == this) {
            event->setDropAction(Qt::MoveAction);
            event->accept();
        } else {
            //对本例而言,如果来源不是本widget,dropAction设置为CopyAction。
           // event->setDropAction(Qt::CopyAction);
            //event->accept();
            event->acceptProposedAction();
        }
    } else {
        event->ignore();
    }
}

//这部分代码并没有改变dragEnterEvent后的状态,所以可以省略
//void DragWidget::dragMoveEvent(QDragMoveEvent *event)
//{
//    if (event->mimeData()->hasFormat("application/x-dnditemdata")) {
//        if (event->source() == this) {
//            event->setDropAction(Qt::MoveAction);
//            event->accept();
//        } else {
//            event->acceptProposedAction();
//        }
//    } else {
//        event->ignore();
//    }
//}

//松开鼠标时,通过itemData,获取图标的pixmap值,和offset。创建新的图标
void DragWidget::dropEvent(QDropEvent *event)
{
    if (event->mimeData()->hasFormat("application/x-dnditemdata")) {
        QByteArray itemData = event->mimeData()->data("application/x-dnditemdata");
        QDataStream dataStream(&itemData, QIODevice::ReadOnly);

        QPixmap pixmap;
        QPoint offset;
        dataStream >> pixmap >> offset;

        QLabel *newIcon = new QLabel(this);
        newIcon->setPixmap(pixmap);
        newIcon->move(event->pos() - offset);
        newIcon->show();
        newIcon->setAttribute(Qt::WA_DeleteOnClose);

        if (event->source() == this) {
            event->setDropAction(Qt::MoveAction);
            event->accept();
        } else {
            event->acceptProposedAction();
        }
    } else {
        event->ignore();
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值