【问题标题】:QPropertyAnimation not running immediately when QAbstractAnimation::start() is called调用 QAbstractAnimation::start() 时,QPropertyAnimation 不会立即运行
【发布时间】:2023-04-10 15:24:01
【问题描述】:

我正在尝试使用Qt 4.8.6 在Qt Creator 中使用QStackedWidgets 制作一个简单的多页小部件。目标是在进度条达到完整值后使QLabelQProgressBar 消失。我认为实现这一目标的最佳方法是串联使用QGraphicsOpacityEffectQPropertyAnimation,如下所示。

void MainWindow::AnimateStartScreen()
{
    //QSound::play("./Audio/THX-DeepNote-48Khz.wav");
    sleep(5);

    logoEffect = new QGraphicsOpacityEffect();
    logoAnimation = new QPropertyAnimation(logoEffect, "opacity");
    ui->startLogo->setGraphicsEffect(logoEffect);
    logoAnimation->setDuration(2000);
    logoAnimation->setStartValue(1);
    logoAnimation->setEndValue(0);
    logoAnimation->start();

    progressBarEffect = new QGraphicsOpacityEffect();
    progressBarAnimation = new QPropertyAnimation(progressBarEffect, "opacity");
    ui->startProgressBar->setGraphicsEffect(progressBarEffect);
    progressBarAnimation->setDuration(2000);
    progressBarAnimation->setStartValue(1);
    progressBarAnimation->setEndValue(0);
    progressBarAnimation->start();

    sleep(3);
}

然后由main 方法调用:

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;

    w.HideTitleBar();
    w.CenterWidget();
    //QMainWindow::showFullScreen();
    w.show();
    w.IncrementProgressbar();
    w.AnimateStartScreen();
    w.ChangePageTo(1);

    return a.exec();
}

这就是问题所在。我希望这个动画在我改变页面之前完成:

void MainWindow::ChangePageTo(int page)
{
    ui->stackedWidget->setCurrentIndex(page);
}

有什么方法可以延迟页面更改,直到我的动画完成?当我注释掉页面更改时,动画似乎直到在我的 main 方法中调用 QApplication::exec() 才开始,这可以通过 8 秒的等待时间(两个睡眠调用的组合)来证明,而不是 5调用QAbstractAnimation::start() 之前的第二次延迟。

我相信正在发生的事情是 sleep(3) 行正在停止运行 GUI 的线程,因此将动画的开始延迟了三秒钟。当 sleep 调用完成后,我想知道动画是否会尝试继续,但是由于页面更改,快速转换没有可见的效果。

如何在不停止动画运行的线程的情况下延迟 3 秒?或者有没有其他可以产生相同效果的建议?

【问题讨论】:

    标签: c++ qt qt4


    【解决方案1】:

    我相信发生的事情是 sleep(3) 行正在停止运行 GUI 的线程

    几乎可以肯定。要运行动画,您需要保持消息队列运行,在您发布的代码中,直到随后调用 a.exec() 才会发生。

    如果您确实需要在动画完成之前阻止 MainWindow::AnimateStartScreen 的执行,那么更好的办法是将调用 sleep(3) 替换为...

    while (progressBarAnimation->state() != QAbstractAnimation::Stopped)
      QCoreApplication::processEvents();
    

    (尽管您可能不得不使用传递给QCoreApplication::processEvents 的标志来获得所需的精确行为。)

    【讨论】:

    • 这样的无限循环是一个很大的开销和不必要的CPU使用。
    • 在什么情况下是无限循环? QCoreApplication::processEvents 将处理当前排队的那些事件,然后返回。如果需要超时,则调用允许指定超时的重载(因此我对指定标志等的评论)。
    • 我的意思是,你不是在等待事件,而是每一步都调用processEvents。这是相当繁重的操作。有一个 QEventLoop 类用于此类事情。检查我的答案。
    • @Dmitry Sazonov -- 我们似乎发现自己的矛盾是不必要的。我认为我们都在推动的一点是事件队列必须处于活动状态才能使动画进行。鉴于 OP 调用了sleep(3),我假设MainWindow::AnimateStartScreen 应该阻塞直到动画完成。如果这不是必需的,那么连接到QAbstractAnimaion::finished 信号——正如你所建议的——是一个更好的选择。关于您对QEventLoop 的评论,事实上QEventLoop::exec 只是QCoreApplication::processEvents 的包装。
    • @G.M.在动画完成之前,您的阻塞是正确的。
    【解决方案2】:

    使用下一个模式进行非阻塞等待(而不是睡眠):

    QEventLoop loop;
    connect( progressBarAnimation, &QAbstractAnimaion::finished, &loop, &QEventLoop::quit );
    loop.exec();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-11-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-25
      • 2011-05-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多