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 :

Récupérer les valeurs des widgets dans un Frame à partir d'une fonction dans un autre module [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 Récupérer les valeurs des widgets dans un Frame à partir d'une fonction dans un autre module
    Bonsoir à 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é pour la base.
    Merci encore à wiztricks qui m'a aidé à franchir une étape.

    Ma question porte ici sur un autre problème, pour lequel j'ai trouvé quelques pistes, sans arriver à les exploiter.
    Si vous pouviez m'apporter réponse, ou tout au moins des pistes à suivre, je vous en serai redevable !

    Mon programme est axé autour de plusieurs modules (limité à trois dans l'exemple ci-dessous). Un de ces module à vocation à regrouper un ensemble de fonctions ayant leur utilité sur différentes pages (Frames). Le but est évidemment de ne pas recopier cette fonction à chaque fois, à la fois pour un gain de place, mais aussi afin de faciliter la lecture et compréhension du code.

    Certaines fonctions devront lister l'ensemble des objets/enfants de la page (avec "winfo_children" je pense ?), pouvoir récupérer leur valeur, ou alors modifier l'un des objet/enfant en particulier pour lui attribuer une valeur/le modifier.
    Je n'arrive pas à créer le lien vers la page/Frame, moins encore les objets. Mais j'imagine que répondre au premier problème me permettra de résoudre également le second ?

    Pour exemple, mon code, en trois modules :


    Module : main
    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
    import tkinter as tk
    from Pages import *
     
     
    class SampleApp(tk.Tk):
        def __init__(self):
            tk.Tk.__init__(self)
            self._frame = None
            self.switch_frame(StartPage)
     
        def switch_frame(self, frame_class):
            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()
     
     
    if __name__ == "__main__":
        app = SampleApp()
        app.geometry("300x300")
        app.mainloop()
    Module : Pages
    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
    import tkinter as tk
    from function import *
     
     
    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)
            tk.Button(self, text="Do something",
                      command=lambda: dosomething).place(relx=0.1, rely=0.7)
            my_entry = tk.Entry(self, name="txt_my_entry").place(relx=0.1, rely=0.9)
     
     
    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)
            tk.Button(self, text="Do something",
                      command=lambda: dosomething).place(relx=0.1, rely=0.7)
            my_entry = tk.Entry(self, name="txt_my_entry").place(relx=0.1, rely=0.9)
     
     
    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.3)
            tk.Button(self, text="Do something",
                      command=lambda: dosomething).place(relx=0.1, rely=0.5)
            my_entry = tk.Entry(self, name="txt_my_entry").place(relx=0.1, rely=0.9)
    Module : function
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    import tkinter as tk
     
    def dosomething():
        print("Here I want to get values from widgets in the active Frame")
        print("Ici, je veux récupérer les valeurs d'objets dans le cadre actif")
    En vous remerciant par avance pour vos lumières, pistes, idées,...

    Bonne soirée à tous,

  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
    Je n'arrive pas à créer le lien vers la page/Frame, moins encore les objets. Mais j'imagine que répondre au premier problème me permettra de résoudre également le second ?
    Une fonction ne peut accéder qu'aux objets associées aux paramètres/variables locales d'appels et à ceux associés aux variables globales.

    Et si elles doivent accéder à des objets particuliers autant en faire des méthodes de ces objets là.

    Citation Envoyé par wulfram Voir le message
    Mon programme est axé autour de plusieurs modules (limité à trois dans l'exemple ci-dessous). Un de ces module à vocation à regrouper un ensemble de fonctions ayant leur utilité sur différentes pages (Frames). Le but est évidemment de ne pas recopier cette fonction à chaque fois, à la fois pour un gain de place, mais aussi afin de faciliter la lecture et compréhension du code.
    Si l'objectif est "faciliter la lecture et compréhension du code" en utilisant les boites de rangement "class" et "modules" pour "ranger" votre code, il va falloir le reformuler pour y arriver avec ce que ces outils vous proposent (savoir penser avec tkinter, des class, les modules Python,...).

    A la fin, il restera quand même un large choix de découpages possibles, le faire à priori demande une certaine expérience (avoir déjà écrit des applications de ce type). Dans le cas contraire, autant garder tout dans le même module le plus longtemps possible et "découper" quelque chose de fonctionnel.

    C'est plus facile de ranger un tas d'objets dont on connaît rôle et relations avec les autres, plutôt que de partir sur un tas de boîtes arbitraires et patauger à savoir où ranger un truc qu'on n'a même pas commencé à écrire.

    - 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,

    Une fois de plus, je vous remercie pour votre réponse pertinente et constructive.

    Afin de "déconstruire" le problème, je cherche effectivement à accéder aux informations que je souhaite via une fonction placée dans le même module. (un seul module pour l'ensemble) Je me suis permis de présenter la problématique ainsi, car c'est où je souhaite aller. Le découpage auquel je pense fait selon une typologie des fonctionnalités (navigation, formulaires de saisis, formulaires de restitutions, fonctions opérationnelles, fonctions support,...) comme j'ai pu le faire avec une application aux bases similaire en VBA.
    Ce n'est peut-être pas adapté à Python ?

    Dans tous les cas, je n'ai eu qu'une petite heure pour chercher aujourd'hui, sans succès. J'y passerai plus de temps demain. Pensez-vous qu'il puisse être intéressant que je détaille ma démarche de recherche au fur-à-mesure ? Il me semble que cela prendrait bien de la place, pour peu de réponse, mais si cela vous intéresse je ne manquerai pas de le faire !

    Bonne soirée à vous,

  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,

    Citation Envoyé par wulfram Voir le message
    Ce n'est peut-être pas adapté à Python ?
    C'est à vous de l'adapter à Python.
    Mais honnêtement, si vous avez l'habitude de programmer en VBA (ou dans n'importe quel autre langage), je comprends qu'on ait besoin de s'y retrouver en comparant.
    C'est un peu comme quand on apprend une langue étrangère, au début, on pense en français et on traduit mot à mot. Mais pour de venir "fluent", il va falloir apprendre à penser dans cette langue là.

    Avec Python, c'est un peu pareil... Il faut arriver à penser Python, tkinter, POO et çà fait 3 gros sujets à bien potasser avant de pouvoir se lancer sans se cogner contre des murs.

    Citation Envoyé par wulfram Voir le message
    Dans tous les cas, je n'ai eu qu'une petite heure pour chercher aujourd'hui, sans succès. J'y passerai plus de temps demain. Pensez-vous qu'il puisse être intéressant que je détaille ma démarche de recherche au fur-à-mesure ?
    Vous faites un peu comme vous voulez... Si j'ai du temps, j'essaierai de vous répondre.

    - 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
    Bonsoir,

    Désolé pour le temps de réponse. Les mesures gouvernementales m'ont donné un "léger" surplus de travail.
    Merci bien pour votre analogie aux langues, ayant eu l'opportunité d'en apprendre plusieurs lors de mes voyages, votre exemple me parle tout à fait.
    Je n'irai pas jusqu'à dire que j'ai l'habitude de coder en VBA, j'ai simplement eu à m'en servir à quelques reprises fin de me faciliter la tâche. Je ne suis pas "codeur", ni même dans le domaine informatique, et n'en prends pas la voie : je ne fais que chercher des solutions à mes problèmes, et je vous remercie une fois encore de m'avoir éclairé quelques chemins.

    Avec Python, c'est un peu pareil... Il faut arriver à penser Python, tkinter, POO et çà fait 3 gros sujets à bien potasser avant de pouvoir se lancer sans se cogner contre des murs.
    Je ne compte pas y passer mes nuits, mais auriez-vous des lectures synthétiques me permettant d'appréhender, sur ces sujets, les tenants et aboutissants de vos propos ? LA documentation Python me semble un peu lourde à digérer pour une première approches !

    Pour en revenir à nos moutons, j'avais effectivement approché le problème, dans un premier temps, en créant une "méthode" (sans savoir que cela s'appelait ainsi !) dans chaque classe correspondant à une "page". Cette méthode était identiques dans toutes, raison pour laquelle je souhaitais "monter" un niveau au dessus. Afin de résoudre ce problème, et suite à vos propos, j'ai repensé aux nombreux essais réalisés afin de forcer la taille de ma frame tout en utilisant .place().

    J'ai donc commencé à créer une méthode (dosomething2) directement dans la classe servant de "relais" entre les pages. (Dans mon programme complet, c'est là que j'ai placé la création du menu) Puis une seconde (dosomething3) avec une autre approche, néanmoins très proche. (Avec ou sans passage de variable lors de l'appel de la méthode)

    Mais ce début de solution ne me convenait pas pleinement : en effet, je vais à termes avoir un bon nombre de méthodes à utiliser dans des pages aux finalités diverses. Je souhaitais donc pouvoir "sortir" cette méthode, afin de la placer dans un autre module, comme indiqué au début. Vos propos me font penser que ce n'est peut-être pas une autre approche, je vous questionnerai peut-être à ce sujet suite aux lecture que vous m'aurez conseillées ! (Mais ne suis pas contre deux trois idées clés dès maintenant)
    Je suis tombé sur les procédés d'héritages de classes, et cherché à adapter une solution à mon problème : je suis parvenu à un résultat fonctionnel. N'hésitez pas à me faire savoir si cela n'est pas "propre" en Python.

    Ci-dessous, le code des trois modules actuellement en place, permettant de visualiser mes trois approches. (J'espère que cela servira à un futur lecteur !)

    Module main
    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
    import tkinter as tk
    from Pages import *
     
     
    class SampleApp(tk.Tk):
        def __init__(self):
            tk.Tk.__init__(self)
            self._frame = None
            self.switch_frame(StartPage)
     
        def switch_frame(self, frame_class):
            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()
     
        def dosomething2(self, frame_name):
            for widget in frame_name.winfo_children():
                if widget.winfo_name()[:3]=="txt":
                    print("Ceci est du texte")
                    print(widget.get())
     
                if widget.winfo_name()[:3] == "num":
                    print("Ceci est un numéro")
     
        def dosomething3(self):
            for widget in self._frame.winfo_children():
                if widget.winfo_name()[:3]=="txt":
                    print("Ceci est du texte")
                    print(widget.get())
     
                if widget.winfo_name()[:3] == "num":
                    print("Ceci est un numéro")
     
     
    if __name__ == "__main__":
        app = SampleApp()
        app.geometry("300x300")
        app.mainloop()
    Module Pages
    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
    import tkinter as tk
    from main import *
    from function import *
     
     
    class StartPage(tk.Frame, dosomething):
        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)
            tk.Button(self, text="Do something",
                      command=lambda: dosomething.dosomething(self)).place(relx=0.1, rely=0.7)
            tk.Entry(self, name="txt_my_entry").place(relx=0.1, rely=0.8)
            tk.Entry(self, name="num_my_entry").place(relx=0.1, rely=0.9)
     
     
    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)
            tk.Button(self, text="Do something",
                      command=lambda: master.dosomething2(self)).place(relx=0.1, rely=0.7)
            tk.Entry(self, name="txt_my_entry").place(relx=0.1, rely=0.9)
     
     
    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.3)
            tk.Button(self, text="Do something",
                      command=lambda: master.dosomething3()).place(relx=0.1, rely=0.5)
            tk.Entry(self, name="txt_my_entry").place(relx=0.1, rely=0.9)
    Module function (même si ce n'est pas le bon nom !)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    import tkinter as tk
     
     
    class dosomething():
        def dosomething(frame_name):
            for widget in frame_name.winfo_children():
                if widget.winfo_name()[:3]=="txt":
                    print("Ceci est du texte")
                    print(widget.get())
     
                if widget.winfo_name()[:3] == "num":
                    print("Ceci est un numéro")
    Bonne soirée,

  6. #6
    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,

    Je suis tombé sur les procédés d'héritages de classes, et cherché à adapter une solution à mon problème : je suis parvenu à un résultat fonctionnel. N'hésitez pas à me faire savoir si cela n'est pas "propre" en Python.
    On peut écrire un code qui fera la même chose sans utiliser des classes et le tout dans un seul module.
    Donc "çà fonctionne" n'est pas un critère pour définir "c'est bien ou c'est mieux": l'organisation d'un code essaie de répondre à des besoins non fonctionnels (testabilité, maintenabilité, extensibilité,...).

    Le besoins "non fonctionnels" dépendent du type de projet: vous n'allez peut être pas écrire un plan de test sans savoir quelles fonctionnalités tester... et vous allez peut être organiser votre code en fonction du comment tester.

    Citation Envoyé par wulfram Voir le message
    Vos propos me font penser que ce n'est peut-être pas une autre approche, je vous questionnerai peut-être à ce sujet suite aux lecture que vous m'aurez conseillées ! (Mais ne suis pas contre deux trois idées clés dès maintenant)
    Il n'y a rien de bon ou de moins bon: c'est vous qui construisez avec l'expérience que vous avez et une appréciation personnelle de ce qui pourra être facile et des détails à travailler parce que à priori difficile.

    Personnellement, si je devais fabriquer une application avec une interface de types "Pages", j'utiliserai un Notebook ou un PanedWindow avec une
    navigation arborescente réalisée avec un Treeview si nécessaire...

    Histoire de pouvoir avoir du temps pour penser au fonctionnel (ce qui fait l'intérêt de l'application) et avoir rapidement un premier prototype qui me donnera du tangible pour apprécier les aspects non fonctionnel à mettre en place si je dois aller plus loin.

    - W

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

Discussions similaires

  1. Récupérer les valeurs des jcheckbox dans un jlabel
    Par nadong dans le forum Composants
    Réponses: 3
    Dernier message: 09/07/2015, 12h30
  2. Récupérer les valeurs des attributs dans un fichier XML ?
    Par chinoismasque dans le forum Windows Phone
    Réponses: 3
    Dernier message: 01/08/2011, 11h15
  3. Réponses: 2
    Dernier message: 03/08/2010, 10h52
  4. [JSTL] Récupérer les valeurs des champs dans un c:forEach
    Par SaladinDev dans le forum Taglibs
    Réponses: 3
    Dernier message: 06/01/2009, 21h56
  5. Réponses: 2
    Dernier message: 11/12/2006, 13h38

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