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

  1. #1
    Membre habitué Avatar de robinechuca
    Homme Profil pro
    PHELMA grenoble inp
    Inscrit en
    avril 2019
    Messages
    108
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 22
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : PHELMA grenoble inp
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : avril 2019
    Messages : 108
    Points : 131
    Points
    131
    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 : 294
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 sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    juin 2008
    Messages
    17 701
    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 : 17 701
    Points : 30 551
    Points
    30 551
    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 habitué Avatar de robinechuca
    Homme Profil pro
    PHELMA grenoble inp
    Inscrit en
    avril 2019
    Messages
    108
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 22
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : PHELMA grenoble inp
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : avril 2019
    Messages : 108
    Points : 131
    Points
    131
    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 sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    juin 2008
    Messages
    17 701
    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 : 17 701
    Points : 30 551
    Points
    30 551
    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 habitué Avatar de robinechuca
    Homme Profil pro
    PHELMA grenoble inp
    Inscrit en
    avril 2019
    Messages
    108
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 22
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : PHELMA grenoble inp
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : avril 2019
    Messages : 108
    Points : 131
    Points
    131
    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 498
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : octobre 2011
    Messages : 2 498
    Points : 3 231
    Points
    3 231
    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 sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    juin 2008
    Messages
    17 701
    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 : 17 701
    Points : 30 551
    Points
    30 551
    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

  8. #8
    Membre expert
    Homme Profil pro
    Inscrit en
    octobre 2011
    Messages
    2 498
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : octobre 2011
    Messages : 2 498
    Points : 3 231
    Points
    3 231
    Par défaut
    Re-salut,

    Une autre question me turlupine : la condition if self.existing_window n'est-elle pas toujours vraie ?

    Si elle fausse, c'est-à-dire comme vous dites "dans le cas ou aucune instance tkinter n'existe" alors vous créez un instance tkinter... Mais si la fonction _question_reponse est exécutée c'est que forcément il existe une instance tkinter, non ?

  9. #9
    Membre habitué Avatar de robinechuca
    Homme Profil pro
    PHELMA grenoble inp
    Inscrit en
    avril 2019
    Messages
    108
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 22
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : PHELMA grenoble inp
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : avril 2019
    Messages : 108
    Points : 131
    Points
    131
    Par défaut
    Merci pour toutes ces réponses

    1)
    la condition if self.existing_window n'est-elle pas toujours vraie ?
    Si c'est toujours vrai dans cet exemple! Seulement dans mon code, ce n'est pas tout le temps le cas.

    2)Oui, je souhaite qu'une seule fenêtre à la fois soit créée, de toute façon, quand la première fenêtre se ferme, elle change l’environnement de sorte que les futures fenêtres ne soient pas créées.

    3)Je tiens au <FocusOut> car il ne me parait pas trivial de demander à l'utilisateur de taper sur <Return> systématiquement. A la rigueur, je me passerais plutôt de <Return>. Mais je suis surpris qu'on ne puisse pas mettre autant d’événements qu'on veut.

    4)
    Effectivement malgré le .grab_set, lorsque <FocusOut> pète, on a une 2ème fenêtre.
    Heu Je ne suis pas certain de comprendre: le '.grab_set' n'aurai pas d'effet sur événement <FocusOut> ? Il n'arriverai pas à l'empêcher?

    5)
    C'est assez facile à corriger.
    Houla! Vous voulez dire à corriger dans mon code, ou dans cpython?
    Je ne suis pas contre faire un rapport de bug (quand je l'aurais mieux compris) mais je vois que beaucoup sont déjà signalés.
    Est-ce vraiment un service à rendre aux développeurs python de les submerger encore plus (j'ai l’impression qu'il y a plus de 7400 bugs en attente de résolution).

  10. #10
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    juin 2008
    Messages
    17 701
    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 : 17 701
    Points : 30 551
    Points
    30 551
    Par défaut
    Salut,

    Citation Envoyé par robinechuca Voir le message
    Houla! Vous voulez dire à corriger dans mon code, ou dans cpython?
    Dans votre code bien sûr pour cpython, (ou plutôt TCL/Tk), on peut toujours leur signaler mais il est tellement facile à contourner que çà ne va pas être dans les top priority bugs.

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

  11. #11
    Membre habitué Avatar de robinechuca
    Homme Profil pro
    PHELMA grenoble inp
    Inscrit en
    avril 2019
    Messages
    108
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 22
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : PHELMA grenoble inp
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : avril 2019
    Messages : 108
    Points : 131
    Points
    131
    Par défaut
    Et bien merci à tous pour vos réponses,

    La solution que j'ai mis en place est un système de 'verrou', qui permet de s'assurer qu'il n'y ai pas de fenêtre en double. C'est de la bidouille, mais faute de mieux ça donne le résultat attendu.

  12. #12
    Membre expert
    Homme Profil pro
    Inscrit en
    octobre 2011
    Messages
    2 498
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : octobre 2011
    Messages : 2 498
    Points : 3 231
    Points
    3 231
    Par défaut
    Citation Envoyé par robinechuca Voir le message
    La solution que j'ai mis en place est un système de 'verrou', qui permet de s'assurer qu'il n'y ai pas de fenêtre en double. C'est de la bidouille, mais faute de mieux ça donne le résultat attendu.
    C'est-à-dire tu as fait quoi exactement ?

    En tous cas ce problème m'a intrigué, il semblerait que grab_set ne fonctionne pas avec les champs texte (Entry), je me suis dit c'est peut-être à cause du bind mais non car avec un bouton cela fonctionne avec bind et command...

    J'ai testé avec ce code :

    Code python : 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
    from tkinter import Tk, Toplevel, Button, Frame, END, Entry
     
     
    class Gui(Frame):
     
        def __init__(self, master, *args, **kwargs):
            Frame.__init__(self, master, *args, **kwargs)
     
            self.master = master
            self.my_frame = Frame(self.master)
            self.my_frame.pack()
     
            self.button1 = Button(
                self.master, text="Button-command Ouvrir Nouvelle Fenêtre", command=new_win)
            self.button1.pack()
     
            self.button2 = Button(
                self.master, text="Button-bind Ouvrir Nouvelle Fenêtre")
            self.button2.pack()
            self.button2.bind("<Button-1>", new_win)
     
            self.username_widget = Entry(self.master)
            self.username_widget.bind("<FocusOut>",  new_win)
            self.username_widget.bind("<Return>",  new_win)
            self.username_widget.pack()
     
     
    def new_win(event=None):
     
        NewWindow()
     
     
    class NewWindow(Toplevel):
     
        def __init__(self, *args, **kwargs):
            Toplevel.__init__(self, *args, *kwargs)
            self.button = Button(self, text="quit", command=lambda: quit())
            self.button.pack()
            self.grab_set()
     
     
    if __name__ == "__main__":
        root = Tk()
        app = Gui(root)
        root.mainloop()

    Une fenêtre est créée chaque fois que l'on tape sur "Entrée" du champ texte ou que le champs texte (Entry) perd le focus...

  13. #13
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    juin 2008
    Messages
    17 701
    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 : 17 701
    Points : 30 551
    Points
    30 551
    Par défaut
    Salut,

    Citation Envoyé par robinechuca Voir le message
    C'est de la bidouille, mais faute de mieux ça donne le résultat attendu.
    Un singleton aurait été plus "moderne" (mais galère à réaliser dans votre code actuel).

    Après consultation de nombreuses notes qui trainent sur le sujet, Tk ne gère pas complètement le focus lors de la création d'une nouvelle fenêtre: c'est le windows manager qui est en dessous qui bosse, et on peut avoir des focusout intempestifs.

    De plus, le grab_set n'est pris en compte qu'après que la fenêtre soit "visible".
    Et une fois que l'évènement est dans la pile d'évènements, dès qu'on rend la main à la boucle évènementielle, il sera traité (et on se retrouve avec 2 fenêtres).

    Vérou/Singleton... je n'ai pas mieux.

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

  14. #14
    Membre habitué Avatar de robinechuca
    Homme Profil pro
    PHELMA grenoble inp
    Inscrit en
    avril 2019
    Messages
    108
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 22
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : PHELMA grenoble inp
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : avril 2019
    Messages : 108
    Points : 131
    Points
    131
    Par défaut
    on peut avoir des focusout intempestifs
    Et bien voila donc une réponse très claire! Ça explique beaucoup de choses

    C'est-à-dire tu as fait quoi exactement ?
    et bien j'ai fait ça:
    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
     
    class JumpDecorator:
        """
        permet de s'assurer que la fonction n'est excécutee qu'une seule fois
        """
        def __init__(self):
            self.is_free = {} # c'est l’élément qui permet de savoir si la fonction est en cours d’exécution
     
        def __call__(self, func):
            """
            retourne la fonction 'func' décorée
            """
            def decorated_func(*args, **kwargs):
                if self.is_free.get(func.__name__, True):    # si la voix est libre
                    self.is_free[func.__name__] = False      # et bien on ne la laisse pas libre bien longtemps
                    try:                                     # en effet, on s'empresse
                        resultat = func(*args, **kwargs)     # exécuter la fonction qui doit être exécutée
                        self.is_free[func.__name__] = True   # une fois qu'elle c'est bien exécuter, il faut rendre la main
                    except Exception as e:                   # et ce, même si une erreur bondi depuis la fonction appelée
                        self.is_free[func.__name__] = True   # ce serait dommage de bloquer infiniment l’accès a la fonction!
                        raise e from e                       # mais bon, il ne faut tout de même pas planquer les erreurs
                    return resultat                          # si tout c'est bien passé, on retourne le résultat
            return decorated_func
     
    @JumpDecorator() # on appelle la methode __init__ de façon a n'avoir qu'une instance de l'objet et donc un verrou unique
    def foo(*args, **kwargs):
        """
        la fonction qui ne doit pas
        être executer simultanement
        """
        ...

  15. #15
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    juin 2008
    Messages
    17 701
    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 : 17 701
    Points : 30 551
    Points
    30 551
    Par défaut
    Oui enfin... reproduire le problème se fait assez simplement:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    import tkinter as tk
     
    def create_window():
        w = tk.Toplevel()
        w.grab_set()
        w.focus_set()
        w.wait_window()
     
    entry = tk.Entry()
    entry.bind('<Return>', lambda e: create_window())
    entry.bind('<FocusOut>', lambda e: create_window())
    entry.focus_set()
    entry.pack()
    tk.mainloop()
    16 lignes de code où on a enlevé tout le superflu, c'est quand même plus simple à comprendre que ce qui a été posté ici.

    Outre que çà montre qu'on a essayé de bosser sur le sujet, çà permet aussi aux débutants de reproduire le problème avec un code compréhensible.

    Facile aussi dans ce cas de tester une solution:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    lock = False
     
    def create_window():
        global lock
        if lock :
            return
        lock = True
     
        w = tk.Toplevel()
        w.grab_set()
        w.focus_set()
        w.wait_window()
     
        lock = False
    et comme, elle sera "compréhensible" (enfin il faut quand même savoir un peu programmer) elle pourra être comprise et adaptée à la sauce de son goût.

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

  16. #16
    Membre expert
    Homme Profil pro
    Inscrit en
    octobre 2011
    Messages
    2 498
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : octobre 2011
    Messages : 2 498
    Points : 3 231
    Points
    3 231
    Par défaut
    Salut,

    Citation Envoyé par robinechuca Voir le message
    et bien j'ai fait ça:
    Merci je vais essayer de comprendre... Perso je pensais simplement à une variable pour faire cela certes elle serait globale...
    D'ailleurs puisque que tu utilises une classe n'y a-t-il pas moyen d'ajouter une variable "statique" (il faut que je regarde si ça existe en Python).



    Citation Envoyé par wiztricks Voir le message
    16 lignes de code où on a enlevé tout le superflu, c'est quand même plus simple à comprendre que ce qui a été posté ici.
    J'ai testé et cela provoque la même erreur que j'avais eu en testant le code que j'ai posté... J'ai ajouté event=None pour régler le problème mais pour ton code j'ai remplacé def create_window(): par def create_window(event): ...

    Citation Envoyé par wiztricks Voir le message
    et comme, elle sera "compréhensible" (enfin il faut quand même savoir un peu programmer) elle pourra être comprise et adaptée à la sauce de son goût.
    J'avai aussi pensé à ça, c'est en effet plus simple même si on se retrouve avec une variable globale d'ailleurs justement il faut ajouter global lock dans ta fonction create_window...

  17. #17
    Membre habitué Avatar de robinechuca
    Homme Profil pro
    PHELMA grenoble inp
    Inscrit en
    avril 2019
    Messages
    108
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 22
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : PHELMA grenoble inp
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : avril 2019
    Messages : 108
    Points : 131
    Points
    131
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    16 lignes de code où on a enlevé tout le superflu, c'est quand même plus simple à comprendre que ce qui a été posté ici.
    Effectivement, j'ai supprimé quelque milliers de lignes mais j’aurais pu aller un peu plus loin. Dans ma façon de programmer, je fait des choses très 'générale' que j'applique ensuite à un cas particulier, et c'est vrai que ça prend souvent plus de lignes. La prochaine fois que je posterais, je fournirais plus de travail sur la simplification, pour plus de clarté. Pardon d'avoir été confus. Et encore merci pour votre investissement.

+ 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