2009-04-03 8 views
3

Ok, also ich habe eine QGraphicsScene in einer Klasse namens Auge. Ich nenne eine Funktion:Qt: QGraphicsScene nicht aktualisiert, wenn ich es erwarten würde

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; 
      } 
    } 
} 

, das für jede Folie ruft:

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); 
} 

Nun, ich würde erwarten, dass dies einen Satz von Bildern angezeigt werden, für 5 Sekunden warten, dann die nächste Anzeige, und so auf. Stattdessen wird nichts angezeigt, bis alle Folien bearbeitet wurden und dann die letzten vier Bilder angezeigt werden. Ich habe versucht, an jedem Ort zu nennen, an dem ich mich vorstellen konnte, und es hat nichts getan. Es sieht so aus, als ob die Szene nur aktualisiert wird, wenn die Funktion playSequence zurückkehrt. Irgendwelche Ideen was hier vor sich geht?

Antwort

7

Dies ist die Art von Verhalten, die oft in ereignisgesteuerten GUI-Frameworks zu sehen ist, wenn man fortlaufende Animation machen möchte. Ich werde raten, dass Auge :: playSequence von einem Knopfklick oder vielleicht von irgendeinem Punkt während des Startcodes der Anwendung angerufen wird? Auf jeden Fall, hier ist was los ist.

Qt verwendet den Hauptanwendungs-Thread, um eine Ereignisschleife zu steuern. Die Ereignisschleife ist so etwas wie diese:

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

Das Problem, das Sie sehen, ist, dass Updates auf den Bildschirm während eines Paint-Ereignisses fertig ist. Wenn Sie während eines Mausklick-Ereignisses oder eines anderen Ereignisses Code ausführen, wird die gesamte Zeichnung, die Sie gerade bearbeiten, in die Warteschlange gestellt und beim nächsten Mal-Ereignis auf den Bildschirm gezogen. Manchmal dauert es eine Weile, bis dies eintritt.

Der beste Weg, dies anzugehen, ist, Ihren Ansatz ein wenig zu ändern. Eine Möglichkeit besteht darin, die While-Schleife wegzuwerfen und einen QTimer-Satz einzurichten, der alle 5 Sekunden ausgelöst wird. Im Timer-Slot können Sie eine Folie zeichnen. Wenn der Timer erneut ausgelöst wird, zeichnen Sie die nächste Folie usw.

Wenn Sie eine direktere und weniger elegante schnelle Lösung wünschen, rufen Sie direkt nach Ihrem Aufruf von presentSlide (sequenceNum, i) qapp-> processEvents() auf. Dies zwingt die Anwendung (die meiste Zeit) dazu, alle in die Warteschlange gestellten Ereignisse zu löschen, die Paint-Ereignisse enthalten sollten.

ich auch dieses Auge erwähnen sollte :: presentSlide() Zugabe lediglich neue Szene-Objekte in der Szene bei jeder Iteration die, die Abdeckung, die während des letzten Aufrufs hinzugefügt wurden. Denken Sie an die Szene als eine Kühlschranktür und wenn Sie Szene() aufrufen addXXX werfen Sie mehr Kühlschrankmagnete an die Tür :)

7

Sie müssen die Ereignisschleife der Anwendung ausgeführt werden, um die Benutzeroberfläche aktualisiert zu halten. Der einfachste Weg, dies mit Ihrem Code zu tun, ist, QApplication :: processEvents() in Ihrer inneren while-Schleife aufzurufen.

Viele Menschen würden Ihre While-Schleife für ineffizient halten - schließlich warten Sie nur auf einen bestimmten Zeitraum. Vielleicht möchten Sie darüber nachdenken, Ihren Code neu zu strukturieren, um stattdessen einen Timer zu verwenden.

Sie könnten ein QTimer-Objekt im Konstruktor Ihrer Augenklasse erstellen, ein Timeout von 5 Sekunden festlegen und sein timeout() -Signal mit einem Slot in Ihrer Augenklasse verbinden, der den Index in den Foliensatz und die Aufrufe aktualisiert presentSlide(). Sie würden den Timer in der Funktion playSequence() starten.