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

Multithreading Discussion :

Cannot set parent, new parent is in a different thread [QThread]


Sujet :

Multithreading

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    60
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 60
    Points : 50
    Points
    50
    Par défaut Cannot set parent, new parent is in a different thread
    Bonjour la communauté,

    J'ai un problème aléatoire avec QThread...

    Je pense que je n'ai pas bien défini mon thread.
    Si j'effectue mes opérations "trop rapidement" (du moins c'est ce qui semble être le problème...), ou que je clique deux fois trop rapidement sur le bouton une fois que celui-ci revient actif, l'erreur suivante sort :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    QObject::setParent: Cannot set parent, new parent is in a different thread
    QPixmap: It is not safe to use pixmaps outside the GUI thread
    <unknown>: Fatal IO error 11 (Resource temporarily unavailable) on X server :0.0.
    Environnement : Ubuntu 9.10, QT4, Q Designer

    Le .h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class ThreadConnectForum : public QThread
    {
    	public:
    		ThreadConnectForum(MaClasseAppelante* parent = 0);
    		void run();
     
    	private:
    		MaClasseAppelante* fenetre;
    };
    Le .cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    ThreadConnectForum::ThreadConnectForum(MaClasseAppelante* parent) : QThread(parent)
    {
    	this->fenetre = parent;
    }
     
    void ThreadConnectForum::run()
    {
        fenetre->buttonBox->setDisabled(false);
       exec()
    }
    Une bouton depuis "on_buttonBox_accepted" de ma classe MaClasseAppelante (basée sur un QDialog) par exemple lance le thread, de la manière suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    void MaClasseAppelante::on_buttonBox_accepted()
    {
    	buttonBox->setDisabled(true);
            ThreadConnectForum* t = new ThreadConnectForum(this);
            t->start();
    }
    Parfois ça marche, parfois ça affiche l'erreur :s

    Quel est le souci ?
    Ce qui est bizarre c'est que c'est que je n'ai que ce thread et qu'un seul thread a la fois à chaque fois...
    J'ai ma classe principale, MaClasseAppelante, et celle-ci lance le thread en bloquant tout les boutons avant de le lancer, et le thread lui-même réactive les bouton une fois qu'il se termine.
    Je n'ai aucun autre thread, toujours qu'un seul thread.

    Et aussi j'ai aucune idée de ce qu'est un Pixmap.

    Une idée au problème ?



    Edit : Quel est l'intérêt d'un QThread d'ailleurs ? Un Thread simple serait pas mieux ? (j'y connais rien en threads C++... j'ai pris le QThread vu que j'utilise cette librairie pour l'interface graphique mais bon...)

  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

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    60
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 60
    Points : 50
    Points
    50
    Par défaut
    Je vois... une classe pas vraiment utile quoi...

    Bon bah j'ai plus qu'à me plonger dans l'apprentissage de la manipulation de signaux/slots...

  4. #4
    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
    Citation Envoyé par $p00ky Voir le message
    Je vois... une classe pas vraiment utile quoi...

    Bon bah j'ai plus qu'à me plonger dans l'apprentissage de la manipulation de signaux/slots...
    ho que si. C'est une classe trés utile.
    Mais ce n'est pas fait pour manipuler les classe d'IHm. Que cherche tu à faire et pourquoi tu pense avoir besoin de thread?

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    60
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 60
    Points : 50
    Points
    50
    Par défaut
    Dans un premier temps, je voulais juste tester les threads avec un petit bouton, qui quand je clique dessus, lance une tâche dans le thread, qui dure quelque temps (genre 5 secondes) mais que la fenêtre principale soit toujours disponible (pas d'effet "fenêtre indisponible" ou "qui ne répond pas").

    Pour ce faire, mon main() (qui ne contient presque rien) lance une petite classe dérivée de QDialog avec un bouton.
    Lorsque je clique sur ce bouton, celui-ci devient indisponible et lance le thread.
    C'est alors le thread qui est censé remettre le bouton "cliquable" lorsque celui-ci a fini sa tâche.

    Plus tard quand j'aurais avancé dans mon code, je voudrais du vrai multithread pour lancer plusieurs tâches en même temps, attendre qu'elles aient été effectuée et mettre à jour l'interface.

    En fait je débute en C++/Qt et j'ai déjà tout fait en Java, notamment ce thread de bouton ou les multithreads.
    Cependant j'ai envie de me mettre à QT puisque c'est aussi multi-plateforme et a l'air bien puissant.

    Je suis entrain de découvrir les signaux/slots et espère me débrouiller avec.
    Ca pourra aussi gérer le multithread (ou simplement lancer plusieurs tâches en même temps) ?

    J'ai implémenté mon premier "signal/slot" perso, mais j'ai un petit problème.

    J'ai toujours le même problème.
    En fait, mon QDialog a 1 label et 1 buttonBox avec 2 boutons.

    Ce que je veux pour tester la "dynamicité", c'est que lorsque je clique sur le bouton, le label se change en "chargement..." et le bouton est désactivé le temps que la tâche s'effectue, puis le label se change en "tâche effectuée" et le bouton redevient actif lorsque la tâche est terminée.

    Le problème que j'avais sans le thread c'est que le label ne se changeait pas en "chargement..." et le bouton ne se désactivé pas.
    En effet, la fenêtre restait "indisponible" le temps que la tâche s'effectue, et le résultat direct était alors affiché (par exemple "tâche effectuée" pour le label, et les boutons toujours actifs).

    J'ai changé vers un profil signal/slot, donc maintenant, quand on clique sur le bouton, je change le label, désactive le buttonBox et émet un signal qui effectue la tâche et mets à jour le label et ré-active le buttonBox à la fin de la tâche.

    Comme ceci :
    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
     
    ...
    QObject::connect(this, SIGNAL(startTask()), this, SLOT(myTask()));
    ...
    void MaClasse::on_buttonBox_accepted()
    {
        buttonBox->setDisabled(true);
        label->setText("Loading...");
         emit startTask();
    }
     
    void MaClasse::myTask()
    {
            ... taches qui demandent un peu de temps (3/4 secondes) ...
            buttonBox->setDisabled(false);
        label->setText("tâche terminée");
    }
    Mais le problème est que l'interface reste "bloquée" pendant ces 3/4 secondes, et affiche directement l'état du résultat de ma tâche après ces 3/4 secondes...
    L'état "intermédiaire" de chargement dans lequel je souhaite entrer est totalement zappé.

    Qu'est ce que je fais mal ?

  6. #6
    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
    Citation Envoyé par $p00ky Voir le message
    Mais le problème est que l'interface reste "bloquée" pendant ces 3/4 secondes, et affiche directement l'état du résultat de ma tâche après ces 3/4 secondes...
    L'état "intermédiaire" de chargement dans lequel je souhaite entrer est totalement zappé.

    Qu'est ce que je fais mal ?
    ou est passé ta thread?

  7. #7
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    60
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 60
    Points : 50
    Points
    50
    Par défaut
    Oh ! J'avais mal compris l'histoire de "Thread principal" et avait complètement ré-écrit mon code sans thread, en pensant que les signaux pouvaient "simuler" cela.

    Maintenant que j'ai compris, j'ai fait comme cela :
    on_buttonBox_accepted() désactive les bouttons et lance le thread
    le thread ne touche pas à la GUI mais lorsqu'il a fini émet un signal qui réveille un processus dans mon thread de la gui qui lui réactive les boutons.

    Et ça marche à merveille, merci !

    Code :

    .h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class monThread : public QThread
    {
    	Q_OBJECT
     
    	public:
    		monThread(MaClasseAppelante* parent = 0);
    		void run();
     
    	private:
    		MaClasseAppelante* fenetre;
    	signals:
    		void taskDone(int output);
    };
    .cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    MonThread::MonThread(MaClasseAppelante* parent) : QThread(parent)
    {
    	this->fenetre = parent;
    }
     
    void MonThread::run()
    {
            ... des taches qui ne modifient pas la GUI ...
            emit taskDone(result);
            exec();
    }
    Et dans ma classe appelante, j'ai un "void actionAfterTask(int)" qui rétablit la GUI en fonction de l'int en argument.
    Je crée la connexion signal/slot lors de la création du thread dans la classe appelante :
    QObject::connect(task, SIGNAL(taskDone(int)), this, SLOT(actionAfterTask(int)));

    Merci pour tout !

  8. #8
    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
    Citation Envoyé par $p00ky Voir le message
    Maintenant que j'ai compris, j'ai fait comme cela :
    on_buttonBox_accepted() désactive les bouttons et lance le thread
    le thread ne touche pas à la GUI mais lorsqu'il a fini émet un signal qui réveille un processus dans mon thread de la gui qui lui réactive les boutons.

    Et ça marche à merveille, merci !
    c'est bien cela
    De plus, comme les signaux sont thread safe, tu peut émettre d'autre signaux dans le thread.
    Y as de très bon exemple fourni avec Qt. Je te conseil de les regarder.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 1
    Dernier message: 25/11/2010, 21h34
  2. Cannot create a new instance
    Par iacobm dans le forum JOnAS
    Réponses: 2
    Dernier message: 20/02/2008, 00h16
  3. Set R=New Range
    Par deubelte dans le forum Macros et VBA Excel
    Réponses: 3
    Dernier message: 21/11/2007, 19h11
  4. Locale: Cannot set LC_ALL to default locale: No such file or directory
    Par Trillian dans le forum Mandriva / Mageia
    Réponses: 7
    Dernier message: 03/11/2006, 10h08
  5. Réponses: 10
    Dernier message: 23/05/2006, 16h42

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