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

Programmation multimédia/Jeux Python Discussion :

fenetre tkinter Toplevel asynchrone, pas bloquante [Python 3.X]


Sujet :

Programmation multimédia/Jeux Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éprouvé
    Homme Profil pro
    Vagabong étudiant en annalyse du signal.
    Inscrit en
    Avril 2019
    Messages
    139
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 27
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Vagabong étudiant en annalyse du signal.
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Avril 2019
    Messages : 139
    Par défaut fenetre tkinter Toplevel asynchrone, pas bloquante
    Bonjour, j'aimerai donner un comportement séquentiel à l’appel d'une fenêtre Toplevel mais je n'y arrive pas.

    Un résumé du code:
    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
     
    class _Manager():
        def __init__(self):
            self.window = tkinter.Tk()
            self.initializing_variables_and_widgets() # ajoute les widgets a la fenetres
            self.window.mainloop()
     
        def initializing_variables_and_widgets():
            e = tkinter.Entry(frame_account, textvariable=self.username_var)
            e.bind("<Key>", lambda event: question(self.window))
            e.bind("<Return>", lambda event: question(self.window))
            e.pack()
     
    def question(fen_papa=None):
        class  DialogWindow:
            def __init__(self, fen_papa):
                # preparation de la fenetre
                if fen_papa:          # si il y a deja une fenetre ouverte
                    self.window = tkinter.Toplevel(fen_papa)                        # on est oblige d'utiliser un toplevel sinon ca plante
                    self.window.grab_set()                                                      # on fige la fenetre parente
                    self.window.protocol("WM_DELETE_WINDOW", lambda : (self.window.destroy(), self.window.quit())) # il se trouve que ca semble fonctionner comme ca...
                else:                             # dans le cas ou aucune instance tkinter n'existe
                    self.window = tkinter.Tk()                                                  # et bien on en cre une tout simplement
                ...
                self.window.mainloop()
        g = DialogWindow(fen_papa)
        return g.resultat
    Le problème c'est que l'événement lance plusieurs fenetres! malgrès le 'grab_set' qui limite la casse.

    Nom : example_echec.png
