QGraphicsScene中显示GIF动图,GIF图片在场景中移动

效果图

在这里插入图片描述
在这里插入图片描述

引言

  • 当我们想在QGraphicsScene显示或者说绘制一张GIF动图时,该如何处理?
  • Qt中的 QGraphicsItempaint 函数中,你不能直接绘制 GIF 动图。paint 函数是用来绘制 QGraphicsItem 的当前状态的,它不支持动画。QGraphicsItem 是一个静态的对象,它不具备播放动画的能力。

显示GIF图片(方法一)

  • 可以结合QMovieQGraphicsItem来展示GIF动画
  1. 创建一个自定义的QGraphicsItem
  2. 使用QMovie来加载GIF文件,并通过信号和槽机制接受帧更新。
  3. 当GIF的新帧可用时,更新绘制的QGraphicsItem
  4. 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 来定期更改它的位置。以下是如何实现这个功能的步骤:
  1. 创建一个 QTimer 对象。
  2. 连接 QTimer 的 timeout 信号到一个槽函数,该槽函数将移动 QGraphicsProxyWidget。
  3. 启动 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); });
    // 启动 QTimer
    timer->start(1000); // 每秒移动一次
  • 此处以方法二的为例的,使用方法一显示图片在场景中一样可移动
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值