概要
Draggable Icons 示例演示如何在同一应用程序中的 widget 之间以及不同应用程序之间拖放图像数据。
- widget内部操作,只是MoveAction
- 拖拽到widget之外(application之内,或之间效果一样),会发生CopyAciton。 在本例中,我们使用QLabel创建用作拖拽源的图标,并将它们放在QWidget中,QWidget同时用作拖拽站点。此外,当拖放操作发生时,发送的不仅仅是图像。还需要发送有关用户在图像中单击的位置的信息,以便用户可以将其精确地放置在放置目标上。这种详细级别意味着我们必须为数据创建自定义的MIME类型。
QT5.14.2自带Examples:Draggable Icons
实现步骤
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();
}
}