IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Threads & Processus C++ Discussion :

Utilisation de 'run' de QtConcurrent


Sujet :

Threads & Processus C++

  1. #1
    Membre du Club
    Inscrit en
    Mars 2007
    Messages
    127
    Détails du profil
    Informations forums :
    Inscription : Mars 2007
    Messages : 127
    Points : 54
    Points
    54
    Par défaut Utilisation de 'run' de QtConcurrent
    Bonjour,

    je souhaiterais afficher sur une carte des points. Lorsque je clique sur un bouton, les coordonnées de ses points se mettent à jour, ils se déplacent donc sur la carte jusqu'à ce que je clique à nouveau sur le bouton. Pour cela, j'ai écris le code suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    class tabVisu : public QWidget {
        Q_OBJECT
    ...
    private:
        bool loopRun;
    private slots:
        void playDisplay(const bool state);
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    tabVisu::tabVisu(QWidget *parent) : QWidget(parent) {
        loopRun= false;
        QPushButton * playBt = new QPushButton(tr("Jouer"));
        playBt->setCheckable(true);
        connect(playBt, SIGNAL(clicked(bool)), this, SLOT(playDisplay(bool)));
    }
     
    void tabVisu::playDisplay(const bool state) {
        loopRun = state;
        QtConcurrent::run(this, &tabVisu::infiniteLoopDisplay);
    }
     
    void tabVisu::infiniteLoopDisplay() const {
        while(loopRun) {
            // calcul des nouvelles positions et modification de l'affichage sur la carte
        }
    }
    Ca compile mais lorsque j'appuie sur le bouton, j'obtiens le message d'erreur : "ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread 24769638. Receiver '' (of type 'MainWindow') was created in thread 19729290"

    J'essaye de comprendre ce qui ne fonctionne pas mais découvrant QtConcurrent, je n'arrive pas m'en sortir. Pourriez-vous m'aider ? Merci !

  2. #2
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    Salut.
    Dans ton cas, comme tu veux une boucle dans un thread, il faut mieux que tu créé un QThread.

    Pour l'erreur, il faudrait voir ce que tu fait dans infiniteLoopDisplay. Mais en gros, tu appel dans infiniteLoopDisplay des fonctions IHM de widget. Ce qui n'est pas possible en Qt. Une manière de contourner le problème est d'utiliser des signal/slot et d’émettre les signaux dans ta fonction. Tu trouva des infos dans la FAQ.

    Yan

  3. #3
    Membre du Club
    Inscrit en
    Mars 2007
    Messages
    127
    Détails du profil
    Informations forums :
    Inscription : Mars 2007
    Messages : 127
    Points : 54
    Points
    54
    Par défaut
    Merci Yan, ça doit en effet venir du fait que je modifie bien des widgets (qcustomplot) dans la fonction infiniteLoopDisplay. Je vais lire la FAQ et je poste mon code une fois que j'ai avancé.

    Merci !

  4. #4
    Membre du Club
    Inscrit en
    Mars 2007
    Messages
    127
    Détails du profil
    Informations forums :
    Inscription : Mars 2007
    Messages : 127
    Points : 54
    Points
    54
    Par défaut
    Bonjour Yan,

    j'ai suivi tes conseils et une bonne partie commence à marcher. Quand je lance le thread, les signaux sont envoyés et reçus et la carte évolue bien. Par contre, quand je veux stopper l'animation, tout se fige... Il y a quelque chose que je ne fais pas bien ? Merci d'avance !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
     
    class tabVisu : public QWidget {
    private:
        QPushButton * playBt = nullptr;
    private slots:
        void stepDisplay() const;
        void playDisplay();
    }
     
    class threadEmetteur : public QThread {
        Q_OBJECT
     
    public:
        void run(QPushButton * button) {
            while(button->isChecked()) {
                msleep(500);
                emit nextStep();
            }
            quit();
        }
     
    signals:
        void nextStep();
    };
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    tabVisu::tabVisu {
        QPushButton * playBt = nullptr;
        connect(playBt, SIGNAL(clicked()), this, SLOT(playDisplay()));
    }
     
    void tabVisu::playDisplay() {
        threadEmetteur thread;
        connect(&thread, SIGNAL(nextStep()), this, SLOT(stepDisplay()));
        thread.run(playBt);
    }
     
    void tabVisu::stepDisplay() {
        // Affichage sur la carte
    }

  5. #5
    Membre du Club
    Inscrit en
    Mars 2007
    Messages
    127
    Détails du profil
    Informations forums :
    Inscription : Mars 2007
    Messages : 127
    Points : 54
    Points
    54
    Par défaut
    Juste une petite correction mais qui ne change rien au résultat:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    void tabVisu::playDisplay() {
        if(playBt->isChecked()) {
            threadEmetteur thread;
            connect(&thread, SIGNAL(nextStep()), this, SLOT(stepDisplay()));
            thread.run(playBt);
        }
    }

  6. #6
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    A priori, il ne faut pas bloquer le dessin, mais l'évolution du dessin.
    La boucle de dessin doit se poursuivre (c'est son arrêt qui fige l'interface).
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  7. #7
    Membre du Club
    Inscrit en
    Mars 2007
    Messages
    127
    Détails du profil
    Informations forums :
    Inscription : Mars 2007
    Messages : 127
    Points : 54
    Points
    54
    Par défaut
    Bonjour Leternel et merci pour ta réponse par contre, je ne la comprends pas bien. Je veux bien un peu plus de détail.

    A priori, il ne faut pas bloquer le dessin, mais l'évolution du dessin.
    J'ai l'impression que je ne bloque que la partie émission des signaux qui demandent de dessiner mais je ne touche pas à la partie dessin.

  8. #8
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Moi non plus, je ne connais pas Qt.
    Mais dans toutes les bibliothèques graphiques, si la boucle principale (celle qui dessine) n'itère pas assez vite, l'interface est figée.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  9. #9
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    salut.
    Il y as plusieurs problème
    1-
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void tabVisu::playDisplay() {
        threadEmetteur thread;
        connect(&thread, SIGNAL(nextStep()), this, SLOT(stepDisplay()));
        thread.run(playBt);
    }
    quand tu sort de playDisplay, le thread est détruit.

    2- tu essaie d'utiliser un élément graphique dans le thread. Ce qui est interdit.


    Il te faut utiliser autre chose pour stopper ta boucle. Par exemple un bool qui est lue dans le thread et modifié dans le thread GI. En gros tu ajoute des slot qui vont modifier la valeur de ce bool.

  10. #10
    Membre du Club
    Inscrit en
    Mars 2007
    Messages
    127
    Détails du profil
    Informations forums :
    Inscription : Mars 2007
    Messages : 127
    Points : 54
    Points
    54
    Par défaut
    Merci Yan,

    j'ai compris les 2 problèmes. J'essaye d'améliorer et je poste le code !

  11. #11
    Membre du Club
    Inscrit en
    Mars 2007
    Messages
    127
    Détails du profil
    Informations forums :
    Inscription : Mars 2007
    Messages : 127
    Points : 54
    Points
    54
    Par défaut
    J'ai un peu progressé. Maintenant, je peux lancer et arrêter la mise à jour de la carte.

    Voici mes modifications de code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    void tabVisu::playDisplay(const bool state) {
        if(state)
            m_thread.run();
        else
            m_thread.abort();
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
    class threadEmetteur : public QThread {
        Q_OBJECT
     
    public:
        void run() {
            mRunning = true;
            while(mRunning) {
                emit nextStep();
                QEventLoop loop;
                QTimer::singleShot(250, &loop, SLOT(quit()));
                loop.exec();
            }
        }
     
        void abort() {
            mRunning = false;
        }
     
    private:
        bool mRunning = false;
     
    signals:
        void nextStep();
    };
    Ca marche mieux maintenant que j'ai remplacé "msleep" par le QTimer.

    Maintenant, il me reste juste un petit soucis: si pendant que la boucle d'envoi des signaux tourne (mRunning = true) dans le thread appelé et que je ferme la fenêtre principale, j'ai l'impression qu'il reste des choses qui tournent. Pourtant, j'ai rajouté dans le destructeur du thread appelant:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    tabVisu::~tabVisu() {
        m_thread.abort();
        m_thread.wait();
    }
    Vous avez une idée de ce que je dois améliorer ? Merci.

Discussions similaires

  1. Utiliser Application.run avec une classe
    Par baya22 dans le forum VBA Access
    Réponses: 1
    Dernier message: 12/04/2012, 12h07
  2. [Première utilisation] Pas possible de faire un run
    Par Faiche dans le forum Eclipse C & C++
    Réponses: 2
    Dernier message: 30/07/2009, 15h33
  3. web.xml : utilisation de run-at
    Par hihi30 dans le forum Tomcat et TomEE
    Réponses: 0
    Dernier message: 24/11/2008, 12h51
  4. [Virtual Pascal] Comment utiliser linker pour que run fonctionne dans le compilateur
    Par gmaxjeu dans le forum Autres IDE
    Réponses: 1
    Dernier message: 04/07/2008, 20h44
  5. [Erreur] Utilisation du "Run as"
    Par guilopouloos dans le forum Eclipse Java
    Réponses: 3
    Dernier message: 07/02/2007, 10h30

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo