使用QMovie和Qt C ++中的信号/插槽在GIF之间导航

时间:2018-02-10 16:03:32

标签: c++ qt animation synchronization

我使用Qt QMovie播放GIF集合。在到达GIF的最后一帧时,我断开信号,停止QMovie并启动下一个QMovie。在此步骤之前,代码工作正常。

在此之后,我将介绍可以在GIF中导航的下一个和上一个按钮。这些按钮的onClick操作执行与上面相同的操作,除了不等待最后一帧,我立即断开连接并停止电影。

这会随机导致所有GIF播放速度超过正常速度。而且,即使在帧结束之前,即将到来的GIF也会突然导航到下一个GIF。

此效果会以指数方式消耗大量内存。终于崩溃了应用程序。

这是我的头文件

class AnimationBox : public QWidget
{
    Q_OBJECT

public:
    explicit AnimationBox(QWidget *parent = 0);
    ~AnimationBox();

private slots:
    void loopAnimation(int frame);
    void changeSlide(int direction = 1);
    void prevGIFSlot();
    void nextGIFSlot();

private:
    Ui::AnimationBox *ui;
    std::vector<QMovie*> movieVector;  
    int currentMovieIndex;
};

这是我的cpp文件

AnimationBox::AnimationBox(QWidget *parent) 
: QWidget(parent)
, ui(new Ui::AnimationBox),
{
    ui->setupUi(this);

    currentMovieIndex = 0;
    movieVector.push_back(new QMovie("/Users/qq/Desktop/gif1.gif"));
    movieVector.push_back(new QMovie("/Users/qq/Desktop/gif2.gif"));
    movieVector.push_back(new QMovie("/Users/qq/Desktop/gif3.gif"));

    ui->movieLabel->setMovie(movieVector[currentMovieIndex]);
    movieVector[currentMovieIndex]->start();

    connect(movieVector[currentMovieIndex], SIGNAL(frameChanged(int)), this, SLOT(loopAnimation(int)));
    connect(ui->leftButton, SIGNAL(clicked()), this, SLOT(prevGIFSlot()));
    connect(ui->rightButton, SIGNAL(clicked()), this, SLOT(nextGIFSlot()));

}

void AnimationBox::loopAnimation(int frame)
{    
    if (frame == movieVector[currentMovieIndex]->frameCount() - 1)
    {
        disconnect(movieVector[currentMovieIndex], SIGNAL(frameChanged(int)), this, SLOT(loopAnimation(int)));
        movieVector[currentMovieIndex]->stop();
        changeSlide();
    }
}

void AnimationBox::prevGIFSlot()
{
    disconnect(movieVector[currentMovieIndex], SIGNAL(frameChanged(int)), this, SLOT(loopAnimation(int)));
    movieVector[currentMovieIndex]->stop();        
    changeSlide(-1);
}

void AnimationBox::nextGIFSlot()
{
    disconnect(movieVector[currentMovieIndex], SIGNAL(frameChanged(int)), this, SLOT(loopAnimation(int)));
    movieVector[currentMovieIndex]->stop();        
    changeSlide(1);
}

void AnimationBox::changeSlide(int direction)
{
    currentMovieIndex = (currentMovieIndex + direction) % movieVector.size();
    ui->movieLabel->setMovie(movieVector[currentMovieIndex]);
    movieVector[currentMovieIndex]->start();

    connect(movieVector[currentMovieIndex], SIGNAL(frameChanged(int)), this, SLOT(loopAnimation(int)));
}

1 个答案:

答案 0 :(得分:0)

  

此外,即将到来的GIF也会突然导航到下一个GIF   在到达帧结束之前。

这是因为在加载最后一帧时调用了一个插槽loopAnimation(int frame),并且您的插槽会停止播放电影.. 在播放帧本身之前足够早,因此它会被切断... 这个微小的变化向您展示了如何避免这种情况:

void AnimationBox::loopAnimation(int frame)
{
    if (frame == 0)
    {
        disconnect(movieVector[currentMovieIndex], SIGNAL(frameChanged(int)), this, SLOT(loopAnimation(int)));
        movieVector[currentMovieIndex]->stop();
        changeSlide();
    }
}

请注意,这是一个条件解决方案,因为您实际上在连接到插槽之前启动了电影..所以当帧最初为0时它不会被击中,但它会在下一个动画周期被击中,但是下一个动画在这里停止。如果你改变你的代码东西..这可能不是最佳解决方案..但只需确保在停止电影之前播放最后一帧。

  

这会随机导致所有GIF播放速度超过正常值。

这是不可重复的!我可以运行你的代码而不会看到这个问题...这可能意味着它可能与你的标签的UI设计有关..或者GIF中的任何东西......如果你有任何设置,尝试将你的UI设置设置为默认值我们在代码中看不到的其他设置。底线:它在这里正常工作。

2条评论:

  • 最好使用Qt新的信号/插槽语法:

    connect(ui->leftButton, &QPushButton::clicked, this, &AnimationBox::prevGIFSlot);

  • 一个好的方法是在你启动对象的逻辑之前放置你的信号/插槽connect() (在你启动电影的情况下),在你开始的情况下电影..然后..你建立信号/插槽连接..我相信这不是一个好习惯。