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

Tkinter Python Discussion :

Toplevel, widgets, méthodes lift et destroy [Python 3.X]


Sujet :

Tkinter Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre très actif

    Homme Profil pro
    Bidouilleur
    Inscrit en
    Avril 2016
    Messages
    721
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Bidouilleur

    Informations forums :
    Inscription : Avril 2016
    Messages : 721
    Billets dans le blog
    1
    Par défaut Toplevel, widgets, méthodes lift et destroy
    Salut,

    J'avais laissé de côté mon script de bataille navale, je l'ai repris, j'ai résolu mon problème lié au thread, mais je n'arrive manifestement pas à résoudre en premier lieu un comportement sur le destroy d'un toplevel, ou alors c'est tellement flagrant que ça ne me saute pas aux yeux, et en second lieu le passage au 1er plan des fenêtres toplevel, les unes par rapport aux autres.

    J'explique succinctement, j'ai l'appli principale qui contient plusieurs méthodes pour ouvrir différentes fenêtres, entre-autres :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    def scores(self, titre) :
            if not MenuScores.ouvert() :
                self.__scores = MenuScores(self.menuOptions, self.__theme, self.__langue, titre)
                self.__scores.afficher()
            else :
                self.__scores.avantPlan()
    MenuScores est une classe qui hérite d'une classe Classeur (hérite de Toplevel) et d'une classe MenuBase, c'est celle-ci qui me pose problème alors qu'elle est très simple.

    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
    class MenuBase :
        instances = []
        def __init__(self) :
            MenuBase.instances.append(self)
            self.winfo_toplevel().bind('<Destroy>', self.__supInstance)
            self.i = 0
     
        def boutonFermer(self, texte) :
            boutonsQuitter = tk.Button(self, text=texte, command=self.__quitter)
            boutonsQuitter.grid(pady=10)
     
        def __supInstance(self, evt=None) :
            self.i += 1
            print(self.i)
            for n in MenuBase.instances :
                if n.__class__.__name__ == self.__class__.__name__ :
                    MenuBase.instances.remove(n)
     
        def avantPlan(self) :
            self.lift() # Ne fonctionne pas sur unix
            self.attributes('-topmost', True) # Fonctionne un moment, mais au bout de n essais, ne fonctionne plus
            '''
            # Pareil, fonctionne un moment, puis ça déconne
            for n in [n for n in MenuBase.instances if n.__class__.__name__ != self.__class__.__name__] :
                n.after_idle(self.attributes, '-topmost', False)
            self.lift()
            self.after_idle(self.attributes, '-topmost', True)
            '''
     
        def __quitter(self) :
            #self.winfo_toplevel().destroy()
            self.destroy()
     
        @classmethod
        def ouvert(self) :
            return self.__name__ in [n.__class__.__name__ for n in MenuBase.instances]
    Dans cette classe deux problèmes :

    - le lift, lorsque j'ouvre une fenêtre tkinter me la met bien en focus devant les autres toplevel, maintenant je voudrais admettons avec 2 fenêtres modales ouvertes, lorsque je clic à nouveau sur le menu d'une fenêtre déjà en cours d'exécution, elle passe au 1er plan devant les autres, mais au bout de plusieurs essais, ça ne fonctionne plus, et c'est pire encore si plus de 2 fenêtres sont ouvertes.
    Je voudrais donc savoir si lift fonctionnait chez vous sur les widgets tkinter ?
    Je suis sur Debian Jessie, architecture 64 bits.

    - Le destroy, là je pige rien, je ne comprenais pas pourquoi tkinter appelait x fois ma fonction __supInstance, et j'ai percuté que cela variait en fonction du nombre d'enfants du toplevel, comme si tkinter détruisait récursivement tous les enfants sans le faire internement mais en appelant chaque fois la fonction reliée au destroy.
    Donc soit mon erreur est tellement flagrante que je ne la voit pas, soit je n'ai pas compris quelquechose.
    Une idée ?

  2. #2
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 738
    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 738
    Par défaut
    Citation Envoyé par bistouille Voir le message
    - le lift, lorsque j'ouvre une fenêtre tkinter me la met bien en focus devant les autres toplevel, maintenant je voudrais admettons avec 2 fenêtres modales ouvertes, lorsque je clic à nouveau sur le menu d'une fenêtre déjà en cours d'exécution, elle passe au 1er plan devant les autres, mais au bout de plusieurs essais, ça ne fonctionne plus, et c'est pire encore si plus de 2 fenêtres sont ouvertes.
    Je voudrais donc savoir si lift fonctionnait chez vous sur les widgets tkinter ?
    Je suis sur Debian Jessie, architecture 64 bits.
    Changer le z-order d'une fenetre (via .lift) est une chose. La rendre modale c'est plus compliqué. Pour les détails, c'est expliqué sur effbot

    Citation Envoyé par bistouille Voir le message
    - Le destroy, là je pige rien, je ne comprenais pas pourquoi tkinter appelait x fois ma fonction __supInstance, et j'ai percuté que cela variait en fonction du nombre d'enfants du toplevel, comme si tkinter détruisait récursivement tous les enfants sans le faire internement mais en appelant chaque fois la fonction reliée au destroy.
    tkinter ne fait pas "comme si", il le fait effectivement comme çà (voir les sources).

    La difficulté à laquelle vous êtes confronté est que Python, tkinter (et derrière TCL/Tk) réalisent déjà nombre de fonctionnalités. Vous pouvez essayer de les améliorer mais si vous les ignorez vous risquez des incohérences. La question a se poser (comme toujours) est de savoir si on ira plus vite à recoder un truc vite fait plutôt qu'apprendre à utiliser une bibliothèque puis voir comment la mettre en œuvre pour ses projets.

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

  3. #3
    Membre très actif

    Homme Profil pro
    Bidouilleur
    Inscrit en
    Avril 2016
    Messages
    721
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Bidouilleur

    Informations forums :
    Inscription : Avril 2016
    Messages : 721
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Changer le z-order d'une fenetre (via .lift) est une chose. La rendre modale c'est plus compliqué. Pour les détails, c'est expliqué sur effbot
    Je pense m'être mal fait comprendre, il n'y a aucune interactivité à avoir entre les fenêtres modales, elles sont modales vis à vis du parent, mais n'ont aucune communication à faire entre elles, mon problème est uniquement une histoire de file.

    Dans la fenêtre principale, j'ai un menu destiné à ouvrir ces fenêtres.
    1 - J'ouvre fenêtre A
    2 - J'ouvre fenêtre B -> (B devant A)
    3 - J'ouvre fenêtre A -> déjà ouverte -> doit passer devant B, au 1er coup, c'est bon
    4 - J'ouvre fenêtre B -> déjà ouverte -> doit repasser devant A -> fonctionne pas

    Je pourrais carrément détruire et recréer chaque fois la fenêtre pour la faire repasser devant, mais c'est crade.

    En plus, mon problème avec lift/lower n'est pas spécifique au toplevel, avec d'autres widgets, j'ai également des dysfonctionnements, même avec les objets d'un canevas avec tag_raise et tag_lower, cela ne fonctionne pas chez moi.

    Citation Envoyé par wiztricks Voir le message
    tkinter ne fait pas "comme si", il le fait effectivement comme çà (voir les sources).
    Bien, au moins je ne suis pas fou

    Merci.

    Citation Envoyé par wiztricks Voir le message
    La difficulté à laquelle vous êtes confronté est que Python, tkinter (et derrière TCL/Tk) réalisent déjà nombre de fonctionnalités. Vous pouvez essayer de les améliorer mais si vous les ignorez vous risquez des incohérences. La question a se poser (comme toujours) est de savoir si on ira plus vite à recoder un truc vite fait plutôt qu'apprendre à utiliser une bibliothèque puis voir comment la mettre en œuvre pour ses projets.
    Je n'ai pas saisi le sens de ta remarque ni le sous-entendu.
    En quoi j'ignorerais quoi que ce soit ? Ou recoderais quoi que ce soit ?

  4. #4
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 738
    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 738
    Par défaut
    Citation Envoyé par bistouille Voir le message
    En plus, mon problème avec lift/lower n'est pas spécifique au toplevel, avec d'autres widgets, j'ai également des dysfonctionnements, même avec les objets d'un canevas avec tag_raise et tag_lower, cela ne fonctionne pas chez moi.
    Postez un code (minimal) qui permette de reproduire ce que vous constatez...
    note: minimal, c'est quelques lignes genre
    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
    import tkinter as tk
     
    root = tk.Tk()
     
    windows = []
     
    for color in ('grey', 'blue', 'green'):
        w = tk.Toplevel()
        w.title(color)
        w['bg'] = color
        w.geometry('+300+300')
        w.bind('<1>', lambda e, w=w: windows[windows.index(w) - 1].lift())
        windows.append(w)
     
    tk.mainloop()
    Bon évidemment, mon code essaie de reproduire le scenario que vous décrivez.
    S'il fonctionne aussi chez vous, c'est qu'il y manque votre "special sauce".

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

  5. #5
    Membre très actif

    Homme Profil pro
    Bidouilleur
    Inscrit en
    Avril 2016
    Messages
    721
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Bidouilleur

    Informations forums :
    Inscription : Avril 2016
    Messages : 721
    Billets dans le blog
    1
    Par défaut
    Ça ne fonctionne pas chez moi, aucune réaction quand je presse la touche, le lift ne fonctionne pas.

    Donc voilà mon code spécial « Sauce tartare du mitron »

    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
    import tkinter as tk
     
    root = tk.Frame(width=800, height=600)
    root.master.title('Fenêtre Maître')
    root.grid()
    root.grid_propagate(0)
     
    fenetresOuvertes = {}
    listeFenetres = {'red':'200+50', 'blue':'240+90', 'green':'280+130'}
     
    def fenetre(titre) :
        f = tk.Toplevel(root, width=400, height=600, bg=titre)
        f.geometry('300x500+' + listeFenetres[titre])
        f.transient(root)
        f.title(titre)
        f.grid()
        f.bind('<Destroy>', lambda evt, n=titre : fermer(n, evt))
        return f
     
     
    def ouvrir(nom) :
        if nom not in fenetresOuvertes.keys() :
            fenetresOuvertes[nom] = fenetre(nom)
        else :
            fenetresOuvertes[nom].lift() # Fonctionne pas
            fenetresOuvertes[nom].attributes('-topmost', True) # Fonctionne au 1er essais uniquement
     
    def fermer(nom, evt) :
        fenetresOuvertes[nom].destroy()
        del(fenetresOuvertes[nom])
     
     
    menu = tk.Menubutton(root, text='Options')
    menu.grid(row=1, sticky=tk.NW)
     
    menuItems = tk.Menu(menu, tearoff=0)
    menu.configure(menu=menuItems)
     
    for n in listeFenetres.keys() :
        menuItems.add_command(label=n, command=lambda f=n : ouvrir(f))
     
    root.mainloop()
    Rien de bien spécial, si ce n'est que les fenêtres sont modales et appelées via un menu.

  6. #6
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 738
    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 738
    Par défaut
    Salut,

    Chez moi le code que vous avez posté fonctionne sous Windows, Debian, Ubuntu,...
    => ce qui fait le boulot n'est ni Python, ni tkinter, ni TCL/Tk mais le "windows manager" qui sous debian est une implémentation de X11.

    - 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. Réponses: 1
    Dernier message: 23/03/2014, 18h38
  2. Méthode bind et widget
    Par henri005 dans le forum Tkinter
    Réponses: 1
    Dernier message: 20/08/2013, 14h35
  3. Réponses: 11
    Dernier message: 23/12/2011, 18h02
  4. Widget PhotoImage dans un Toplevel
    Par moithibault dans le forum Tkinter
    Réponses: 4
    Dernier message: 13/04/2010, 20h11
  5. Réponses: 5
    Dernier message: 05/09/2008, 10h02

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