2009-04-03 7 views
3

Ok, donc j'ai un QGraphicsScene dans une classe appelée eye. J'appelle une fonction:Qt: QGraphicsScene ne pas mettre à jour quand je m'attendais à

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

qui, pour chaque diapositive appelle:

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

Maintenant, je me attends à cette option pour afficher un ensemble d'images, attendez 5 secondes, puis afficher la suivante, et ainsi sur. Au lieu de cela, il n'affiche rien tant que toutes les diapositives n'ont pas été traitées et que les quatre dernières images sont affichées. J'ai essayé d'appeler scene.update() dans tous les endroits où je pouvais l'image et il n'a rien fait. Il semble que la scène ne soit mise à jour que lorsque la fonction playSequence retourne. Des idées sur ce qui pourrait se passer ici?

Répondre

7

C'est le genre de comportement que l'on voit souvent dans les frameworks GUI pilotés par les événements quand on veut faire de l'animation continue. Je vais deviner que eye :: playSequence est appelée à partir d'un clic sur un bouton ou peut-être à partir d'un point quelconque du code de démarrage de l'application? En tout cas, voici ce qui se passe.

Qt utilise le thread d'application principal pour piloter une boucle d'événements. La boucle d'événement est quelque chose comme ceci:

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

Le problème que vous voyez est que les mises à jour à l'écran sont faites lors d'un événement de peinture. Si vous exécutez du code au cours d'un événement de clic de souris ou de tout autre événement, tout le dessin que vous effectuez est mis en file d'attente et sera dessiné à l'écran lors de l'événement de peinture suivant. Parfois, il faut un certain temps pour que cela plonge.

La meilleure façon de résoudre ce problème est de changer quelque peu votre approche. Une façon est de jeter votre boucle while et de configurer un jeu QTimer à tirer toutes les 5 secondes. Dans la fente de la minuterie, vous pouvez dessiner une diapositive. Lorsque la minuterie se déclenche à nouveau, dessinez la diapositive suivante, etc.

Si vous voulez une solution plus directe et moins élégante, essayez d'appeler qapp-> processEvents() juste après votre appel à presentSlide (sequenceNum, i). Ceci (la plupart du temps) forcera l'application à effacer tous les événements en attente qui devraient inclure des événements de peinture.

Je dois également mentionner que eye :: presentSlide() ajoute simplement de nouveaux objets de scène à la scène à chaque itération couvrant ceux qui ont été ajoutés lors du dernier appel. Pensez à la scène comme une porte de réfrigérateur et quand vous appelez scene(). AddXXX vous lancez plus d'aimants de réfrigérateur sur la porte :)

7

Vous devez laisser la boucle d'événement de l'application s'exécuter afin de garder l'interface utilisateur à jour. La façon la plus simple de le faire à partir de votre code est d'appeler QApplication :: processEvents() dans votre boucle while interne. Beaucoup de gens considéreraient votre boucle de temps comme inefficace - après tout, vous attendez juste pour une période de temps donnée. Vous pouvez penser à la restructuration de votre code pour utiliser une minuterie à la place. Vous pouvez créer un objet QTimer dans le constructeur de votre classe œil, définir un délai d'expiration de 5 secondes et connecter son signal timeout() à un emplacement de votre classe eye qui met à jour l'index dans l'ensemble des diapositives et des appels presentSlide(). Vous démarrez la minuterie dans la fonction playSequence().

Questions connexes