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 :

Problème d'organisation du code qui soulève une "AttributeError".


Sujet :

Tkinter Python

  1. #1
    Nouveau Candidat au Club
    Femme Profil pro
    Etudiante
    Inscrit en
    octobre 2022
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Territoire de Belfort (Franche Comté)

    Informations professionnelles :
    Activité : Etudiante

    Informations forums :
    Inscription : octobre 2022
    Messages : 4
    Points : 1
    Points
    1
    Par défaut Problème d'organisation du code qui soulève une "AttributeError".
    Bonjour à tous.

    J'écris sur ce forum car je ne parviens pas à trouver une organisation de code satisfaisante pour un programme, qui me permette de ne pas soulever d'AttributeError.

    Il s'agit d'une application qui possède deux frame, l'une dévouée à la connexion, l'autre au cœur de l'application, chacune étant définie par une classe. Le problème est que j'ai besoin d'accéder aux attributs de la première classe lorsque je manipule la deuxième pour pouvoir configurer l'application selon les souhaits de l'utilisateur. Or comme la première classe n'est pas encore instanciée lorsque je définie la seconde, l'interpréteur me renvoie une erreur du type "AttributeError: type object 'XXX' has no attribute 'XXX'".

    Je sais qu'une solution pourrait être d'instancier la classe mais la façon dont j'ai construit le code ne me le permet pas : je crée les deux frames l'une sur l'autre en même temps après les avoir définies et je navigue dans les deux avec la fonction tkraise() pour afficher celle que je souhaite.

    Voici le canevas du code qui pose problème :

    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
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    class App(ttk.Frame):
        def __init__(self, parent):
            ttk.Frame.__init__(self)
    
            # le container contient les frames
            container = tk.Frame(self)
            container.pack(side="top", fill="both", expand=True)
            container.grid_rowconfigure(0, weight=1)
            container.grid_columnconfigure(0, weight=1)
    
            self.frames = {}
    
            for F in (LoginPage, MainPage):
                page_name = F.__name__
                frame = F(parent=container, controller=self)
                self.frames[page_name] = frame
    
                frame.grid(row=0, column=0, sticky="nsew")
           #J'affiche la première frame.
            self.show_frame("LoginPage")
            print(self.frames['LoginPage'].var_activity.get())
    
        def show_frame(self, page_name):
            frame = self.frames[page_name]
            frame.tkraise()
    
    class LoginPage(tk.Frame):
    
        def __init__(self, parent, controller):
            tk.Frame.__init__(self, parent)
            self.controller = controller
     
             .
             .
             .
    
    
            # Create control variables
     
             .
             .
             .
            self.var_activity = tk.StringVar() #L'attribut en question est défini ici.
            
    
            # Create widgets
            self.setup_widgets()
     
            .
            .
            .
    
        def setup_widgets(self):
            .
            .
            .
    
            # Create a Frame for input widgets
            self.widgets_frame = ttk.Frame(self, padding=(0, 0, 0, 10))
            self.widgets_frame.grid(row=0, column=1, padx=10, pady=(30, 10), sticky="nsew", rowspan=3)
            self.widgets_frame.columnconfigure(index=0, weight=1)
    
            # Read-only combobox
            self.readonly_combo = ttk.Combobox(self.widgets_frame, state="readonly", textvariable=self.var_activity, values=self.readonly_combo_list)
            self.readonly_combo.current(0)
            self.readonly_combo.grid(row=3, column=0, padx=5, pady=10, sticky="ew")
            
     
             .
             .
             .
    
    
    
    class MainPage(tk.Frame):
        def __init__(self, parent, controller):
            tk.Frame.__init__(self, parent)
            self.controller = controller
     
            .
            .
            .
       
            # Create widgets
            self.setup_widgets()
            
        def setup_widgets(self):
    
            # Create a Frame for input widgets
            self.widgets_frame = ttk.Frame(self, padding=(0, 0, 0, 10))
            self.widgets_frame.grid(row=0, column=1, padx=10, pady=(30, 10), sticky="nsew", rowspan=3)
            self.widgets_frame.columnconfigure(index=0, weight=1)
            
    
            #Le problème est ici, je souhaite récupérer l'attribut "var_activity" de LoginPage.
            # Accentbutton
            self.accentbutton1 = ttk.Button(self.widgets_frame, text=LoginPage.var_activity.get(), style="Accent.TButton", command=lambda : self.startPause())
            self.accentbutton1.grid(row=7, column=1, padx=5, pady=10, sticky="nsew")
            
         
    
    if __name__ == "__main__":
        root = tk.Tk()
     
        .
        .
        .
    
        app = App(root)
        app.pack(fill="both", expand=True)
     
        .
        .
        .
        root.mainloop()
    J'obtiens donc l'erreur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    AttributeError: type object 'LoginPage' has no attribute 'var_activity'
    Sauriez-vous comment je peux accéder à cet attribut ?

    Je vous remercie de votre aide et vous souhaite une excellente journée.

    Cordialement,

    Jessie.

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    juin 2008
    Messages
    19 924
    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 : 19 924
    Points : 34 473
    Points
    34 473
    Par défaut
    Salut,

    Citation Envoyé par JessieJ Voir le message
    Sauriez-vous comment je peux accéder à cet attribut ?
    On ne peut pas accéder à un attribut qui n'existe pas encore...
    Reste à changer l'organisation du code ou revoir vos ambitions à la baisse.

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

  3. #3
    Nouveau Candidat au Club
    Femme Profil pro
    Etudiante
    Inscrit en
    octobre 2022
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Territoire de Belfort (Franche Comté)

    Informations professionnelles :
    Activité : Etudiante

    Informations forums :
    Inscription : octobre 2022
    Messages : 4
    Points : 1
    Points
    1
    Par défaut
    Je vous remercie de votre réponse.

    Je veux réorganiser mon code, mais je ne sais justement pas quelle manière serait la plus adaptée. L'application que je cherche à concevoir n'est pas bien compliquée, elle est donc, je pense, faisable avec Tkinter. Ma question est donc de savoir s'il existe une alternative simple qui me permette de garder la majeure partie de mon code ; une variable globale qui prend la valeur de l'attribut de la classe LoginPage pourrait-elle marcher ?

    Je suis un peu troublée car cet emploi des attributs doit être très courant dans la conception d'applications, quelque soit le langage de programmation... Si ce que j'ai fait est sans issue, comment font alors les professionnels ?

  4. #4
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    juin 2008
    Messages
    19 924
    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 : 19 924
    Points : 34 473
    Points
    34 473
    Par défaut
    Citation Envoyé par JessieJ Voir le message
    Si ce que j'ai fait est sans issue, comment font alors les professionnels ?
    Un professionnel s'engagera à livrer un programme qui fonctionne dans un délai et un coût fixé à l'avance.
    S'il ne veut pas y être de sa poche, il ne va pas utiliser des constructions qu'il ne connaît pas mais s'inspirer de codes qu'il a déjà fait.

    Bien sur ce sera une nouvelle application et aura des fonctionnalités spécifiques mais si on doit la coder en utilisant tkinter et Python, il faudra bien reformuler ce qu'on cherche à faire "avec" ces outils et l'organisation adaptés à ce qu'ils sont (et ce qu'on en connaît).

    Citation Envoyé par JessieJ Voir le message
    Ma question est donc de savoir s'il existe une alternative simple qui me permette de garder la majeure partie de mon code ; une variable globale qui prend la valeur de l'attribut de la classe LoginPage pourrait-elle marcher ?
    Si vous ne maîtrisez pas la POO qu'est ce qui vous oblige (techniquement) à utiliser des "class"?

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

  5. #5
    Nouveau Candidat au Club
    Femme Profil pro
    Etudiante
    Inscrit en
    octobre 2022
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Territoire de Belfort (Franche Comté)

    Informations professionnelles :
    Activité : Etudiante

    Informations forums :
    Inscription : octobre 2022
    Messages : 4
    Points : 1
    Points
    1
    Par défaut
    Citation Envoyé par wiztricks
    il faudra bien reformuler ce qu'on cherche à faire "avec" ces outils et l'organisation adaptés à ce qu'ils sont (et ce qu'on en connaît).
    Mon problème est bien là : je sais que c'est techniquement possible, et j'en ai besoin car faire l'application sans considérer le coté POO de Python serait un non-sens complet et peut-être même bien trop difficile si l'on souhaite implémenter des fonctionnalités complexes.

    Citation Envoyé par wiztricks
    Si vous ne maîtrisez pas la POO qu'est ce qui vous oblige (techniquement) à utiliser des "class"?
    Si je viens sur ce forum, c'est précisément dans l'attente que quelqu'un m'aiguille sur une fonctionnalité ou une méthode que je ne connaitrais pas et que je n'ai pas trouvée de moi-même. Répondre "autant tout abandonner" ou un équivalent ne me fera jamais progresser.

    Citation Envoyé par JessieJ
    une variable globale qui prend la valeur de l'attribut de la classe LoginPage pourrait-elle marcher ?
    Vous ne m'avez pas répondu sur ce point. Quand je demande comment font les professionnels, j'entends savoir comment techniquement ils construisent une application complexe avec Tkinter, comment ils gèrent les différentes frames, dans quel ordre ils instancient les choses, comment ils se débrouillent pour que les différentes "class" communiquent entre elles afin de former des modules graphiques de Tkinter élaborés — d'ailleurs, est-il préférable de définir une "class" pour toute l'application ? pour une frame ? pour un élément graphique ?

    Ce sont ce genre de détails techniques qui vont me permettre de résoudre mon problème qui est lié spécifiquement à la POO dans le cadre d'une GUI. Je ne vous demande pas de m'éclairer sur toutes ces interrogations, mais mon problème d'attribut doit avoir une solution simple dans le cadre de la POO.

    Je vous remercie à nouveau et vous prie de bien vouloir excuser mon insistance concernant mon affaire.

    Cordialement,

    Jessie

  6. #6
    Membre éprouvé
    Avatar de Hominidé
    Homme Profil pro
    Paysan à 3 francs six sous
    Inscrit en
    juin 2018
    Messages
    743
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Paysan à 3 francs six sous
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : juin 2018
    Messages : 743
    Points : 1 282
    Points
    1 282
    Billets dans le blog
    3
    Par défaut
    Bonjour,
    Tu ne peux pas accéder à un attribut défini dans l'__init__() sans instancier ta classe (sans cela la méthode ne sera pas appelée, donc attribut inexistant)
    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
    >>> class bid():
    	attr = 'yes'
    	def __init__():
    		truc = 'yop'
     
     
    >>> bid.truc
    Traceback (most recent call last):
      File "/usr/lib/python3.8/idlelib/run.py", line 559, in runcode
        exec(code, self.locals)
      File "<pyshell#40>", line 1, in <module>
    AttributeError: type object 'bid' has no attribute 'truc'
    >>> bid.attr
    'yes'
    >>>
    Tu dois revoir la conception de ton prog:
    Avec deux classes qui héritent de tkinter.Frame, on crée deux objets tkinter distincts que l'on peut placer comme le widget frame dans un code tkinter.
    C'est ce code qui instanciera les deux classes et c'est lui qui gérera l'ensemble.
    à première vue, c'est ainsi que je procéderai ...
    pathlib, poetry, importlib_ressources...

  7. #7
    Nouveau Candidat au Club
    Femme Profil pro
    Etudiante
    Inscrit en
    octobre 2022
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Territoire de Belfort (Franche Comté)

    Informations professionnelles :
    Activité : Etudiante

    Informations forums :
    Inscription : octobre 2022
    Messages : 4
    Points : 1
    Points
    1
    Par défaut
    Merci beaucoup Hominidé, je vais essayer de faire comme cela !

  8. #8
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    juin 2008
    Messages
    19 924
    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 : 19 924
    Points : 34 473
    Points
    34 473
    Par défaut
    Citation Envoyé par JessieJ Voir le message
    comment ils se débrouillent pour que les différentes "class" communiquent entre elles afin de former des modules graphiques de Tkinter élaborés — d'ailleurs, est-il préférable de définir une "class" pour toute l'application ? pour une frame ? pour un élément graphique ?
    Il n'y a pas de solution générale: que des cas particuliers... et c'est le programmeur qui choisira que faire et qui saura le justifier (un autre pourra faire d'autres choix et avoir de très bonnes raisons pour ça).

    Vous avez récupéré un code qui traîne un peu partout... qui a été (et reste) l'objet de multiple discussions: les débutants adorent récupérer un code qui marche oubliant que sans un niveau comparable à celui qui l'a codé, difficile d'en faire quelque chose.

    Un gars s'est amusé à en recenser un certain nombre sur SOW dans cette discussion.
    Vous y trouverez des solutions adaptées (à ce cas particulier) côté partage de données entre "classes".

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

Discussions similaires

  1. Réponses: 2
    Dernier message: 16/01/2012, 10h28
  2. Connaître le code qui appelle une procédure
    Par The Jos dans le forum Langage
    Réponses: 4
    Dernier message: 13/08/2010, 12h08
  3. [XL-2003] comment ecrire un code qui parcours une colonne?
    Par doudou8mc dans le forum Macros et VBA Excel
    Réponses: 6
    Dernier message: 08/07/2009, 17h21
  4. Compréhention pour faire marcher un code qui génere une torche
    Par malicia_bm dans le forum ActionScript 3
    Réponses: 7
    Dernier message: 12/11/2008, 17h02

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