Qt官方案例知识点总结(拖放操作——Drag And Drop Robot )


QPixmap轮廓剪裁

去掉Pixmap的外围部分,如下:

cpp 复制代码
QPixmap pixmap("./img");
//调用createHeuristicMask(),再调用setMask
pixmap.setMask(pixmap.createHeuristicMask());

效果对比:

------》

可以看到以图像内轮廓为边界线,无关的白色区域被抹去了


QGraphicsItem中开启拖动QDrag

重写QGraphicsItem的鼠标移动事件,在移动事件中开启拖动

cpp 复制代码
void ColorItem::mouseMoveEvent(QGraphicsSceneMouseEvent * event) {
    //判断拖动距离,使用qt推荐的距离QApplication::startDragDistance()
    if (QLineF(event -> screenPos(), event -> buttonDownScreenPos(Qt::LeftButton))
        .length() < QApplication::startDragDistance()) {
        return;
    }

  	//创建拖动对象
    QDrag * drag = new QDrag(event -> widget());
    //创建数据对象,并设置给本次拖动,这样本次拖动就有数据了
  	QMimeData * mime = new QMimeData;
    drag -> setMimeData(mime);

    QImage image(":/images/head.png");
    mime -> setImageData(image);//可以设置图像数据
  
    mime -> setColorData(color);//颜色数据
  
    mime -> setText(QString("#%1%2%3")
        .arg(color.red(), 2, 16, QLatin1Char('0'))
        .arg(color.green(), 2, 16, QLatin1Char('0'))
        .arg(color.blue(), 2, 16, QLatin1Char('0')));//字符串数据

    QPixmap pixmap(34, 34);
    pixmap.fill(Qt::white);
    drag -> setPixmap(pixmap);//设置拖动过程中在鼠标处显示的图片
    drag->setHotSpot(QPoint(15, 20));//设置鼠标在图片里的位置偏移

    drag -> exec();//开启本次拖动
}

qt推荐的拖动距离阈值:QApplication::startDragDistance() ,超过这个距离才启用拖动

创建的拖动对象 (QDrag * drag)可以指定父对象也可以不指定,他会在这次拖动结束时自动释放,无论这次拖动有没有被drop接收

创建的数据对象QMimeData在设置给拖动对象后也不用管他的释放(drag -> setMimeData(mime);),会跟着拖动对象一起释放

同时还可以设置鼠标在拖动的过程下面跟随着图片drag -> setPixmap(pixmap)

拖动执行函数

cpp 复制代码
Qt::DropAction QDrag::exec(Qt::DropActions supportedActions = Qt::MoveAction)
Qt::DropAction QDrag::exec(Qt::DropActions supportedActions, Qt::DropAction defaultDropAction)

常用的行为就是复制、移动、空操作

这是一个阻塞函数,

拖动结束后可以获取到返回值 , 来获取到本次拖动最终执行了什么行为

supportedActions 可以指定本次拖动支持的行为

defaultDropAction可以指定本次拖动默认的行为


QMimeData携带自定义数据

**其中QMimeData可以设置自定义的数据,**需要继承重写或者调用setData方法

  • 使用setData方法

他的第一个参数是一个字符串,指定数据的类型,可以自己定义

第二个参数是QByteArray,即要传输的数据

比如数据是1个结构体

结构体需要提供转成QByteArray的方法从QByteArray转到结构体的方法

cpp 复制代码
// 自定义数据结构
struct Person {
    QString name;
    int age;
    
    // 序列化到 QByteArray
    QByteArray serialize() const {
        QByteArray data;
        QDataStream stream(&data, QIODevice::WriteOnly);
        stream << name << age;
        return data;
    }
    
    // 从 QByteArray 反序列化
    static Person deserialize(const QByteArray &data) {
        QDataStream stream(data);
        QString name;
        int age;
        stream >> name >> age;
        return {name, age};
    }
};

创建自定义数据 ,指定类型的字符串可以自己随便写

cpp 复制代码
// 创建自定义数据
Person person{"Alice", 30};

// 序列化并设置到 QMimeData
QMimeData *mimeData = new QMimeData;
mimeData->setData("application/x-custom-person", person.serialize());

接收方解析自定义数据

cpp 复制代码
// 获取 QMimeData(例如从拖放事件)
const QMimeData *mimeData = event->mimeData();

// 检查是否存在自定义数据
if (mimeData->hasFormat("application/x-custom-person")) {
    // 提取数据并反序列化
    QByteArray data = mimeData->data("application/x-custom-person");
    Person person = Person::deserialize(data);
    
    qDebug() << "Received person:" << person.name << person.age;
}
  • 最小子类化QMimeData

即不重写相关虚函数,直接将数据作为其子类的成员变量,如下

比如把Person传出去

cpp 复制代码
//自定义数据
struct Person{
    QString name="11"  ;
    int age=15;
};