Affichages : 1903
Taille : 54,9 Ko

    -Si j'enlève l'un des 2 '.bing', ça fonctionne mais je veux pouvoir garder les 2
    -Je me dit que c'est possible car si dans 'def question' je met un 'tkinter.messagebox', je n'ai pas le problème!
    -J'ai pensé à lancer DialogWindow dans un autre processus avec multiprocessing, et bloquer la fenêtre principal avec un '.join' mais je ne trouve vraiment pas ça élégant
    -J'ai essayer de créer une nouvelle Frame plutôt qu'une nouvelle fenêtre mais ce fut un échec aussi.
    -J'ai essayer de mettre un décorateur sur 'question'. Ce décorateur ayant pour but de ne pas exécuter la fonction si elle est déjà exécutée par ailleurs, ça marchouille mais je ne trouve vraiment pas ça propre du tout!

    Si cet extrai de code ne suffit pas, le code complet testable se trouve la: https://framagit.org/robinechuca/rai...aster/setup.py
    Il suffit ensuite de taper "python3 -m raisin configure" pour tout lancer.

    Si vous avez une piste ou même une solution, je suis preneur Merci!

  2. #2
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 790
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 790
    Par défaut
    Salut,

    Citation Envoyé par robinechuca Voir le message
    Si vous avez une piste ou une même une solution, je suis preneur Merci!
    Une fenêtre secondaire qui bloque/attende d'être fermée avant de permettre autre chose, s'appelle fenêtre modale.
    Vous avez un tuto. la dessus sur effbot.

    Pas sûr que ce soit le seul problème mais la mise au point votre application et la réduction des problèmes rencontrés à un code minimal qui permette de le reproduire... c'est votre boulot (je sais combien c'est ingrat et harassant, et plein de moment de solitude... mais j'ai déjà ma dose tous les jours).

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  3. #3
    Membre éprouvé
    Homme Profil pro
    Vagabong étudiant en annalyse du signal.
    Inscrit en
    Avril 2019
    Messages
    139
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 27
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Vagabong étudiant en annalyse du signal.
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Avril 2019
    Messages : 139
    Par défaut
    Merci beaucoup,

    Je viens d'éplucher en détail votre lien et un autre. Mais ça ne change absolument rien à la situation, il y a systématiquement 2 fenêtres...
    même en utilisant 'wait_window' ou encore une extension de classe sur 'tkinter.Toplevel'.
    Pourtant quand j’affiche un 'tkinter.messagebox', il n'y a aucun problème.
    Je me dit que je pourrais faire une extension de 'tkinter.messagebox' mais c'est une fonction , et en regardant dans le code
    source, je n'ai pas réussi à identifier comment ils font Bref, le sujet n'est pas encore résolu, je continue mes recherches.

    D’ailleurs, pour ceux qui seraient dans le même situation que moi, l'option de relancer une nouvelle fenetre tkinter.Tk()
    dans un autre processus avec multiprocessing.Process() puis start puis join ne résout pas le problème, au contraire ça en ajoute

  4. #4
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 790
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 790
    Par défaut
    Salut,

    Simplifiez votre code a un minimum permettant de reproduire le problème.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  5. #5
    Membre éprouvé
    Homme Profil pro
    Vagabong étudiant en annalyse du signal.
    Inscrit en
    Avril 2019
    Messages
    139
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 27
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Vagabong étudiant en annalyse du signal.
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Avril 2019
    Messages : 139
    Par défaut
    le voila:

    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
    50
    51
    52
    53
    54
    55
     
     
    import tkinter
    import tkinter.messagebox
    import tkinter.ttk
     
     
    def _question_reponse(existing_window):
        class DialogWindow:
            """
            permet de poser graphiquement une question a choix ouvert a l'utilisateur
            """
            def __init__(self, existing_window):
                self.existing_window = existing_window
     
                # preparation de la fenetre
                if self.existing_window:                                                        # si il y a deja une fenetre ouverte
                    self.window = tkinter.Toplevel(self.existing_window)                        # on est oblige d'utiliser un toplevel sinon ca plante
                    self.window.grab_set()                                                      # on fige la fenetre parente
                    self.window.protocol("WM_DELETE_WINDOW", lambda : (self.window.destroy(), self.window.quit()))# il se trouve que ca semble fonctionner comme ca...
                else:                                                                           # dans le cas ou aucune instance tkinter n'existe
                    self.window = tkinter.Tk()                                                  # et bien on en cre une tout simplement
     
                self.window.mainloop()
     
     
        g = DialogWindow(existing_window)
        if g.violently_closed:
            raise KeyboardInterrupt("La fenetre a ete fermee violement!")
        return g.answer
     
     
    class _Manager():
        """
        gestionaire graphique pour la configuration de raisin
        aucune fenetre tkinter ne doit etre deja instanciee
        """
        def __init__(self, action="configure"):
            self.window = tkinter.Tk()              # et bien on cre la fenetre principale
            self.create_widgets()                   # on rempli la fenetre avec les widget.configure()
            self.window.mainloop()                  # on reste a ttentif aux action de l'utilisateur
     
        def create_widgets(self):
            """
            mise en place du contenu des fenetres
            """
            frame_account = tkinter.Frame(self.window)         # creation d'un cadre pour deposer tous les widgets 'account'
            frame_account.pack()
            username_widget = tkinter.Entry(frame_account) # variable de la bare de saisie
            username_widget.bind("<FocusOut>", lambda event: _question_reponse(self.window)) # on check des que l'on sort du champ
            username_widget.bind("<Return>", lambda event: _question_reponse(self.window)) # ou que l'on presse la touche 'entrer'
            username_widget.pack()
     
     
    _Manager(action="configure")
    il faut cliquer dans le Entry, puis taper 'entrer'

  6. #6
    Membre Expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 919
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 919
    Par défaut
    Salut,
    Citation Envoyé par robinechuca Voir le message
    il faut cliquer dans le Entry, puis taper 'entrer'
    Effectivement quand on tape sur "Entrée" une première fenêtre est créée mais quand le champs texte (Entry) perd le focus une deuxième fenêtre est créée ce qui est normal puisque c'est ce que vous demandez explicitement :

    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    username_widget.bind("<FocusOut>", lambda event: _question_reponse(self.window))  # on check des que l'on sort du champ
    username_widget.bind("<Return>", lambda event: _question_reponse(self.window))  # ou que l'on presse la touche 'entrer'

    Et il n'y a rien de fait pour empêcher qu'une deuxième fenêtre soit créée d'ailleurs une fenêtre est créée chaque fois que l'on tape sur "Entrée"...

    Vous voulez qu'une seule fenêtre à la fois soit créée ? Même si on tape plusieurs fois sur "Entrée" ou que le champs texte (Entry) perd le focus* ?


    * Pourquoi garder le "<FocusOut>" puisqu'il fait quelque chose que vous ne voulez pas ? C'est pour comprendre que je pose la question...

  7. #7
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 790
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 790
    Par défaut
    Salut,

    Ce que je constate, c'est que vous avez fait un .bind sur <FocusOut> et <Return>.
    Effectivement malgré le .grab_set, lorsque <FocusOut> pète, on a une 2ème fenêtre.
    Et je constate aussi que si à la place de créer un Toplevel, on lance message.askyesno(...), on n'a pas ce soucis.

    C'est assez facile à corriger (ou vivre avec).
    Maintenant si vous estimez que c'est un problème qui mérite d'être corrigé, la buglist Python c'est ici.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

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

Discussions similaires

  1. [Python 3.X] Tkinter Toplevel apparaît mais pas d'affichage
    Par lagratteCchouette dans le forum Tkinter
    Réponses: 3
    Dernier message: 23/12/2019, 13h11
  2. Image dans une sous-fenetre Tkinter
    Par guillaume_pays_ceven dans le forum Tkinter
    Réponses: 2
    Dernier message: 16/05/2007, 13h25
  3. Communication entre deux fenetres qui n'ont pas de lien de parenté
    Par Invité dans le forum Général JavaScript
    Réponses: 1
    Dernier message: 02/09/2006, 15h58
  4. [VB6] La fenetre ne s'affiche pas
    Par jerzy59 dans le forum VB 6 et antérieur
    Réponses: 8
    Dernier message: 10/05/2006, 13h11
  5. comment savoir si une fenetre est agrandi ou pas ?
    Par EssaiEncore dans le forum Langage
    Réponses: 3
    Dernier message: 07/11/2005, 11h42

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