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

Qt Discussion :

Widgets must be created in the GUI thread


Sujet :

Qt

  1. #1
    Membre actif Avatar de gassi64
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2008
    Messages
    255
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Juin 2008
    Messages : 255
    Points : 230
    Points
    230
    Par défaut Widgets must be created in the GUI thread
    Bonjour,

    Je n'arrive pas à créer de composants Qt dans une DLL.
    Mon programme principal est un code C++ non Qt, qui charge une dll personnelle.
    Dans celle ci, je crée un QPushButton. Alors déjà pour le créer il faut simuler un QApplication :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    int argc = 1;
    char** argv = NULL;
    QApplication a(argc, argv);
    QPushButton widget("Push Button");
    Tout ça dans une unique fonction exportée, ça fonctionne.
    Mais, une fois qu'on veut faire plus évolué, c'est la galère : j'ai créé 3 fonctions exportées dans le dll : createWidget, setSizeToWidget, getWidgetRender.
    Pour palier au problème de persistance du widget créé entre appels successifs des fonctions, j'ai mis un QPushButton en variable globale (juste pour tester avant de faire une liste de widgets si cela fonctionnait)

    Voilà que je lance mon programme...et au moment de créer l'objet il plante :*
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    ASSERT failure in QWidget: "Widgets must be created in the GUI thread.", file kernel\qwidget.cpp, line 1069
    Alors, là j'ai lu plusieurs forums, mais à chaque fois la résolution c'est "finalement j'ai tout laissé dans un unique thread"
    Moi je n'ai pas de threads, je n'ai qu'une pauvre dll qui crée un QPushButton et renvoi son rendu !

    j'ai trouvé ça comme info : http://www.qtforum.org/article/22708...-instance.html mais je ne comprends rien, ça me semble trop complexe pour peu de choses...

    J'avais essayé aussi de mettre le QApplication en variable globale mais pareil ça fait des horreurs de compilation

    Je pense que le programme principal crée un thread, et que la dll qui crée le QPushButton le fait dans un autre thread ce qui fait le problème, à mon avis.
    Comment palier à ce problème de thread SVP ?

  2. #2
    Membre averti
    Avatar de Niak74
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    271
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2007
    Messages : 271
    Points : 333
    Points
    333
    Par défaut
    Utiliser une lib avec du Qt dans une appli sans Qt... hum. Ça me parait compromis d'avance.

    Qt est un framework qui ne repose pas sur les lib graphique propres aux OS (c'est à dire que contrairement à WxWidget, pour ne citer que lui, il ne s'agit pas d'une couche intermédiaire qui fait appel à l'API Win32 pour Windows, à la libX pour Unix, ect...). Qt possède ses propres éléments graphiques et ses propres mécanismes pour créer un rendu graphique.
    Ceci étant dit, je ne pense pas qu'une "DLL" puisse retourner des objets du Framework Qt.

    Les librairies sous Qt répondent à un mécanisme propre à Qt : les Plugins. Donc, la création d'une "DLL" Qt se fera selon le schéma des Plugins Qt, et cette DLL devra être appelée par une application Qt (via la classe QPluginLoader).

    Peut-être existe-t-il une interface permettant de faire le pont de Qt vers C/C++ pour ce qui est du GUI, je n'en sais rien. A première vue, ça va bloquer.


    Quelques liens en rapports avec les Plugins Qt :
    http://qt.developpez.com/doc/4.5/plugins-howto/
    http://qt.developpez.com/tutoriels/plug-ins/
    http://qt.developpez.com/doc/4.5/tools-plugandpaint/
    Un clavier Azerty en vaut deux.

  3. #3
    Membre actif Avatar de gassi64
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2008
    Messages
    255
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Juin 2008
    Messages : 255
    Points : 230
    Points
    230
    Par défaut
    Merci Ryo2468 pour ton aide!

    Citation Envoyé par Ryo2468 Voir le message
    Utiliser une lib avec du Qt dans une appli sans Qt... hum. Ça me parait compromis d'avance.


    Citation Envoyé par Ryo2468 Voir le message
    Qt est un framework qui ne repose pas sur les lib graphique propres aux OS (c'est à dire que contrairement à WxWidget, pour ne citer que lui, il ne s'agit pas d'une couche intermédiaire qui fait appel à l'API Win32 pour Windows, à la libX pour Unix, ect...). Qt possède ses propres éléments graphiques et ses propres mécanismes pour créer un rendu graphique.
    J'ai préféré Qt à WxWidgets pour sa gestion des look de widgets, car comme WxWidgets utilise directement le look natif, le fait de changer le look contredit l'idée même de cette API, contrairement à Qt.

    Citation Envoyé par Ryo2468 Voir le message
    Ceci étant dit, je ne pense pas qu'une "DLL" puisse retourner des objets du Framework Qt.
    Je ne retourne pas d'objets Qt ! Je crée des objets Qt en leur affectant certains paramètres donnés pour en récupérer le rendu sous forme d'image uniquement. Ceci fonctionne si on met tout dans une unique méthode.

    Citation Envoyé par Ryo2468 Voir le message
    Les librairies sous Qt répondent à un mécanisme propre à Qt : les Plugins. Donc, la création d'une "DLL" Qt se fera selon le schéma des Plugins Qt, et cette DLL devra être appelée par une application Qt (via la classe QPluginLoader).
    J'ai créé une Qt Shared Library à partir de QtCreator et elle fonctionne bien dans un programme C++ non Qt.

    Citation Envoyé par Ryo2468 Voir le message
    Peut-être existe-t-il une interface permettant de faire le pont de Qt vers C/C++ pour ce qui est du GUI, je n'en sais rien. A première vue, ça va bloquer.
    J'espère que non !

  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
    Salut
    Tu veut faire quoi?
    Pour l'ihm doit être dans une dll?C'est un prendre le problème à l'envers...

    Ce qu'il faut savoir :
    1- QApplication doit être créé avant toute création/manipulation de widget
    2- la fonction exec() de QApplication créé doit être exécuter
    3- toute manipulation IHM doit être faite dans le thread de QApplication.

    Il est intéressant de savoir que les signaux sont thread safe => tu pourrais envoyer des commandes vers l'ihm par un signal.

    int argc = 1;
    char** argv = NULL;
    QApplication a(argc, argv);
    suivant l'os, argv peut contenir des choses invisible. De plus ici tu dit qu'il as un argument mais tu en met aucun. Le top serait tu donner les vrai argv,argc du programme.

    Voila quelque piste.

  5. #5
    Membre actif Avatar de gassi64
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2008
    Messages
    255
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Juin 2008
    Messages : 255
    Points : 230
    Points
    230
    Par défaut
    Citation Envoyé par yan Voir le message
    Salut
    Tu veut faire quoi?
    Pour l'ihm doit être dans une dll?C'est un prendre le problème à l'envers...
    Pour être clair :
    1) une IHM Java fait appel à une interface JNI pour effectuer un dessin voulu
    2) la JNI fait appel à la dll Qt en lui donnant les paramètres qu'il faut
    3) la dll prend les ordres, dessine de son côté son widget...(comme si on faisait une snapshot d'une IHM qu'on aurait dessiné vite fait sur QtDesigner) et renvoi l'image
    4) et on plaque l'image sur le bon buffer

    quand je met dans une unique fonction exportée dans la dll la création de la QApplication, la création d'un widget, le renvoi du rendu, ça marche!
    quand je veux séparer la création, l'envoi des paramètres, le renvoi, ça plante.

    Je crois que j'ai trouvé la raison: (http://qt.developpez.com/doc/4.5/thr...ing-in-threads)
    creating an object in one thread and calling its functions from another thread is not guaranteed to work. There are three constraints to be aware of:
    donc le fait de créer une QApplication et un widget en variables globales c'est possible, mais ensuite quand on veut changer le widget on ne peut pas car la fonction appelée, même si elle est dans le fichier source où on a les variables globales, sera dans un autre thread que le thread de base où aura été créé les variables globales.

    Ce que tu me dis ensuite rejoint cette idée là, il faut un thread pour la QApplication. Donc je crois que la solution passe par la création d'un thread pour la QApplication, thread appelé à chaque fois par les trois fonctions de ma dll...

    suivant l'os, argv peut contenir des choses invisible. De plus ici tu dit qu'il as un argument mais tu en met aucun. Le top serait tu donner les vrai argv,argc du programme.
    J'avais essayé avec un argv à 0, mais ça plantait, contrairement à 1, ensuite on m'avait dit que ça ne pouvait pas être 0 car il y a au moins le premier argument étant le nom de l'application lançée! (même sur windows...)

    En tout cas merci pour les explications

  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
    Comme les qignaux sont threadsafe, si tu emet un signal dans une fonction exporté, qui est connecté sur ton ihm, ca pourrais passer.

    Une autre solution, tu créé une aplli qui communique avec ton programme par tcp, ou autre moyen.

  7. #7
    Membre actif Avatar de gassi64
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2008
    Messages
    255
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Juin 2008
    Messages : 255
    Points : 230
    Points
    230
    Par défaut
    Ok merci pour les infos, par contre si je dois passer par une appli externe qui doit être lancée, et passant par TCP ça va être très long pour afficher...enfin c'est pas bête! merci

  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 gassi64 Voir le message
    TCP ça va être très long pour afficher...enfin c'est pas bête! merci
    Ca dépend.
    Sur une même machine, ca peu suffire.

  9. #9
    Membre actif Avatar de gassi64
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2008
    Messages
    255
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Juin 2008
    Messages : 255
    Points : 230
    Points
    230
    Par défaut
    En fait, suffit de mettre le code suivant dans chaque fonction où on instancie un composant Qt (quand on change juste un paramètre pas la peine de mettre ce code)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    int argc = 1;
    char** argv = NULL;
    QApplication a(argc, argv);
    Mais c'est très moche
    En essayant de faire une méthode qui retourne ou qui crée simplement le QApplication, ça crash -> il fait réellement instancier le QApplication DANS la fonction où l'on crée des QWidgets (en tout cas pour des Qimage ou QPushButton)

    Je ne vois aucune solution propre à cela encore, à moins comme vous le disiez de passer carrément par une application externe qui communique ses données par TCP (mais je ne sais pas le faire, en espérant que ça soit rapide à tester j'essairai) ou de créer un thread pour le QApplication mais je n'ai pas su comment concevoir cela (un thread possédant les méthodes de gestion de composants ou les méthodes de gestion de composants exécutant le run du thread de l'application?)

    En attendant, mon problème est un peu résolu, ça marche sans warning mais c'est laid.

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

Discussions similaires

  1. Réponses: 5
    Dernier message: 22/08/2013, 14h47
  2. PyNoAppError: The wx.App object must be created first!
    Par vega95 dans le forum wxPython
    Réponses: 5
    Dernier message: 23/11/2008, 19h47
  3. sudoku console + gui + thread
    Par marc_dd dans le forum Interfaces Graphiques en Java
    Réponses: 2
    Dernier message: 28/04/2006, 09h25

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