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 :

App multiframe - .place() au lieu de .pack() n'affiche rien [Python 3.X]


Sujet :

Tkinter Python

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    206
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 206
    Points : 127
    Points
    127
    Par défaut App multiframe - .place() au lieu de .pack() n'affiche rien
    Bonjour à tous,

    Je m'excuse par avance si ma question vous semble trivial, mais je me considère comme étant un (grand) débutant en Python.
    J'ai effectué des recherches pour résoudre mon problème, autant ici que sur Stack Overflow, ainsi que mon moteur de recherche préféré. Sans résultat concluant !

    Contexte : Je souhaite créer une application sur la base de différents formulaires, en passant de l'un à l'autre par le biais d'un menu. A chaque nouvelle "ouverture", le formulaire doit se réinitialiser.
    J'ai trouvé plusieurs approches pour créer une application multiforme, mais une seule permettant cette réinitialisation. Je m'en suis donc inspiré.
    Cette approche utilise la méthode .pack() pour placer les différents widgets. Compte tenu de mes besoins, je souhaitais passer par la méthode .place()

    Suite à mes remplacements, je me rend compte que l'outil ne fonctionne plus : rien ne s'affiche dans ma fenêtre.
    En farfouillant, j'en suis venu à remplacer "self" par "master" ou "master._frame" lors de la création de l'objet. Mais alors, un autre problème apparaît : les widgets ne sont plus effacés lors du passage d'un formulaire à l'autre.

    Avez-vous une idée de comment remédier à l'un de ces inconvénients ? Une lecture accessible me permettant de comprendre le pourquoi du comment ? (En français ou anglais, pas de problèmes !)

    Ci-dessous un exemple apuré du code initial, avec commentaires :

    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
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
     
    import tkinter as tk
     
     
    class SampleApp(tk.Tk):
        def __init__(self):
            tk.Tk.__init__(self)
            self._frame = None
            self.switch_frame(StartPage)
     
        def switch_frame(self, frame_class):
            """Destroys current frame and replaces it with a new one."""
            new_frame = frame_class(self)
            if self._frame is not None:
                self._frame.destroy()
            self._frame = new_frame
            self._frame.pack()
     
     
    # Toutes les pages seront dans d'autres modules/fichiers que le SampleApp
    # Je regroupe ça ici pour simplifier !
    class StartPage(tk.Frame):
        def __init__(self, master):
            tk.Frame.__init__(self, master)
     
            # avec la méthode .pack() tout fonctionne correctement, mais ça va être compliqué pour organiser les GUI
            # si je remplace par .place(), rien de s'affiche, sauf si je change aussi
            # le "self" en "master", par ex pour le label :
     
            # tk.Label(master, text="This is the start page").place(relx=0.1, rely=0.1)
     
            # par contre en faisant comme ça, la méthode "switch_frame" de SampleApp n'efface plus les widgets
            # quand je passe d'une page à l'autre
     
            # En gros mon objectif : avoir le même fonctionnement, mais en utilisant .place()
     
            tk.Label(self, text="This is the start page").pack(side="top", fill="x", pady=10)
            tk.Button(self, text="Open page one",
                      command=lambda: master.switch_frame(PageOne)).pack()
            tk.Button(self, text="Open page two",
                      command=lambda: master.switch_frame(PageTwo)).pack()
     
     
    class PageOne(tk.Frame):
        def __init__(self, master):
            tk.Frame.__init__(self, master)
     
            # Problème identique à Startpage
     
            tk.Label(self, text="This is page one").pack(side="top", fill="x", pady=10)
            tk.Button(self, text="Return to start page",
                      command=lambda: master.switch_frame(StartPage)).pack()
            tk.Button(self, text="Open page two",
                      command=lambda: master.switch_frame(PageTwo)).pack()
     
     
    class PageTwo(tk.Frame):
        def __init__(self, master):
            tk.Frame.__init__(self, master)
     
            # Problème identique à Startpage
     
            tk.Label(self, text="This is page two").pack(side="top", fill="x", pady=10)
            tk.Button(self, text="Return to start page",
                      command=lambda: master.switch_frame(StartPage)).pack()
     
     
    if __name__ == "__main__":
        app = SampleApp()
        app.geometry("300x300")
        app.mainloop()
    En vous remerciant par avance pour vos lumières,

    Jacques

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 442
    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 442
    Points : 37 034
    Points
    37 034
    Par défaut
    Salut,

    Citation Envoyé par wulfram Voir le message
    Cette approche utilise la méthode .pack() pour placer les différents widgets. Compte tenu de mes besoins, je souhaitais passer par la méthode .place()
    Si vous ne montrez pas ce que vous avez essayé de faire...

    Notez que place c'est sympa pour des popup, mais s'il faut afficher plusieurs widgets et gérer leur visibilité comme le font grid ou pack, çà devient vite galère.

    - W

  3. #3
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    206
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 206
    Points : 127
    Points
    127
    Par défaut
    Bonsoir,

    Tout d'abord, permettez-moi de vous remercier pour votre retour.

    Concernant l'aspect pratique entre .place() et .pack(), ce doit être une question d'habitude : je trouve bien plus intuitif de placer les widgets où je le souhaite que de les empiler. A noter que dans mon application, la taille de la fenêtre sera figée (app.resizable(height=0, width=0)), ce qui doit réduire les problématiques souvent mises en avant avec .place().
    Mais cela vaudrait peut-être la peine de m'entrainer avec .pack(), puisque je ne peux prendre à la légère votre avis qui semble éclairé !

    Concernant mes essais, j'ai essayé les quatre combinaisons suivantes dans mon code (pour le label par exemple) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
            tk.Label(self, text="This is the start page").pack(side="top", fill="x", pady=10)
    # ça fonctionne bien, mais je n'aime pas / n'arrive pas à utiliser .pack()
            tk.Label(self, text="This is the start page").place(relx=0.1, rely=0.1)
    # rien ne s'affiche (dès le départ), à part une fenêtre vierge
            tk.Label(master, text="This is the start page").place(relx=0.1, rely=0.1)
            tk.Label(master._frame, text="This is the start page").place(relx=0.1, rely=0.1)
    # dans ces deux cas, la première page (StartPage) s'affiche correctement, mais en voulant ensuite naviguer entre les "pages", les widgets ne sont pas effacés
    J'ai également essayé avec des méthodes différentes dans chaque classe, le résultat est identique à la description supra.

    Le code complet avec self et .place() (ce qui, je pensais, aurait du fonctionner tout 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
    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
    import tkinter as tk
     
     
    class SampleApp(tk.Tk):
        def __init__(self):
            tk.Tk.__init__(self)
            self._frame = None
            self.switch_frame(StartPage)
     
        def switch_frame(self, frame_class):
            """Destroys current frame and replaces it with a new one."""
            new_frame = frame_class(self)
            if self._frame is not None:
                self._frame.destroy()
            self._frame = new_frame
            self._frame.pack()
     
     
    class StartPage(tk.Frame):
        def __init__(self, master):
            tk.Frame.__init__(self, master)
            tk.Label(self, text="This is the start page").place(relx=0.1, rely=0.1)
            tk.Button(self, text="Open page one",
                      command=lambda: master.switch_frame(PageOne)).place(relx=0.1, rely=0.3)
            tk.Button(self, text="Open page two",
                      command=lambda: master.switch_frame(PageTwo)).place(relx=0.1, rely=0.5)
     
     
    class PageOne(tk.Frame):
        def __init__(self, master):
            tk.Frame.__init__(self, master)
            tk.Label(self, text="This is page one").place(relx=0.1, rely=0.1)
            tk.Button(self, text="Return to start page",
                      command=lambda: master.switch_frame(StartPage)).place(relx=0.1, rely=0.3)
            tk.Button(self, text="Open page two",
                      command=lambda: master.switch_frame(PageTwo)).place(relx=0.1, rely=0.5)
     
     
    class PageTwo(tk.Frame):
        def __init__(self, master):
            tk.Frame.__init__(self, master)
            tk.Label(self, text="This is page two").place(relx=0.1, rely=0.1)
            tk.Button(self, text="Return to start page",
                      command=lambda: master.switch_frame(StartPage)).place(relx=0.1, rely=0.31)
     
     
    if __name__ == "__main__":
        app = SampleApp()
        app.geometry("300x300")
        app.mainloop()
    En vous remerciant,

  4. #4
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 442
    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 442
    Points : 37 034
    Points
    37 034
    Par défaut
    Salut,

    Si vous utilisez "master" comme parent des widgets "placés", ils passeront à travers le .destroy() lors du changement de page.

    Pour le reste, vous avez oublié que la Frame dans laquelle sont affichés les widgets via pack ou grid sera, par défaut, redimensionnée pour qu'on voit les widgets qu'on y affiche.

    place ne fait pas ce boulot pour vous: la dimension de la Frame est nulle. Du coup, on ne voit pas les widgets.
    La dimension de la fenêtre principale n'étant pas nulle permet de les voir... mais .destroy ne fonctionne plus.

    Bon courage.

    - W

  5. #5
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    206
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 206
    Points : 127
    Points
    127
    Par défaut
    Si je vous suis correctement, l'idée serait donc effectivement de conserver le "self", afin que le "destroy" fonctionne toujours, tout en réussissant à modifier la taille de la nouvelle Frame.
    Je viens de faire quelques essais sans succès, mais je vais essayer un peu tous les endroits du code possible, avec différentes combinaisons de self/master.

    Merci pour la piste, je vous tiens au courant !

  6. #6
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    206
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 206
    Points : 127
    Points
    127
    Par défaut
    Me revoila ! (Déjà...)

    Après quelques essais infructueux, j'ai compris que je ne cherchais pas de la bonne manière.
    Je me suis donc tourné une fois de plus vers mon ami, lu quelques posts, et trouvé une solution.

    J'ai donc ajouté une ligne à ma fonction me permettant de passer d'une Frame à l'autre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
        def switch_frame(self, frame_class):
            """Destroys current frame and replaces it with a new one."""
            new_frame = frame_class(self)
            if self._frame is not None:
                self._frame.destroy()
            self._frame = new_frame
            self._frame.config(width=300, height=300)
            self._frame.pack()
    Encore merci pour votre aide.

    PS : ce n'était pas un oubli, je ne le savais tout simplement pas, que .place() n'avait pas d'impact sur la fenêtre, contrairement à .pack() et .grid()...

    Je me permettrais de poser une autre question relative à ce bout de code dans un autre message. (Autre problématique pour laquelle je cherche une piste depuis quelques jours, sans doute du mauvais côté, comme c'était le cas ici !)

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

Discussions similaires

  1. Réponses: 27
    Dernier message: 12/06/2014, 11h02
  2. Réponses: 0
    Dernier message: 14/01/2008, 17h13
  3. sortie en lieu et place d un fichier
    Par ZaaN dans le forum C++
    Réponses: 5
    Dernier message: 10/07/2007, 12h46
  4. pointeur en lieu et place de tableau
    Par gauguin dans le forum C
    Réponses: 11
    Dernier message: 13/02/2007, 14h34
  5. [Pack EE] Sun App Server PE 8.1 et jbdc
    Par Bartmoss dans le forum NetBeans
    Réponses: 3
    Dernier message: 22/04/2006, 00h39

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