Partage
  • Partager sur Facebook
  • Partager sur Twitter

[Qt] problème avec QTimer

Sujet résolu
    26 mai 2010 à 15:27:23

    Bonjour,

    j'ai un problème avec QTimer, il me fait totalement planter mon programme lorsque je l'utilise conjointement avec une autre librairie.

    j'ai déclaré dans ma classe (dérivée de QLabel avec un Q_OBJECT) un QTimer (m_timer)
    ensuite dans le démarrage de mon appli, je fais :
    m_timer.start(100);
    connect(&m_timer, SIGNAL(timeout()), this, SLOT(captureLoop()));

    dans captureLoop() (public slots)
    j'ai une fonction d'une autre librairie qui récupère une image
    et appelle une autre méthode de ma classe qui détecte un visage sur l'image et retourne la position du visage. La détection s'effectue via une fonction de ma seconde librairie.

    Sauf que dès qu'il arrive à la détection (la fonction de l'autre librairie en particulier), le programme me met un segmentation fault. Sans rentrer dans la fonction (mode debbugeur)

    Si je désactive la détection, tout fonctionne avec le Timer de Qt.

    Vous allez surement me dire : "ben le problème viens de la fonction de détection de ton autre librairie"

    Eh bien non, car si je supprime le timer de Qt et que j'appelle ma méthode manuellement, tout fonctionne (mais pas de boucle possible).

    J'ai l'impression que c'est le méta code crée par Qt pour les slots personnalisés qui pose problème...

    Merci de votre aide.


    • Partager sur Facebook
    • Partager sur Twitter
      26 mai 2010 à 16:45:04

      Bonjour,

      Déclare m_timer comme un pointeur... J'ai récemment travaillé sur les timers, et lors de la connexion par QObject::connect , c'était ça qui me faisait planter. :)
      • Partager sur Facebook
      • Partager sur Twitter
        26 mai 2010 à 16:55:07

        Ne t'inquiète pas, tout doit bien marcher le seul problème c'est ça :

        m_timer.start(100);

        il est probable qu'en 100ms ton appli n'est pas fini le premier traitement fait dans captureLoop(). Il te faut donc optimiser à mort ton code. Je te conseil de pré calculer tout ce que tu peux, si tu as des variables qui ne changent pas entre deux appels de captureLoop() alors initialise les ailleurs, enfin optimise ton traitement ^^.
        • Partager sur Facebook
        • Partager sur Twitter

        Ma chaine youtube, une notion de c++ en 5 min !

          26 mai 2010 à 17:24:11

          Le traitement pourrait faire planter le programme ? o_O
          • Partager sur Facebook
          • Partager sur Twitter
            26 mai 2010 à 18:04:09

            oui et non ^^, disons qu'il a pas fini de traiter la totalité du traitement et bim l'évènement du QTimer ce déclenche quand même, or ton appli n'est pas multi thread donc il va essayer de rappeler la même fonction qui n'a pas fini son traitement, résultat ton ordi ne sait plus ou il en est
            • Partager sur Facebook
            • Partager sur Twitter

            Ma chaine youtube, une notion de c++ en 5 min !

              26 mai 2010 à 18:32:31

              Citation : SixtyOne

              oui et non ^^, disons qu'il a pas fini de traiter la totalité du traitement et bim l'évènement du QTimer ce déclenche quand même, or ton appli n'est pas multi thread donc il va essayer de rappeler la même fonction qui n'a pas fini son traitement, résultat ton ordi ne sait plus ou il en est


              Non.

              Pour faire un peu plus long : La boucle de évènementielle de Qt ne peut pas fonctionner en même temps qu'un slot (sauf si tu fais du multithreading mais dans ce cas tu le saurais), quand Qt appelle un slot il sort de sa boucle et donc les événements ne sont pas gérés jusqu'à ce que le slot finisse.

              Edit : et pour répondre à Aure77, je pense que ça vient quand même de la méthode de détection quoique tu en penses :p peut-être un problème d'initialisation ou je ne sais quoi.
              Montre ton code avec QTimer qui plante et celui sans qui ne plante pas, ça serait plus évident à voir.
              • Partager sur Facebook
              • Partager sur Twitter
                26 mai 2010 à 20:30:55

                Lancement de l'application version qui marche pas :
                int MaClasse::run()
                {
                 // initialisations ....
                 if( initialisation OK )
                 {
                    m_timer.start(100);
                    connect(&m_timer, SIGNAL(timeout()), this, SLOT(captureLoop()));
                 }
                }
                

                Lancement de l'application version qui marche (une seule image car plus de boucle) mais s'affiche et plante pas :
                int MaClasse::run()
                {
                 // initialisations ....
                 if( initialisation OK )
                 {
                    captureLoop();
                 }
                }
                

                CaptureLoop :
                void MaClasse::captureLoop()
                {
                ostringstream score_str;
                Cercle c;
                // Capture la frame on la charge dans une matrice Mat
                capture >> frame;
                
                if( frame.empty() )
                	break;
                
                flip( frame, frame_copy, 1 );
                
                if(compteur>50 || compteur<1)
                {
                	compteur=0;
                	position_pt = giveRandomposition();
                	createRandomCreature(creature);
                	creature->setPosition(position_pt, ((double)NBCASES/(double)nb_cases));
                }
                compteur++;
                
                // Detection de visage
                if( detect_faces )
                {
                	// Appel de la fonction pour détecter et afficher les visages
                c = detect_and_draw_faces(2); // c'est dans cette fonction qui ma fait planter mon programme !!!!!!!
                
                	if(collisionCercle(creature->getPtGauche(), creature->getPtDroite(), c ))
                	{
                		 creature->updateScore(score);
                		 //score++;
                		 cout << "Collision - Score : " << score << endl;
                		 position_pt = giveRandomposition();
                		 createRandomCreature(creature);
                		 creature->setPosition(position_pt, ((double)NBCASES/(double)nb_cases));
                	}
                }
                
                
                // On affiche une grille
                if( show_grid )
                	draw_grid();
                
                creature->draw(frame_copy);
                score_str.str("");
                score_str << "Score : " << score;
                putText( frame_copy, score_str.str(), Point(6,12), CV_FONT_HERSHEY_SIMPLEX, 0.40, Scalar(0, 255, 0) );
                
                QImage test = Mat2QImage(frame_copy); // convertit Mat en QImage
                this->setPixmap(QPixmap::fromImage(test));
                this->update();
                }
                

                Méthode de détection :
                Cercle MaClasse::detect_and_draw_faces( double scale )
                {
                    Point pt1, pt2, centre;
                    int i;
                    Cercle c1 = { 0, Point(0,0) };
                    double diametre_cercle;
                
                    vector<Rect> faces;
                    Mat gray, smallFrame( cvRound (frame_copy.rows/scale), cvRound(frame_copy.cols/scale), CV_8UC1 );
                
                    cvtColor( frame_copy, gray, CV_BGR2GRAY ); // ça plante à cette fonction !!!!!!!!!!!!!!
                    resize( gray, smallFrame, smallFrame.size(), 0, 0, INTER_LINEAR );
                    // ............
                }
                


                Je précise que ça ne peut pas venir de temps trop court du timer car je l'ai exécuté en mode pas à pas et ça plante à la fonction que j'ai indiqué (cf le commentaire dans le code source).

                ça ne peut pas venir de la fonction de l'autre librairie car si je laisse l'ancienne boucle de mon programme (qui m'oblige à laisser l'interface graphique de l'autre librairie), tout fonctionne !

                • Partager sur Facebook
                • Partager sur Twitter
                  27 mai 2010 à 20:33:52

                  Dès que je met un peu de code tout le monde s'en va :(
                  • Partager sur Facebook
                  • Partager sur Twitter
                    27 mai 2010 à 22:13:42

                    C'est que personne ne le comprend / ou connais de solution... ;)
                    • Partager sur Facebook
                    • Partager sur Twitter
                      27 mai 2010 à 23:02:31

                      Essaye de remplacer le timer par une boucle:
                      forever
                      {
                         captureLoop();
                         QApplication::processEvents();
                      }
                      

                      Mais sinon le debugger n'indique pas la ligne où ça plante ?
                      • Partager sur Facebook
                      • Partager sur Twitter
                        28 mai 2010 à 9:56:21

                        Merci beaucoup mon code fonctionne avec QApplication::processEvents(); !!!!

                        Tu pourrais m'expliquer ce que fait processEvents ?

                        • Partager sur Facebook
                        • Partager sur Twitter
                          28 mai 2010 à 10:48:36

                          Il empêche le gel de l'application en traitant les événements comme le exec() de l'application (ou d'un QEventLoop) le ferait.

                          Ce qui est embêtant, c'est qu'il n'y a pas de bonne raison que ça marche avec ça et pas avec le QTimer...
                          • Partager sur Facebook
                          • Partager sur Twitter
                            28 mai 2010 à 11:07:15

                            Le problème de QTimer, c'est que la fonction est exécuté en tant que "SLOTS", c'est peut être ça qui pose problème...


                            EDIT : Par contre j'ai un autre problème : lorsque je clique sur la croix fermer de ma fenetre, il ferme bien la fenêtre mais l'exécution de la boucle s'effectue toujours en arrière plan. Comment arrêter cette boucle lorsqu'on ferme ?
                            • Partager sur Facebook
                            • Partager sur Twitter
                              28 mai 2010 à 14:23:02

                              protected:
                              	void closeEvent(QCloseEvent *event)
                              	{
                                      	timer.stop();         
                              		event->accept();
                              	}
                              
                              • Partager sur Facebook
                              • Partager sur Twitter
                                28 mai 2010 à 14:35:44

                                Citation : cfillion

                                protected:
                                	void closeEvent(QCloseEvent *event)
                                	{
                                        	timer.stop();         
                                		event->accept();
                                	}
                                


                                J'utilise plus le timer vu qu'il me fait tout planter...donc timer.stop() pas possible...
                                Le problème c'est que : QApplication::processEvents(); doit laisser la QApplication lancé dans le main, comment dire de d'arrêter dans le closeEvent ?
                                • Partager sur Facebook
                                • Partager sur Twitter
                                  28 mai 2010 à 14:44:16

                                  qApp->quit() ? :o

                                  C'est vrai, tu n'utilise plus QTimer... >_<
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    28 mai 2010 à 14:56:31

                                    Citation : cfillion

                                    qApp->quit() ? :o

                                    C'est vrai, tu n'utilise plus QTimer... >_<



                                    Comment t'as accès à qApp dans la classe ?
                                    car dans le main je fais :
                                    int main(int argc, char **argv)
                                    {
                                      QApplication app(argc, argv);
                                      MaClasse mc;
                                      mc.show(); 
                                      return app.exec();
                                    }
                                    


                                    J'ai essayé dans la classe QApplication::quit(); mais ça marche pas :(


                                    EDIT: je savais pas que qApp était un mot clé mais malheureusement, qApp->quit(); ne fait strictement rien...
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      28 mai 2010 à 16:22:13

                                      Remplace le forever par while(isVisible()) ou un truc de ce genre.

                                      Citation : Aure77

                                      J'utilise plus le timer vu qu'il me fait tout planter...donc timer.stop() pas possible...

                                      En fait, tout ce que tu peux dire, c'est que tu as une erreur dans ton code qui fait tout planter quand tu utilises le QTimer.
                                      Le fait que la fonction soit appelée ou non comme un slot ne change rien (sauf si tu utilises les threads).

                                      Et:
                                      if( frame.empty() )
                                      	break;
                                      
                                      Ça devrait être return , non ? Comme tu avais une boucle au départ, tu as sûrement oublié de le changer.
                                      (Ça n'est même pas censé compiler comme ça).
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        28 mai 2010 à 16:23:39

                                        Oui, j'ai accès à ce pointeur.
                                        Tu n'as qu'à inclure "QApplication" dans le .h. ;)
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          28 mai 2010 à 17:37:09

                                          En même temps la solution qui consiste à remplacer un slot QTimer avec une boucle qui contient processEvent, elle est bien moche.
                                          Ca marche mais ça n'attirera que des problèmes par la suite ...
                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            29 mai 2010 à 1:19:24

                                            Citation : alexisdm

                                            Remplace le forever par while(isVisible()) ou un truc de ce genre.

                                            Citation : Aure77

                                            J'utilise plus le timer vu qu'il me fait tout planter...donc timer.stop() pas possible...

                                            En fait, tout ce que tu peux dire, c'est que tu as une erreur dans ton code qui fait tout planter quand tu utilises le QTimer.
                                            Le fait que la fonction soit appelée ou non comme un slot ne change rien (sauf si tu utilises les threads).

                                            Et:

                                            if( frame.empty() )
                                            	break;
                                            

                                            Ça devrait être return , non ? Comme tu avais une boucle au départ, tu as sûrement oublié de le changer.
                                            (Ça n'est même pas censé compiler comme ça).



                                            Oui ça ne c'est bien return et pas break (erreur de copier/coller).
                                            Une erreur dans mon code ? Alors pourquoi ça fonctionne correctement avec processEvents ? Et comme je l'ai dit, l'erreur apparait sur une fonction de l'autre librairie, comment voulez vous que je débugge... ? Mais il est possible que cette fonction utilise les threads ce qui pourrai poser un problème ?

                                            Citation : GrecKo

                                            En même temps la solution qui consiste à remplacer un slot QTimer avec une boucle qui contient processEvent, elle est bien moche.
                                            Ca marche mais ça n'attirera que des problèmes par la suite ...


                                            Ben le premier problème c'est que je ne peux plus quitter mon application.
                                            Et lorsque je force la fermeture via la console (ctrl+c), j'ai le message suivant qui s'affiche :
                                            QObject::killTimers: timers cannot be stopped from another thread

                                            J'aimerais bien pouvoir utiliser QTimer mais je ne vois pas pourquoi ça plante...
                                            Comment faire pour connaitre l'origine du problème ?


                                            EDIT : Voici l'erreur que j'ai avec QTimer :
                                            Segmentation Fault In icvBGRx2Gray_8u_CnC1R () (C:\OpenCV2.0\bin\libcv200.dll)
                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              29 mai 2010 à 2:24:11

                                              Citation : Aure77

                                              Une erreur dans mon code ? Alors pourquoi ça fonctionne correctement avec processEvents ? Et comme je l'ai dit, l'erreur apparait sur une fonction de l'autre librairie, comment voulez vous que je débugge... ? Mais il est possible que cette fonction utilise les threads ce qui pourrai poser un problème ?


                                              Ça peut être un dépassement de tableau ailleurs dans ton code. Puisque que ça touche le QTimer, tu peux essayer de changer la place de "QTimer timer;" dans la classe (le déclarer avant tous les autres attributs par exemple).
                                              Ça ne corrigera pas le problème, c'est juste pour tester.




                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                29 mai 2010 à 2:40:01

                                                j'ai fait ce test :
                                                void MaClasse::run()
                                                {
                                                // ...
                                                Mat test;
                                                Mat toto = imread("test.png");
                                                cvtColor(toto, test, CV_BGR2GRAY); // pas de problème
                                                timer.start(100);
                                                // ...
                                                }
                                                
                                                void MaClasse::captureLoop()
                                                {
                                                   Mat test;
                                                   Mat toto = imread("test.png");
                                                   cvtColor(toto, test, CV_BGR2GRAY); // erreur !!!!
                                                }
                                                


                                                Comme quoi il peut pas y avoir de problème d'allocation ou de dépassement de tableau.
                                                le premier bloc est OK, cvtColor fonctionne.
                                                je lance le timer qui lance CaptureLoop
                                                le même code plante...

                                                Comme quoi ya un truc dans l'appel de QTimer qu'il aime pas !
                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                  29 mai 2010 à 16:11:42

                                                  As tu fait ce test en isolation totale ?
                                                  Par exemple, avec ce code minimal:
                                                  #include <QtCore>
                                                  #include <opencv/cv.h>
                                                  #include <opencv/cxcore.h>
                                                  #include <opencv/highgui.h>
                                                  
                                                  using namespace cv;
                                                  
                                                  class MaClasse : public QObject
                                                  {
                                                      Q_OBJECT
                                                  public:
                                                      void run();
                                                  
                                                  public slots:
                                                      void captureLoop();
                                                  
                                                  private:
                                                      QTimer timer;
                                                  };
                                                  
                                                  void MaClasse::run()
                                                  {
                                                      connect(&timer, SIGNAL(timeout()), this, SLOT(captureLoop()));
                                                  
                                                      Mat test;
                                                      Mat toto = imread("test.png");
                                                      cvtColor(toto, test, CV_BGR2GRAY); // pas de problème
                                                  
                                                      timer.start(100);
                                                  }
                                                  
                                                  void MaClasse::captureLoop()
                                                  {
                                                     Mat test;
                                                     Mat toto = imread("test.png");
                                                     cvtColor(toto, test, CV_BGR2GRAY); // erreur !!!!
                                                  }
                                                  
                                                  int main(int argc, char *argv[])
                                                  {
                                                      QCoreApplication a(argc, argv);
                                                      MaClasse obj;
                                                      obj.run();
                                                  
                                                      return a.exec();
                                                  }
                                                  
                                                  #include "main.moc"
                                                  

                                                  A compiler directement avec les commandes qmake -project "LIBS += -lcxcore -lhighgui -lcv" && qmake && make (ou l'équivalent sur ton système).
                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                    30 mai 2010 à 17:30:05

                                                    Exactement le même problème en reprenant ton code simplifié !
                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                      2 juin 2010 à 8:08:29

                                                      up, toujours pas trouvé de solutions, tout ce que je sais c'est que toutes les fonctions comprises dans la dll de openCV font planter le progamme quand on utilise QTimer ! (car j'ai essayer des les recodé à la main mais ya certaines qui sont impossible à refaire...)
                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                        2 juin 2010 à 16:34:45

                                                        Apparemment ça viendrait d'opencv, le bug ne semble exister qu'avec le dll compilé avec mingw et utilisé avec plusieurs frameworks (Qt, wxWidgets, openframeworks, glut, et python):
                                                        http://www.openframeworks.cc/forum/vie [...] =2994&start=0
                                                        https://code.ros.org/trac/opencv/ticket/70
                                                        https://code.ros.org/trac/opencv/ticket/98

                                                        Mais tous les liens concernent opencv 2.0 et openmp, et comme opencv 2.1 utilise TBB à la place d'openmp, la solution évoquée dans le 1er lien (2e page), ne changera probablement rien.
                                                        Sinon peut-être qu'il faut recompiler opencv avec la même version de mingw que Qt (parce que recompiler Qt est un peu plus long).

                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                          7 juin 2010 à 15:56:23

                                                          Hello,

                                                          J'ai regardé tes liens (j'ai notamment téléchargé les libs dans la deuxième page), mais ça ne fonctionne pas car le problème provient des *.dll et pas des *.a... (sauf si une directive de compilation oblige à ne pas passer par les dll).
                                                          J'utilise OpenCV2.0. J'ai regardé la possibilité de recompiler OpenCV, mais je ne sais pas comment faire sous windows avec MinGW (avec CMake).

                                                          EDIT:
                                                          Finalement j'ai réussi à recompiler OpenCV avec une version de GCC plus récente, et maintenant tout est OK (avec QTimer)!
                                                          • Partager sur Facebook
                                                          • Partager sur Twitter
                                                            17 octobre 2021 à 19:01:07

                                                            J'ai aussi rencontré ce problème et pour ma part j'ai opté pour une solution peut être moins opti mais bien pratique de ne pas directement connecter mon QTimer au slot que je veux activer a intervalle régulière.

                                                            A la place je connecte a un autre slot qui lui va choisir ou non d'activer le slot en question :

                                                            public slots:
                                                                void foo();
                                                                void fooAppeleParTimer();
                                                            
                                                            private:
                                                                bool m_condition;
                                                            QObject::connect(
                                                                             pointeurVersMonQTimer, 
                                                                             SIGNAL(timeout()), 
                                                                             this, 
                                                                             SLOT(fooAppeleParTimer)
                                                                             );
                                                            void Class::foo()
                                                            {
                                                                //le truc a faire régulierement
                                                            }
                                                            
                                                            void Class::fooAppeleParTimer()
                                                            {
                                                                if (m_condition)
                                                                {
                                                                    this->foo();
                                                                }
                                                            }

                                                            A la place de stopper ou déconnecter le QTimer on choisis simplement quand il peux activer foo() en changeant la valeur du booleen.

                                                            Dans mon cas un QTimer de plus ou de moins activé en fond ne pose pas de problème coté performances.

                                                            • Partager sur Facebook
                                                            • Partager sur Twitter

                                                            [Qt] problème avec QTimer

                                                            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                            × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                                            • Editeur
                                                            • Markdown