Qt:QGraphicsScene 在我期望的时候没有更新
好的,我在一个名为 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 函数返回时更新。 你知道这里可能发生什么吗?
Ok so I've got a QGraphicsScene
in a class called eye. I call a function:
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;
}
}
}
which for each slide calls:
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);
}
Now, I would expect this to display one set of images, wait for 5 seconds, then display the next, and so on. Instead, it displays nothing until all the slides have been processed and then the last four images are displayed. I've tried calling scene.update()
in every place I could image and it didn't do anything. It seems like the scene only updates when the playSequence
function returns. Any ideas what might be going on here?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
当想要进行连续动画时,这是事件驱动的 GUI 框架中经常看到的一种行为。 我猜测 eye::playSequence 是通过单击按钮调用的,或者可能是从应用程序启动代码期间的某个时刻调用的? 无论如何,这就是正在发生的事情。
Qt 使用主应用程序线程来驱动事件循环。 事件循环是这样的:
您看到的问题是屏幕的更新是在绘制事件期间完成的。 如果您在鼠标单击事件或任何其他事件期间运行某些代码,那么您正在执行的所有绘图都会排队,并将在下一个绘图事件时绘制到屏幕上。 有时需要一段时间才能理解这一点。
解决这个问题的最佳方法是稍微改变一下你的方法。 一种方法是放弃 while 循环并设置 QTimer 设置为每 5 秒触发一次。 在计时器插槽中,您可以绘制一张幻灯片。 当计时器再次触发时,绘制下一张幻灯片等。
如果您想要更直接且不太优雅的快速修复,请尝试在调用presentSlide(sequenceNum, i)之后立即调用qapp->processEvents()。 这(大多数时候)将强制应用程序清除任何排队的事件,其中应包括绘制事件。
我还应该提到 eye::presentSlide() 只是在每次迭代时向场景添加新的场景对象,覆盖上次调用期间添加的对象。 将场景想象为冰箱门,当您调用 scene().addXXX 时,您会在门上扔更多的冰箱磁铁:)
This is the kind of behaviour that is often seen in event driven GUI frameworks when one wants to do continuous animation. I'm going to guess that eye::playSequence is called from a button click or maybe from some point during the application startup code? In any case, here is what's going on.
Qt uses the main application thread to drive an event loop. The event loop is something like this:
The problem you are seeing is that updates to the screen are done during a paint event. If you are running some code during a mouse click event or any other event, then all the drawing you are doing is queued up and will be drawn to the screen on the next paint event. Sometimes it takes awhile for this to sink in.
The best way to address this is to change your approach a bit. One way is to throw away your while loop and setup a QTimer set to fire every 5 seconds. In the timer slot you can draw one slide. When the timer fires again, draw the next slide, etc.
If you want a more direct and less elegant quick fix, try calling qapp->processEvents() right after your call to presentSlide(sequenceNum, i). This (most of the time) will force the application to clear out any queued up events which should include paint events.
I should also mention that eye::presentSlide() is merely adding new scene objects to the scene on each iteration covering the ones that were added during the last call. Think of the scene as a fridge door and when you call scene().addXXX you are throwing more fridge magnets on the door :)
您需要让应用程序的事件循环运行才能保持用户界面更新。 从代码中执行此操作的最简单方法是在内部 while 循环中调用 QApplication::processEvents() 。
许多人会认为 while 循环效率低下 - 毕竟,您只是在等待给定的时间段过去。 您可能需要考虑重构代码以使用计时器。
您可以在 Eye 类的构造函数中创建一个 QTimer 对象,设置 5 秒的超时,并将其 timeout() 信号连接到 Eye 类中的一个槽,该槽将索引更新到幻灯片集并调用 PresentSlide()。 您可以在 playSequence() 函数中启动计时器。
You need to let the application's event loop run in order to keep the user interface updated. The easiest way to do this from your code is to call QApplication::processEvents() in your inner while loop.
Many people would consider your while loop to be inefficient - after all, you are just waiting for a given period of time to elapse. You may want to think about restructuring your code to use a timer instead.
You could create a QTimer object in your eye class's constructor, set a time-out of 5 seconds, and connect its timeout() signal to a slot in your eye class which updates the index into the set of slides and calls presentSlide(). You would start the timer in the playSequence() function.