//子类化QMimeData,将自定义的类型作为其成员变量
class PersonMimeData: public QMimeData
{
public:
    Person person;
    //...还可以携带N多数据成员
};

创建自定义的MimeData

cpp 复制代码
//创建自定义的MimeData,并初始化里面自定义的数据,然后设置给QDrag对象
QDrag * drag = new QDrag(event -> widget());
PersonMimeData * mime = new PersonMimeData;
mime -> person = {"May", 18};
drag -> setMimeData(mime);

接受方解析收到的数据

cpp 复制代码
//从事件中获取mimedata(例如拖放事件),并强转成对应的类型
PersonMimeData * data = (PersonMimeData * ) event -> mimeData();
//取出内部携带的数据
qDebug() << data -> person.name << "   " << data -> person.age;

QGraphicsItem中的drop拖放

  • 需要QGraphicsItem接受拖放
cpp 复制代码
setAcceptDrops(true);
  • 需要重写dragEnterEvent事件,拖动进入事件

可对拖动携带数据做一些判断,判断是否有想要的数据

需要接受拖动 ,则需要显示的调用 event->setAccepted(true),否则后面的拖放事件会收不到数据

cpp 复制代码
void CustomItem::dragEnterEvent(QGraphicsSceneDragDropEvent * event) {
    //可以对拖过来的数据进行一些判断,有没有想要的数据
    if (event -> mimeData() -> hasColor()) {
        event -> setAccepted(true); //然后要接受这次拖放,否则后面drop事件无法收到拖放
        //同时可以改变下item的样式,
        isDragging = true; //自己定义的标志变量,标记拖动进入了
        update();
    } 
  	else 
    {
        event -> setAccepted(false); //否则拒绝这次拖放
    }
}
  • 需要重写拖放事件

主要就是获取本次拖放的mimeData

设置本次拖放最后采用的行为

cpp 复制代码
void CustomItem::dropEvent(QGraphicsSceneDragDropEvent *event)
{
    isDragging = false;
    update();
  	auto data=event->mimeData();
  	//取mimeData里的数据
  	//data->text();...
  	event->setDropAction(Qt::CopyAction);//还可以设置本次拖放最后使用的行为,QDrag的exec函数的返回值就会变成这里设置的
}
  • 需要重写拖动离开事件

主要就是设置标记变量,表示拖动离开了

同时刷新下样式

cpp 复制代码
void CustomItem::dragLeaveEvent(QGraphicsSceneDragDropEvent * event) {
    Q_UNUSED(event);
    isDragging = false;
    update();
}

并行动画组QParallelAnimationGroup

可以在动画组里添加多个动画,这些动画可以同时进行

cpp 复制代码
QParallelAnimationGroup * animation = new QParallelAnimationGroup(this);

QPropertyAnimation * a1 = new QPropertyAnimation(target1, "rotation");
a1 -> setStartValue(5);
a1 -> setEndValue(-20);
animation -> addAnimation(a1);

QPropertyAnimation * a2 = new QPropertyAnimation(target2, "rotation");
a2 -> setStartValue(15);
a2 -> setEndValue(-30);
animation -> addAnimation(a2);
//.....可以添加多个动画,这些动画可以同时执行

animation -> setLoopCount(-1); //无限循环
animation -> start(); //并行动画组开启,多个动画同时运行

其中animation -> setLoopCount(-1); 参数设置为-1 ,可让动画无限循环


正弦动画曲线

动画曲线类型QEasingCurve::SineCurve,正弦曲线

可以使动画1个执行周期内产生一来一回的效果,来和回是完全相反的两个动画,如下

其他曲线没有来回的效果

比如QEasingCurve::OutQuad,如下

相关推荐
大魔王(已黑化)1 分钟前
LeetCode —— 94. 二叉树的中序遍历
数据结构·c++·算法·leetcode·职场和发展
csdndenglu5 分钟前
Qt QComboBox 下拉复选多选(multicombobox)
qt
南玖yy5 分钟前
解锁 C++26 的未来:从语言标准演进到实战突破
开发语言·数据库·c++·人工智能·c++23·c++基础语法
六点半8881 小时前
【蓝桥杯】第十六届蓝桥杯C/C++大学B组个人反思总结
c语言·c++·算法·蓝桥杯
✿ ༺ ོIT技术༻1 小时前
笔试强训:Day3
c++·笔记·算法
让我们一起加油好吗3 小时前
【C++】类和对象(中)——默认成员函数详解(万字)
开发语言·c++·visualstudio·类和对象
fhqlongteng3 小时前
一种动态分配内存错误的解决办法
运维·服务器·网络·c++
珊瑚里的鱼4 小时前
牛客网题解 | 栈的压入、弹出序列
开发语言·c++·笔记·算法·leetcode·stl
chuxinweihui7 小时前
初识c++
开发语言·c++·学习
Sunlight_7778 小时前
第六章 QT基础:9、Qt中数据库的操作
数据库·qt·oracle