文章目录
- 效果图
- 引言
- 显示GIF图片(方法一)
- 显示GIF图片(方法二)
- GIF图片在场景中运动
效果图
引言
- 当我们想在
QGraphicsScene
显示或者说绘制一张GIF动图时,该如何处理? - Qt中的
QGraphicsItem
的paint
函数中,你不能直接绘制 GIF 动图。paint 函数是用来绘制QGraphicsItem
的当前状态的,它不支持动画。QGraphicsItem
是一个静态的对象,它不具备播放动画的能力。
显示GIF图片(方法一)
- 可以结合
QMovie
和QGraphicsItem
来展示GIF动画
- 创建一个自定义的
QGraphicsItem
。 - 使用
QMovie
来加载GIF文件,并通过信号和槽机制接受帧更新。 - 当GIF的新帧可用时,更新绘制的
QGraphicsItem
。 - QGraphicsItem的
paint()
函数将绘制来自QMovie
的当前帧。
class AnimatedGifItem : public QGraphicsItem
{
public:AnimatedGifItem(const QString &fileName, QGraphicsItem *parent = nullptr): QGraphicsItem(parent), movie(new QMovie(fileName)){QObject::connect(movie, &QMovie::frameChanged, [this](int /*frame*/){// 在每个新帧上触发重绘this->update(); });movie->start();}~AnimatedGifItem(){delete movie;}QRectF boundingRect() const override{return movie->currentPixmap().rect();}void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override{Q_UNUSED(option);Q_UNUSED(widget);auto pixmap = movie->currentPixmap();QPixmap scaledPixmap = pixmap.scaled(100, 100, Qt::KeepAspectRatio, Qt::SmoothTransformation);painter->drawPixmap(0, 0, scaledPixmap);}private:QMovie *movie;
};
- 然后只需要new出这些item并设置好位置加入到场景中即可
显示GIF图片(方法二)
- 你可以通过将
QMovie
对象作为QGraphicsProxyWidget
添加到QGraphicsScene
中来显示 GIF 动图,以QLabel
为载体。
QMovie *movie = new QMovie("C:\\Users\\KL162\\Desktop\\kk.gif", QByteArray(), nullptr);// 获取GIF动画的原始大小QSize movieSize = movie->scaledSize();// 设定新的大小,保持宽高比int scaledWidth = 200; // 或者其他你想要的宽度QSize scaledSize = movieSize.scaled(scaledWidth, scaledWidth, Qt::KeepAspectRatio);QGraphicsProxyWidget *proxyWidget = new QGraphicsProxyWidget();QLabel *label = new QLabel;label->setMovie(movie);label->setFixedSize(scaledSize);movie->start();proxyWidget->setWidget(label);proxyWidget->setPos(0, 0);scene.addItem(proxyWidget);
GIF图片在场景中运动
- 要使图片在
QGraphicsScene
中随机移动,你可以使用QTimer
来定期更改它的位置。以下是如何实现这个功能的步骤:
- 创建一个 QTimer 对象。
- 连接 QTimer 的 timeout 信号到一个槽函数,该槽函数将移动 QGraphicsProxyWidget。
- 启动 QTimer。
QGraphicsScene scene;scene.setSceneRect(0, 0, 600, 600);scene.setItemIndexMethod(QGraphicsScene::NoIndex); // 设置场景的项索引方法,NoIndex表示场景不使用索引来优化项的遍历和碰撞检测。// AnimatedGifItem *gifItem = new AnimatedGifItem("C:\\Users\\KL162\\Desktop\\kk.gif");// AnimatedGifItem *gifItem2 = new AnimatedGifItem("C:\\Users\\KL162\\Desktop\\kk.gif");// AnimatedGifItem *gifItem3 = new AnimatedGifItem("C:\\Users\\KL162\\Desktop\\kk.gif");// gifItem->setPos(100, 100);// gifItem2->setPos(400, 400);// gifItem3->setPos(300, 300);// scene.addItem(gifItem);// scene.addItem(gifItem2);// scene.addItem(gifItem3);QMovie *movie = new QMovie("C:\\Users\\KL162\\Desktop\\kk.gif", QByteArray(), nullptr);// 获取GIF动画的原始大小QSize movieSize = movie->scaledSize();// 设定新的大小,保持宽高比int scaledWidth = 200; // 或者其他你想要的宽度QSize scaledSize = movieSize.scaled(scaledWidth, scaledWidth, Qt::KeepAspectRatio);QGraphicsProxyWidget *proxyWidget = new QGraphicsProxyWidget();QLabel *label = new QLabel;label->setMovie(movie);label->setFixedSize(scaledSize);movie->start();proxyWidget->setWidget(label);proxyWidget->setPos(0, 0);scene.addItem(proxyWidget);QGraphicsView *view = new QGraphicsView(&scene);view->setRenderHint(QPainter::Antialiasing); // 设置视图的渲染提示,开启抗锯齿,以提高绘制质量view->setCacheMode(QGraphicsView::CacheBackground); // 设置视图的缓存模式,缓存背景以提高性能。view->setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate); // 设置视图的视口更新模式,只有当项的边界矩形发生变化时才更新视口view->setDragMode(QGraphicsView::ScrollHandDrag); // 设置视图的拖动模式,允许用户通过拖动来移动视图view->resize(400, 300);view->show();// 创建一个 QTimer 对象QTimer *timer = new QTimer();// 连接 QTimer 的 timeout 信号到一个槽函数QObject::connect(timer, &QTimer::timeout, [&](){// 获取随机生成器实例QRandomGenerator *randGen = QRandomGenerator::global();// 随机生成新的 x 和 y 坐标int newX = randGen->bounded(scene.width() - proxyWidget->boundingRect().width());int newY = randGen->bounded(scene.height() - proxyWidget->boundingRect().height());// 设置 QGraphicsProxyWidget 的新位置proxyWidget->setPos(newX, newY); });// 启动 QTimertimer->start(1000); // 每秒移动一次
- 此处以方法二的为例的,使用方法一显示图片在场景中一样可移动