tags:

views:

1038

answers:

2

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?

+6  A: 

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:

while(app_running)
{
  if(EventPending)
    ProcessNextEvent();
}

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 :)

Arnold Spence
+6  A: 

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.

David Boddie
+1 Troll (this comment would be funnier on slashdot)
Arnold Spence