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 :

Classe dérivée de Frame [Python 3.X]


Sujet :

Tkinter Python

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Enseignant
    Inscrit en
    Août 2012
    Messages
    31
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2012
    Messages : 31
    Points : 31
    Points
    31
    Par défaut Classe dérivée de Frame
    Bonsoir à tous, je continue à grand peine mon apprentissage de Tkinter à l'aide de classes. J'ai trouvé sur le site de l'université de paris Diderot ce programme qui me déconcerte. Je précise que j'utilise winPython avec l'IDE spyder.


    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
    import tkinter as tk
    class Application(tk.Frame):   
        def __init__(self, racine=None):
            tk.Frame.__init__(self)
            self.racine = racine
            self.create_widgets()
     
        def create_widgets(self):
            self.label = tk.Label(self.racine, text="J'adore Python !")
            self.bouton = tk.Button(self.racine, text="Quitter", command=self.destroy)
            self.label.pack()
            self.bouton.pack()
     
     
    app = Application()
    app.mainloop()
    Question 1
    Pourquoi cliquer sur le bouton ne donne rien (la fenêtre ne se ferme pas) ?

    Question 2
    L'auteur explique que la ligne tk.Frame(self) instancie automatiquement une fenêtre Tk. Ça, je veux bien le croire. Mais il ajoute que l'instance de la fenêtre principale est alors self.racine. C'est sûrement basique, mais je ne comprends pas du tout pourquoi. Ce n'est pas le paramètre self qui contient cette référence ?

    Questions 3
    Quel-est le nom du widget Frame ? Est-ce qu'il est exact de penser que ce Frame a l'instance app pour parent et que Label et Button sont censés être les enfants de Frame ?

    Question 4
    Cet attribut self.racine, quel est son intérêt (à supposer qu'il serve à quelque chose) ? Est-ce que l'attribut self.master ne suffit pas ? J'ai modifié le programme de cette façon. Est-ce que malgré les apparences j'ai fait quelque chose de très différent ?

    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
    class Application(tk.Frame):
        def __init__(self):
            tk.Frame.__init__(self)
            self.create_widgets()
     
        def create_widgets(self):
            self.label = tk.Label(self.master, text="J'adore Python !")
            self.bouton = tk.Button(self.master, text="Quitter", command=self.master.destroy)
            self.label.pack()
            self.bouton.pack()
     
    app = Application()
    app.mainloop()
    Question 5
    Pour finir, si je condense les deux dernières lignes en
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Application().mainloop()
    Comment connaître la référence de la fenêtre principale ?

    Voilà, j'ai conscience d'avoir été long, et pas forcément très clair. J'ai du chemin à faire hein ? Mais je remercie d'avance les bonnes âmes patientes qui se pencheront sur mes questions.

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

    Vous n'avez pas besoin d'utiliser les class pour programmer avec tkinter. Ce qui est intéressant car ça évite de se mélanger les pinceaux entre les notions tkinter et celles des "class".

    Citation Envoyé par zeddiccus Voir le message
    Pourquoi cliquer sur le bouton ne donne rien (la fenêtre ne se ferme pas) ?
    Cliquer sur le Button applique la méthode .destroy à "self" qui est une instance d'application héritant de Frame (donc une Frame) alors que le Button a été crée avec self.master=None comme parent. Autrement dit, la fenêtre principale que tkinter a créé automatiquement parce qu'il faut bien afficher les widgets dans une fenêtre...

    Citation Envoyé par zeddiccus Voir le message
    L'auteur explique que la ligne tk.Frame(self) instancie automatiquement une fenêtre Tk. Ça, je veux bien le croire. Mais il ajoute que l'instance de la fenêtre principale est alors self.racine.
    La programmation n'est pas une religion, vous ne devez pas "croire" mais vérifier et faire un print(self.racine) montrerait que l'objet associé est None. Si on lit le code, il n'y a aucune raison pour que ce soit autre chose.

    Citation Envoyé par zeddiccus Voir le message
    Cet attribut self.racine, quel est son intérêt (à supposer qu'il serve à quelque chose) ? Est-ce que l'attribut self.master ne suffit pas ?
    Faites un print(self.master) çà va afficher autre chose que None (et normalement un '.' qui est "racine" car les widgets tkinter sont rangés dans une hiérarchie (comme les répertoires/fichiers)).

    Comme self.master est la fenêtre principale la passer explicitement ou implicitement (quand c'est None) ne change pas grand chose...

    Il est inutile de préciser "racine" puisque c'est "par défaut" la fenêtre principale. Par contre, il peut être utile de la préciser si on veut autre chose...

    Pour la suite, essayez de lire la documentation tkinter.... cherchez un meilleur tuto...

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

  3. #3
    Nouveau membre du Club
    Homme Profil pro
    Enseignant
    Inscrit en
    Août 2012
    Messages
    31
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2012
    Messages : 31
    Points : 31
    Points
    31
    Par défaut
    Bonjour Wiztricks, et merci pour cette aide nocturne. Elle m'a été vraiment précieuse et je pense avoir compris. Pour tester cette toute fraîche compréhension, j'ai voulu, grâce à des couleurs et aux bordures, bien visualiser quoi est dans quoi : une fenêtre principale, (créée en douce par tkinter), qui contient l'instance app, (qui est une frame), et deux boutons placés dans cette frame, le bouton Quitter ne fermant que l'instance app mais pas la fenêtre principale.

    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
    import tkinter as tk
    class Application(tk.Frame):   
        def __init__(self, racine=None):
            tk.Frame.__init__(self, racine)
            self.master.configure(bg='light coral', bd=20)
     
            self.pack()
            self.configure(bg='Gray26', bd=2, relief='groove')
     
            self.create_widgets()
     
        def create_widgets(self):
            self.label = tk.Label(self, text="J'adore Python !")
            self.bouton = tk.Button(self, text="Quitter", bg="cyan", command=self.destroy)
            self.label.pack()
            self.bouton.pack()
     
    app = Application()
    app.mainloop()
    Encouragé par votre : "l'informatique n'est pas une religion", je me suis émancipé du code d'origine en supprimant l'attribut self.racine, totalement inutile. Donc tout marche vraiment comme je le voulais. Mais je trouve bizarre que je sois obligé de mettre self.pack() à la ligne 7 pour pouvoir modifier les options de l'instance app ? Puisque c'est une frame, est-ce qu'il n'y a pas déjà en coulisse une instruction pack() ?

  4. #4
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 283
    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 283
    Points : 36 770
    Points
    36 770
    Par défaut
    Citation Envoyé par zeddiccus Voir le message
    Puisque c'est une frame, est-ce qu'il n'y a pas déjà en coulisse une instruction pack() ?
    fenêtres principale ou secondaires ne sont pas vraiment des "widgets" alors que Frame oui. Imaginez vouloir afficher plusieurs Frame dans la même fenêtre ou remplacer une Frame par une autre (avec tous les widgets qu'elle contient)....

    Frame n'est qu'une région rectangulaire qui ne contient rien d'autre que les widgets qu'on a placé dedans. Pour jouer, remplacez:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    class Application(tk.Frame):
    par:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    class Application(tk.Label):
    çà va marcher pareil.

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

  5. #5
    Nouveau membre du Club
    Homme Profil pro
    Enseignant
    Inscrit en
    Août 2012
    Messages
    31
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2012
    Messages : 31
    Points : 31
    Points
    31
    Par défaut
    Effectivement, ça marche tout aussi bien, et c'est une très mauvaise nouvelle parce que je n'y comprends plus rien. J'ai toujours cru que le constructeur d'une classe enfant doit faire appel au même constructeur que celui de la classe parent. Alors pourquoi écrire ceci marche ?!

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class Application(tk.Label):   
        def __init__(self, racine=None):
            tk.Frame.__init__(self)
            [...]
     
    app = Application()
    app.mainloop()
    Et puisque j'y suis, est-ce que l'instance app est une fenêtre tkinter qui contient un widget Frame ou un widget Frame placé dans une fenêtre principale créée en coulisses par tkinter ?
    Mille merci d'avance à qui parviendra à comprendre le nœud de ce qui m'échappe.

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

    J'utilise quasi toujours super... et je n'avais pas fait attention à cette ligne là. Il aurait été moins confus d'écrire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    class Application(tk.Label):   
        def __init__(self, racine=None):
            super().__init__(racine)
    Sinon çà marche juste parce que dans tkinter tous les widgets héritent d'une même classe.... et que côté Python, tk.Frame.__init__(self) se réduit à appeler la fonction __init__ de la classe tk.Frame qui se résume à ajouter des attributs dans l'instance.
    Citation Envoyé par zeddiccus Voir le message
    Et puisque j'y suis, est-ce que l'instance app est une fenêtre tkinter qui contient un widget Frame ou un widget Frame placé dans une fenêtre principale créée en coulisses par tkinter ?
    L'instance de app est une sous-classe de Frame/Label.

    Le widget (qui n'est pas l'instance) s'affiche dans la fenêtre principale (par défaut). Si j'écris:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    import tkinter as tk
    root = tk.Tk()
    tk.Label(root, text='toto).pack()
    tk.mainloop()
    ou:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    import tkinter as tk
    tk.Label(text='toto).pack()
    tk.mainloop()
    çà fait juste la même chose compte tenu des défauts.

    Mais si les widgets ont une relation parent/enfants (hiérarchique) qui donne un comportement par défaut aux geometry managers, rien n'empêche (modulo quelque précautions) d'afficher un widget ailleurs que dans le parent direct (avec l'option in_ passée à pack ou grid)...

    Ce qui donne ici lieu à une relation "master"/"slave" un peu différente le widget affiché est contraint par le widget dans lequel on l'affiche (et les méthodes pack_slaves ou grid_slaves).

    La structure ajoutée par des "class" utilisateurs n'apporte pas grand chose par rapport à tout çà (on doit faire avec... et si possible éviter de se perdre).


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

  7. #7
    Nouveau membre du Club
    Homme Profil pro
    Enseignant
    Inscrit en
    Août 2012
    Messages
    31
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2012
    Messages : 31
    Points : 31
    Points
    31
    Par défaut
    Merci beaucoup wiztricks pour ces explications patientes et claires, elles éclairent beaucoup de points. Je vais pouvoir clore cette discussion, jusqu'à la prochaine...

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

Discussions similaires

  1. Gridder une classe dérivée de Frame
    Par Serratonique dans le forum Tkinter
    Réponses: 5
    Dernier message: 03/03/2014, 23h34
  2. Réponses: 2
    Dernier message: 06/12/2005, 09h41
  3. Réponses: 4
    Dernier message: 20/11/2005, 05h48
  4. [MFC] CArray et classe dérivée?
    Par TigreRouge dans le forum MFC
    Réponses: 14
    Dernier message: 02/08/2005, 22h45
  5. Déterminer le type d'une class dérivée
    Par LDDL dans le forum MFC
    Réponses: 3
    Dernier message: 10/12/2004, 17h36

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