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

GTK+ avec Python Discussion :

Exécuter du code au démarrage de gtk.main()


Sujet :

GTK+ avec Python

  1. #1
    Invité
    Invité(e)
    Par défaut Exécuter du code au démarrage de gtk.main()
    Bonjour,

    Je souhaite, dans une application GTK, exécuter du code au lancement.
    Je veux que pendant l'exécution de ce code (qui peut prendre un peu de temps), un popup (MessageDialog) soit affiché pour dire de patienter.

    Le problème, c'est que ce message ne sera visible que quand gtk.main() sera appelé. Or je ne peux plus rien faire après gtk.main().

    La première idée que j'ai eue, c'est de lancer ce code dans un thread. Ça a l'air de poser pas mal de problèmes... J'ai bien protégé le code du thread par gtk.gdk.threads_enter() et gtk.gdk.threads_leave(), mais malgré tout j'ai des erreurs (accès concurrent à des widgets à priori, car dans le code du thread, à la fin, je dois mettre à jour l'affichage de l'application).

    J'aurais donc tendance à penser que ce n'est pas la bonne solution.

    Est-ce qu'il n'existerait pas, plus simplement, un event sur lequel je pourrais m'enregistrer, qui serait appelé quand l'affichage de l'application est terminé, soit juste après l'appel à gtk.main().
    Ça me permettrait d'appeler mon code dans le contexte de la "main loop" GTK et ne poserait plus aucun problème.

    Merci.

  2. #2
    Membre actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2008
    Messages
    327
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2008
    Messages : 327
    Points : 257
    Points
    257
    Par défaut
    Bonjour,

    Les threads sont pour le moins une notion complexe à assimiler, surtout avec des interfaces graphiques en commun.

    Je me souviens avoir répondu à ce genre de problème pour PyGTK, je vous invite à lire le poste suivant et revenir vers nous si vous avez des probèmes :
    http://www.developpez.net/forums/d10...ppel-fonction/

    A très bientot

  3. #3
    Invité
    Invité(e)
    Par défaut
    Bonjour,

    Selon moi c'est un problème différent. D'ailleurs, dans la même application, j'ai déjà un thread qui tourne pour mettre à jour une barre de temps, et ça fonctionne bien. Ce thread est créé sur une action utilisateur.

    Ma fonction qui prend du temps n'est pas lancée depuis la main_loop, sur une action utilisateur, comme dans le cas que vous m'avez donné comme exemple. Elle doit être lancée au démarrage, avant que l'utilisateur ne commence à utiliser l'application.
    Un peu comme Firefox qui, suite à une mise à jour, affiche un popup "checking add-ons compatibility" au démarrage avant de donner la main à l'utilisateur, pour donner un exemple concret.

    En fait ce que j'ai essayé de faire, c'est créer un thread, juste avant d'appeler gtk.main().
    Dans ce thread, j'affiche une popup qui dit "patientez", et je fais le traitement. Et comme je traite plusieurs fichiers je mets à jour la popup au début de chaque traitement pour indiquer où on en est (quel fichier). Tout ça est fait dans le même thread.
    À la fin du thread, je détruit le popup (qui était bloquant, i.e. gtk.DIALOG_MODAL), et du coup ça donne la main à l'utilisateur pour commencer à utiliser l'appli.

    Si je ne le fais pas dans un thread, je vois la fenêtre de mon application et la fenêtre du popup qui restent complètement vides pendant le traitement (car je n'ai pas encore appelé gtk.main())

    Si je le fais dans un thread, j'ai des comportements bizarre.
    Parfois, sur la mise à jour du popup (set_markup sur objet MessageDialog), ça reste bloqué dans l'appel à set_markup.
    Si j'enlève les appels à set_markup, parfois, j'ai carrément un crash de la libc :
    *** glibc detected *** /usr/bin/python: double free or corruption (fasttop): 0x08e6a680 ***
    Avec une fois cette trace en plus :
    Gdk:ERROR:/build/buildd/gtk+2.0-2.24.10/gdk/gdkregion-generic.c:1110:miUnionNonO: assertion failed: (y1 < y2)

    C'est pour ça que je me dis que ma façon de faire n'est pas la bonne.
    Si j'avais un event de type "main loop is started", je pourrais faire toutes mes actions au démarrage dans le contexte de GTK et je pense que ça marcherait mieux.

  4. #4
    Invité
    Invité(e)
    Par défaut
    Je regarde d'autres exemples sur internet, comme celui-ci :
    http://excid3.com/blog/pygtk-and-threads-part-2/

    Et finalement je me demande si mon erreur n'est pas juste de lancer un thread (qui lui-même va appeler gtk.gdk.threads_enter()) avant d'appeler gtk.main().

    Juste une hypothèse, car je ne connais pas le détail des mécanismes en dessous.

    J'ai ajouté un gobject.idle_add (dont vous parlez dans le lien que vous m'avez donné) pour ne commencer - si j'ai bien compris - mon traitement que quand la main loop a démarré et est en attente. Ce qui, au final, semble correspondre à ce que je voulais (un event "main loop started").
    Est-ce que idle_add fait bien ça ? (sachant que quand il est appelé dans le thread, je n'ai peut-être pas encore appelé gtk.main()).

    En lançant plusieurs fois, je ne suis pas retombé dans un crash, par contre rien n'est affiché dans mon MessageDialog (si j'appelle gtk.main_iteration(), comme suggéré également dans le lien, ça reste bloqué !).

    Il faudrait que j'arrive à écrire un test simple pour mettre en évidence le problème...

  5. #5
    Invité
    Invité(e)
    Par défaut Exemple pour reproduire le problème
    Bonjour,

    J'ai finalement réussi à écrire un petit programme de test qui illustre mon problème.
    Je pense que ce sera plus simple pour comprendre ce que je veux dire

    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
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
     
    #!/usr/bin/env python
     
    import gobject
    import gtk
    from threading import Thread
    import time
     
    def _destroy(widget, data=None):
        gtk.main_quit()
     
    def _thread():
        gobject.idle_add(_thread_actions)
     
    def _thread_actions():
        message_dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT)
        message_dialog.set_markup('Patientez...')
        message_dialog.show_all()
     
        gtk.gdk.threads_enter()
        message_dialog.set_markup('Etape 1')
        #gtk.main_iteration()
        gtk.gdk.threads_leave()
        time.sleep(1)
        gtk.gdk.threads_enter()
        message_dialog.set_markup('Etape 2')
        #gtk.main_iteration()
        gtk.gdk.threads_leave()
        time.sleep(1)
        message_dialog.destroy()
     
    window = gtk.Window(gtk.WINDOW_TOPLEVEL)
    window.connect('destroy', _destroy)
     
    vbox = gtk.VBox(False)
    label = gtk.Label()
    label.set_text('Mon application')
    vbox.pack_start(label, False)
    window.add(vbox)
    window.maximize()
    window.set_title('test')
    window.show_all()
     
    gtk.gdk.threads_init()
     
    thread = Thread(None, _thread, 'mon thread')
    thread.start()
     
    gtk.main()
    On constate déjà que la window principale n'affiche son contenu ("Mon application") que quand le thread est fini.

    Mais surtout, le contenu de mon popup ne s'affiche jamais. Les appels à gtk.main_iteration() (si je les décommente) ne changent rien.
    Pourtant, si je supprime l'appel à message_dialog.destroy(), je constate que le contenu s'affiche à la fin du thread.

    J'espère que c'est plus clair avec cet exemple.
    Merci d'avance pour votre aide...

  6. #6
    Invité
    Invité(e)
    Par défaut
    Bonjour,

    Entre temps j'ai posé la question sur un autre forum, et j'ai eu la réponse :
    http://www.gtkforums.com/viewtopic.php?f=3&t=178523

    Donc mon problème est résolu.

    Pour résumer, je pense que les erreurs que j'ai eues au début étaient dues à l'oubli de threads_enter/threads_leave autour de certains appels à GTK, dans mon application réelle.

    Par la suite, quand j'ai écrit mon programme de test, j'ai utilisé idle_add après avoir lu (et visiblement mal compris) la discussion mentionnée par Apocalypses.
    En supprimant le idle_add de mon test, ça fonctionne. Avec idle_add mon traitement est exécuté dans le contexte de la main loop, ce qui l'empêche de rafraîchir l'affichage.

    Maintenant ça semble fonctionner dans mon application réelle (en rajoutant un threads_enter/threads_leave, et en supprimant l'utilisation d'idle_add). Je ne suis pas retombé dans des cas de crash.

    Merci à Apocalypses pour sa réponse.
    Je reconnais que mes explications n'étaient pas toujours très claires, d'où l'intérêt d'isoler le problème dans un petit programme d'exemple.

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

Discussions similaires

  1. [Débutant]Exécuter du code au démarrage
    Par ProgVal dans le forum Autres éditeurs
    Réponses: 1
    Dernier message: 29/12/2007, 14h27
  2. [Jboss] Exécution de code au démarrage
    Par ebaynaud dans le forum Wildfly/JBoss
    Réponses: 3
    Dernier message: 28/04/2007, 22h24
  3. Réponses: 44
    Dernier message: 02/08/2006, 17h12
  4. Réponses: 3
    Dernier message: 20/04/2005, 13h30
  5. Réponses: 7
    Dernier message: 03/02/2005, 18h20

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