Qt:QGraphicsScene 在我期望的时候没有更新

Posted

技术标签:

【中文标题】Qt:QGraphicsScene 在我期望的时候没有更新【英文标题】:Qt: QGraphicsScene not updating when I would expect it to 【发布时间】:2009-04-03 22:08:18 【问题描述】:

好的,所以我在名为 eye 的课程中​​有一个 QGraphicsScene。我调用一个函数:

void eye::playSequence(int sequenceNum) 

    for (int i=0; i<sequences[sequenceNum].numberOfSlides(); i++) 
        presentSlide(sequenceNum, i);
        time_t start;
            time(&start);
            bool cont=false;
            while (!cont) 
                time_t now;
                time(&now);
                double dif;
                dif=difftime(now, start);
                if (dif>5.0)
                    cont=true;
            
    

每张幻灯片调用:

void eye::presentSlide(int sequenceNum, int slideNum) 

    Slide * slide=sequences[sequenceNum].getSlide(slideNum);

    QGraphicsPixmapItem * pic0=scene.addPixmap(slide->getStimulus(0)->getImage());
    pic0->setPos(0,0);

    QGraphicsPixmapItem * pic1=scene.addPixmap(slide->getStimulus(1)->getImage());
    pic1->setPos(horizontalResolution-350,0);

    QGraphicsPixmapItem * pic2=scene.addPixmap(slide->getStimulus(2)->getImage());
    pic2->setPos(horizontalResolution-350,verticalResolution-450);

    QGraphicsPixmapItem * pic3=scene.addPixmap(slide->getStimulus(3)->getImage());
    pic3->setPos(0,verticalResolution-450);

现在,我希望这会显示一组图像,等待 5 秒,然后显示下一个,依此类推。相反,在处理完所有幻灯片并显示最后四个图像之前,它不会显示任何内容。我试过在我能想象到的每个地方都打电话给scene.update(),但它什么也没做。似乎场景仅在 playSequence 函数返回时更新。有什么想法吗?

【问题讨论】:

【参考方案1】:

当人们想要制作连续动画时,这种行为在事件驱动的 GUI 框架中很常见。我猜 eye::playSequence 是通过单击按钮调用的,还是从应用程序启动代码期间的某个时间点调用的?无论如何,这就是发生的事情。

Qt 使用主应用程序线程来驱动事件循环。事件循环是这样的:

while(app_running)

  if(EventPending)
    ProcessNextEvent();

您看到的问题是屏幕更新是在绘制事件期间完成的。如果您在鼠标单击事件或任何其他事件期间运行某些代码,那么您正在执行的所有绘图都会排队,并将在下一个绘图事件时绘制到屏幕上。有时这需要一段时间才能理解。

解决此问题的最佳方法是稍微改变您的方法。一种方法是丢弃您的 while 循环并设置一个 QTimer 设置为每 5 秒触发一次。在计时器插槽中,您可以绘制一张幻灯片。当计时器再次触发时,绘制下一张幻灯片,等等。

如果您想要一个更直接且不太优雅的快速修复,请尝试在调用 presentSlide(sequenceNum, i) 之后立即调用 qapp->processEvents()。这(大部分时间)将强制应用程序清除所有排队的事件,其中应该包括绘制事件。

我还应该提到 eye::presentSlide() 只是在每次迭代时向场景中添加新的场景对象,覆盖上次调用期间添加的对象。将场景想象成冰箱门,当您调用 scene().addXXX 时,您会在门上扔更多冰箱磁铁 :)

【讨论】:

【参考方案2】:

您需要让应用程序的事件循环运行以保持用户界面更新。从代码中执行此操作的最简单方法是在内部 while 循环中调用 QApplication::processEvents()。

许多人会认为您的 while 循环效率低下 - 毕竟,您只是在等待给定的时间段过去。您可能需要考虑重组代码以使用计时器。

你可以在你的 eye 类的构造函数中创建一个 QTimer 对象,设置一个 5 秒的超时时间,并将它的 timeout() 信号连接到你的 eye 类中的一个插槽,该插槽将索引更新到幻灯片集并调用 presentSlide ()。您将在 playSequence() 函数中启动计时器。

【讨论】:

以上是关于Qt:QGraphicsScene 在我期望的时候没有更新的主要内容,如果未能解决你的问题,请参考以下文章

qt - 在 QGraphicsScene 中如何捕捉特定项目

Qt - 如何将 QGraphicsScene 缩放到 QGraphicsView

使用 Qt 的 QGraphicsScene/QGraphicsView 进行 2D 游戏

简化 Qt 程序,我无法使用 QGraphicsScene 在 Qt 中显示图像

QT 在 QGraphicsScene 上方显示一个 QWidget

Qt:选择的项目出现在 QGraphicsScene 的顶部