--------------------------------------------------------------------------------------------------------------------------------
QPixmap轮廓剪裁
去掉Pixmap的外围部分,如下:
QPixmap pixmap("./img");
//调用createHeuristicMask(),再调用setMask
pixmap.setMask(pixmap.createHeuristicMask());
效果对比:
——》
可以看到以图像内轮廓为边界线,无关的白色区域被抹去了
---------------------------------------------------------------------------------------------------------------------------------
QGraphicsItem中开启拖动QDrag
重写QGraphicsItem的鼠标移动事件,在移动事件中开启拖动
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)
拖动执行函数
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转到结构体的方法
// 自定义数据结构
struct Person {QString name;int age;// 序列化到 QByteArrayQByteArray 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};}
};
创建自定义数据 ,指定类型的字符串可以自己随便写
// 创建自定义数据
Person person{"Alice", 30};// 序列化并设置到 QMimeData
QMimeData *mimeData = new QMimeData;
mimeData->setData("application/x-custom-person", person.serialize());
接收方解析自定义数据
// 获取 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传出去
//自定义数据
struct Person{QString name="11" ;int age=15;
};//子类化QMimeData,将自定义的类型作为其成员变量
class PersonMimeData: public QMimeData
{
public:Person person;//...还可以携带N多数据成员
};
创建自定义的MimeData
//创建自定义的MimeData,并初始化里面自定义的数据,然后设置给QDrag对象
QDrag * drag = new QDrag(event -> widget());
PersonMimeData * mime = new PersonMimeData;
mime -> person = {"May", 18};
drag -> setMimeData(mime);
接受方解析收到的数据
//从事件中获取mimedata(例如拖放事件),并强转成对应的类型
PersonMimeData * data = (PersonMimeData * ) event -> mimeData();
//取出内部携带的数据
qDebug() << data -> person.name << " " << data -> person.age;
---------------------------------------------------------------------------------------------------------------------------------
QGraphicsItem中的drop拖放
- 需要QGraphicsItem接受拖放
setAcceptDrops(true);
- 需要重写dragEnterEvent事件,拖动进入事件
可对拖动携带数据做一些判断,判断是否有想要的数据
若需要接受拖动,则需要显示的调用 event->setAccepted(true),否则后面的拖放事件会收不到数据
void CustomItem::dragEnterEvent(QGraphicsSceneDragDropEvent * event) {//可以对拖过来的数据进行一些判断,有没有想要的数据if (event -> mimeData() -> hasColor()) {event -> setAccepted(true); //然后要接受这次拖放,否则后面drop事件无法收到拖放//同时可以改变下item的样式,isDragging = true; //自己定义的标志变量,标记拖动进入了update();} else {event -> setAccepted(false); //否则拒绝这次拖放}
}
- 需要重写拖放事件
主要就是获取本次拖放的mimeData
设置本次拖放最后采用的行为
void CustomItem::dropEvent(QGraphicsSceneDragDropEvent *event)
{isDragging = false;update();auto data=event->mimeData();//取mimeData里的数据//data->text();...event->setDropAction(Qt::CopyAction);//还可以设置本次拖放最后使用的行为,QDrag的exec函数的返回值就会变成这里设置的
}
- 需要重写拖动离开事件
主要就是设置标记变量,表示拖动离开了
同时刷新下样式
void CustomItem::dragLeaveEvent(QGraphicsSceneDragDropEvent * event) {Q_UNUSED(event);isDragging = false;update();
}
---------------------------------------------------------------------------------------------------------------------------------
并行动画组QParallelAnimationGroup
可以在动画组里添加多个动画,这些动画可以同时进行
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,如下