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

GUI Python Discussion :

Organisation du code d'une interface (tkinter)


Sujet :

GUI Python

  1. #1
    Futur Membre du Club
    Organisation du code d'une interface (tkinter)
    Bonjour,

    Je rencontre toujours le même problème lorsque je créé une interface,
    je n'arrive pas à structurer le code, je ne sais pas trop comment gérer mes callbacks
    et j'en arrive rapidement à imbriquer des classes dans tout les sens

    Ce que je fais usuellement, c'est créer une classe par widget, tout mes widgets sont ensuite regroupés dans une classe "Interface"
    Et je me retrouve à faire des "inheritance" :
    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
    #!/usr/bin/python3
    # -*- coding: utf-8 -*-
     
    import tkinter as tk
    import tkinter.ttk as ttk
     
    class Graphique:
     
        def __init__(self, root):
     
            self.canvas = tk.Canvas(root, width=150, height=100)
            self.canvas.pack()
     
        def montrer_texte(self):
     
            self.canvas.create_text(30, 30, text = "mon_texte")
     
     
    class MontrerTexte:
     
        def __init__(self, root):
     
            btn = tk.Button(root, text="Montrer texte", command=lambda: self.montrer_texte())
            btn.pack()
     
     
    class MainGui(Graphique, ChoisirTexte):
     
        def __init__(self, root):
     
            Graphique.__init__(self, root)
            MontrerTexte.__init__(self, root)
     
     
    root=tk.Tk()
    MainGui(root)
    root.mainloop()


    ou des classes imbriquées :
    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
    #!/usr/bin/python3
    # -*- coding: utf-8 -*-
     
    import tkinter as tk
    import tkinter.ttk as ttk
     
    class Graphique:
     
        def __init__(self, root):
     
            self.canvas = tk.Canvas(root, width=150, height=100)
            self.canvas.pack()
     
        def montrer_texte(self):
     
            self.canvas.create_text(30, 30, text = "mon_texte")
     
     
    class MontrerTexte:
     
        def __init__(self, outer, root):
     
            btn = tk.Button(root, text="Montrer texte", command=lambda: outer.graph.montrer_texte())
            btn.pack()
     
     
    class MainGui:
     
        def __init__(self, root):
     
            self.graph = Graphique(root)
            bouton = MontrerTexte(self, root)
     
     
    root=tk.Tk()
    MainGui(root)
    root.mainloop()

    Je trouve ces constructions plutôt bancales,
    je ne vois pas trop quelle structure adopter, des conseils?

  2. #2
    Expert éminent sénior
    Salut,

    Citation Envoyé par Daguhh Voir le message
    Je trouve ces constructions plutôt bancales,
    je ne vois pas trop quelle structure adopter, des conseils?
    Si vous dîtes MontrerTexte a besoin d'accéder à une instance de Graphique parce qu'elle va appeler une méthode de cette classe là... le plus mauvais choix sera de passer par un héritage multiple puisque MainGUI n'est ni un MontrerTexte ni un Graphique.
    Les classes imbriquées ne sont pas une solution non plus puisque pour appeler son callback MontrerTexte devra supposer que outer a bien un attribut graph qui aura bien une méthode montrer_texte...
    En fait, dans l'exemple que vous montrez, MontrerTexte a juste besoin de savoir quel callback appeler peu importe l'objet...
    Donc vous pourriez vous contenter de:
    import tkinter as tk

    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 Graphique:
     
        def __init__(self, root):
     
            self.canvas = tk.Canvas(root, width=150, height=100)
            self.canvas.pack()
     
        def montrer_texte(self):
     
            self.canvas.create_text(30, 30, text = "mon_texte")
     
     
    class MontrerTexte:
     
        def __init__(self, root, callback):
     
            btn = tk.Button(root, text="Montrer texte", command=callback)
            btn.pack()
     
     
    class MainGui:
     
        def __init__(self, root):
     
            self.graphique = Graphique (root)
            self.montrertexte = MontrerTexte(root, self.graphique.montrer_texte)
     
     
    root=tk.Tk()
    MainGui(root)
    root.mainloop()


    Vous réalisez que découper votre code en class, c'est créer des boîtes étanches puis réfléchir aux relations et aux interfaces que vous devrez fabriquer pour que les différentes instances puissent coopérer. Et çà c'est de la POO i.e. un style de programmation à apprendre indépendamment de Python.

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

  3. #3
    Futur Membre du Club
    Bonjour,


    Oui je me rendais bien compte que ma façon de faire allait à l'encontre de l'idée de classe, puisqu'elle consistait à faire trous dans mes boites étanches.
    Passer la fonction en tant que paramètre ne m'a jamais traversé l'esprit, je ne l'ai jamais fait et donc jamais envisagée (bien que la mécanique soit similaire avec celle d'un callback)
    Mais en voyant la solution, effectivement, ça parait plus naturel de faire ainsi

    Me pencher sur un bouquin de POO pure n'est pas une mauvaise idée non plus...

    Merci pour votre réponse détaillée!

###raw>template_hook.ano_emploi###