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

Python Discussion :

Problème POO et Tkinter


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2019
    Messages
    32
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : Mai 2019
    Messages : 32
    Par défaut Problème POO et Tkinter
    Bonjour,

    J'ai une grosse partie de code et dans une partie qui utilise la partie de code ci-dessous. Quand j'exécute le code sans la méthode add_score, tout se passe bien. Quand je l'exécute avec la méthode, y'a une erreur très bizarre qui est relevée et je ne la comprends pas. Je ne vois aucune erreur dans le code pourtant, je ne comprends pas pourquoi ca ne marche pas.


    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
     
    from tkinter import *
    import pickle
    import os
     
    class Window(Tk):
        def __init__(self):
            Tk.__init__(self)
            self.__entry=Entry(self)
            self.__text1=Label(self,text="Entrez votre nom : ")
            self.__text2=Label(self)
            self.__make_zero=Button(self,text="Reinitialiser score",command=self.make_zero)
     
            self.__entry.grid(row=0,column=1)
            self.__text1.grid(row=0,column=0)
            self.__text2.grid(row=1)
            self.__make_zero.grid(row=2)
     
            self.__entry.bind("<Return>", self.give_informations)
     
        def give_informations(self,event):
     
            if os.path.exists("informations"):
                #self.add_score(50)
                with open("informations","rb") as f:
                    mon_depickler=pickle.Unpickler(f)
                    d=mon_depickler.load() 
                if self.__entry.get() in d.keys():
                    self.__text2.configure(text="Votre score est : "+str(d[self.__entry.get()]))
                else:
                    d[self.__entry.get()]=0
                    with open("informations","wb") as f:
                        mon_pickler=pickle.Pickler(f)
                        mon_pickler.dump(d)
                    self.__text2.configure(text="Votre score est : 0")
            else:
                joueur=self.__entry.get()
                with open("informations","wb") as f:
                    mon_pickler=pickle.Pickler(f)
                    mon_pickler.dump({joueur:0})
                self.__text2.configure(text="Votre score est : 0")
     
        def make_zero(self):
            with open("informations","rb") as f:
                mon_depickler=pickle.Unpickler(f)
                d=mon_depickler.load()
            d[self.__entry.get()]=0
            with open("informations","wb") as f:
                mon_pickler=pickle.Pickler(f)
                mon_pickler.dump(d)
            self.__text2.configure(text="Votre score est : 0")
     
        def add_score(self,score):
            with open("informations","rb") as f:
                mon_depickler=pickle.Unpickler(f)
                d=mon_depickler.load()
            s=score+d[self.__entry.get()]
            d[self.__entry.get()]=s
            with open("informations","wb") as f:
                mon_pickler=pickle.Pickler(f)
                mon_pickler.dump(d)
            texte="Votre score est : "+str(s)
            self.__text2.configure(self,text=texte)
     
    if __name__ == "__main__" :
        win= Window()
        win.mainloop()
    Comme ca le code il marche bien, tout est comme voulu. Quand j'enlève le # pour mettre en évidence l'effet de add_score j'ai le problème suivant quand je rentre un nom dans le widget Entry correspondant à self.__entry :

    Exception in Tkinter callback
    Traceback (most recent call last):
    File "c:\users\utilisateur\appdata\local\programs\python\python37-32\lib\tkinter\__init__.py", line 1705, in __call__
    return self.func(*args)
    File "<tmp 1>", line 25, in give_informations
    self.add_score(50)
    File "c:\users\utilisateur\appdata\local\programs\python\python37-32\lib\tkinter\__init__.py", line 2101, in __getattr__
    return getattr(self.tk, attr)
    AttributeError: '_tkinter.tkapp' object has no attribute 'add_score'


    Et ce n'est pas un problème qui vient du fait que le fichier peut être vide puisqu'il contient déjà un dictionnaire avec des noms et des scores.

    J'espère que vous pourrez m'aider à repérer l'erreur. J'y ai réfléchi pendant longtemps et je ne comprends toujours pas pourquoi qu'est-ce qu'il se passe.

    Merci par avance.

  2. #2
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 743
    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 743
    Par défaut
    Salut,

    Si on ne crée pas le fichier, le code plante... et une fois crée, il passe dans add_score mais plante pour d'autres raisons que celle mentionnée. Et si on ne reproduit pas votre problème, impossible de le corriger.

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

  3. #3
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2019
    Messages
    32
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : Mai 2019
    Messages : 32
    Par défaut
    Bonjour,

    Même lorsque le fichier n'existe pas, il le crée et il n'y a pas de problème (je peux faire une capture d'écran si vous voulez). Sinon, c'est bien le message d'erreur que j'ai copié que m'affiche l'IDE Pyzo.
    Là j'ai ré-essayé. Avec à la place d' "informations" un nom : "donnees" (fichier qui n'existe pas au préalable). J'ai l'interface lors de l'exécution du code, je mets Albert comme nom, je clique sur Entrée et j'ai bien le fichier qui est créé. Mais bizarrement, lorsqu'après je rentre un autre nom (Max par exemple) j'ai l'erreur suivante :

    Exception in Tkinter callback
    Traceback (most recent call last):
    File "c:\users\utilisateur\appdata\local\programs\python\python37-32\lib\tkinter\__init__.py", line 1705, in __call__
    return self.func(*args)
    File "<tmp 1>", line 23, in give_data
    self.add_score(50)
    File "<tmp 1>", line 56, in add_score
    s=score+d[self.__entry.get()]
    KeyError: 'Susie'


    J'espère que vous pourrez m'aider à comprendre où se situe l'erreur et qu'est-ce qu'il se passe exactement.

    Merci par avance,

  4. #4
    Membre Expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 910
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 910
    Par défaut
    Salut,

    C'est obliger d'ouvrir le fichier en mode binaire ? Le problème c'est que c'est plus difficile de vérifier le contenu...

    C'est juste une parenthèse...

    Je vais tester le code...

  5. #5
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2019
    Messages
    32
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : Mai 2019
    Messages : 32
    Par défaut
    Bonjour,

    Merci pour votre réponse.

    Je ne sais pas si c'est obliger de lire/ouvrir les fichiers en mode binaire mais c'est comme celà j'ai appris à travailler avec la bibliothèque pickle je pensais que c'était nécessaire pour stocker les objets par exemple des listes ou dictionnaires en tant qu'objet et non pas comme des caractères.

  6. #6
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 743
    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 743
    Par défaut
    Salut,

    Citation Envoyé par ZhaoZhao Voir le message
    Sinon, c'est bien le message d'erreur que j'ai copié que m'affiche l'IDE Pyzo.
    Le mode normal de lancement d'un script Python, c'est lancer une console/terminal puis exécuter le script via $ python script.py.
    Et si on fait çà, votre code plante à la ligne 63 à l'instruction self.__text2.configure(self,text=texte)

    Mais bizarrement, lorsqu'après je rentre un autre nom (Max par exemple) j'ai l'erreur suivante :
    Ben... encore une erreur qu'il faut prendre le temps de reproduire pour la comprendre.
    Ceci dit, lorsque le code que j'écris fait n'importe quoi, j'efface tout et je recommence en essayant de factoriser certaines opérations pour pouvoir les tester avant de les utiliser.

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

  7. #7
    Membre Expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 910
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 910
    Par défaut
    Citation Envoyé par ZhaoZhao Voir le message
    Je ne sais pas si c'est obliger de lire/ouvrir les fichiers en mode binaire mais c'est comme celà j'ai appris à travailler avec la bibliothèque pickle je pensais que c'était nécessaire pour stocker les objets par exemple des listes ou dictionnaires en tant qu'objet et non pas comme des caractères.
    Oui merci, ok je ne connaissais pas pickle et ne connaissant pas pickle je pense que j'aurais stocké les objets dans un fichier json car on peut le lire facilement mais bon il doit y avoir des avantages et des inconvénients dans les deux cas... Quelque chose me dit que cela doit être plus rapide avec pickle et ça a l'air de prendre moins de place...

    En tous cas j'ai découvert pickle et c'est intéressant merci...


    Citation Envoyé par ZhaoZhao Voir le message

    Comme ca le code il marche bien, tout est comme voulu. Quand j'enlève le # pour mettre en évidence l'effet de add_score j'ai le problème suivant quand je rentre un nom dans le widget Entry correspondant à self.__entry :

    Exception in Tkinter callback
    Traceback (most recent call last):
    File "c:\users\utilisateur\appdata\local\programs\python\python37-32\lib\tkinter\__init__.py", line 1705, in __call__
    return self.func(*args)
    File "<tmp 1>", line 25, in give_informations
    self.add_score(50)
    File "c:\users\utilisateur\appdata\local\programs\python\python37-32\lib\tkinter\__init__.py", line 2101, in __getattr__
    return getattr(self.tk, attr)
    AttributeError: '_tkinter.tkapp' object has no attribute 'add_score'
    J'ai essayé plusieurs fois et je n'ai pas eu cette erreur...

    Par contre j'ai bien l'erreur signalée par wiztricks :

    Citation Envoyé par wiztricks Voir le message
    Le mode normal de lancement d'un script Python, c'est lancer une console/terminal puis exécuter le script via $ python script.py.
    Et si on fait çà, votre code plante à la ligne 63 à l'instruction self.__text2.configure(self,text=texte)
    J'ai regardé la méthode configure et je ne vois pas pourquoi vous passez self en paramètre, chez moi il n'y a plus d'erreur quand j'enlève ce paramètre comme ceci : self.__text2.configure(text=texte) et pour que le texte s'affiche j'ai dû ajouter ceci : self.__text2.update()...

    Mais dans ce cas précis, même si on supprime ces deux instructions et celle d'avant (qui actualise texte : texte = "Votre score est : "+str(s)) l'affichage se fait quand même (après l’exécution de self.add_score(50)) à la ligne 9 :

    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
       def give_informations(self, event):
     
            if os.path.exists("informations"):
                self.add_score(50)
                with open("informations", "rb") as f:
                    mon_depickler = pickle.Unpickler(f)
                    d = mon_depickler.load()
                if self.__entry.get() in d.keys():
                    self.__text2.configure(text="Votre score est : "+str(d[self.__entry.get()]))
                    ...
    ...

    Citation Envoyé par ZhaoZhao Voir le message
    Là j'ai ré-essayé. Avec à la place d' "informations" un nom : "donnees" (fichier qui n'existe pas au préalable). J'ai l'interface lors de l'exécution du code, je mets Albert comme nom, je clique sur Entrée et j'ai bien le fichier qui est créé. Mais bizarrement, lorsqu'après je rentre un autre nom (Max par exemple) j'ai l'erreur suivante :

    Exception in Tkinter callback
    Traceback (most recent call last):
    File "c:\users\utilisateur\appdata\local\programs\python\python37-32\lib\tkinter\__init__.py", line 1705, in __call__
    return self.func(*args)
    File "<tmp 1>", line 23, in give_data
    self.add_score(50)
    File "<tmp 1>", line 56, in add_score
    s=score+d[self.__entry.get()]
    KeyError: 'Susie'
    Oui c'est normal, regardez votre fonction add_score :

    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
      def add_score(self, score):
            with open("informations", "rb") as f:
                mon_depickler = pickle.Unpickler(f)
                d = mon_depickler.load()
            s = score+d[self.__entry.get()]

    Si vous entrez un nom déjà enregistré tout va bien mais si vous entrez un nouveau nom alors il n'est pas enregistré au moment où la fonction add_score est exécutée, c'est-à-dire il n'est pas dans le dictionnaire d donc quand on a ceci d[self.__entry.get()] à la ligne 5 (s = score+d[self.__entry.get()]) on essai de lire une propriété du dico qui n'existe pas d'où l'erreur KeyError signalée ...

  8. #8
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 743
    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 743
    Par défaut
    Salut,

    Si on veut faire un peu de POO, on part d'un "score" qui est un simple dictionnaire.

    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
    from tkinter import *
    import pickle
    import os
     
    class Widget(Frame):
        def __init__(self, master, scores):
            super().__init__(master)
            self.scores = scores
     
            self.entry = Entry(self)
            self.text1 = Label(self, text="Entrez votre nom : ")
            self.text2 = Label(self)
            self.zero_btn = Button(self, text='reinitialiser score', command=self.zero_score)
            self.entry.grid(row=0, column=1)
            self.text1.grid(row=0, column=0)
            self.text2.grid(row=1, columnspan=2)
            self.zero_btn.grid(row=2, columnspan=2)
     
            self.entry.bind('<Return>', self.display_score)
     
     
        def show_score(self, name):
            score = self.scores[name]
            self.text2['text'] = f'Votre score est {score}'
     
     
     
        def display_score(self, *e):
            name = self.entry.get()
            if name not in self.scores:
                self.scores[name] = 0
            self.scores[name] += 50
            self.show_score(name)
     
        def zero_score(self):
            name = self.entry.get()
            self.scores[name] = 0
            self.show_score(name)
     
     
     
    if __name__ == '__main__':
        root = Tk()
        scores = {}
        w = Widget(root, scores)
        w.pack()
        mainloop()
    Puis on améliore le dictionnaire pour lui ajouter de la persistence:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class Score(dict):
        def __init__(self, path):
            super().__init__()
            self.path = path
            if os.path.exists(self.path):
                with open(self.path, 'rb') as f:
                    self.update(pickle.Unpickler(f).load())
     
        def __setitem__(self, name, value):
            oldv = self.get(name, None)
            super().__setitem__(name, value)
            if oldv and oldv != value:
                with open(self.path, 'wb') as f:
                     pickle.Pickler(f).dump(self)
    Et en plus de l'ajout de ce code, la seule ligne qui va changer dans le code précédent sera la ligne 44: scores = {} qui devient scores = Score('scores.dat').
    Et là on a fait un peu de POO i.e. remplacer un dictionnaire "standard" par un dictionnaire un peu plus intelligent sans trop changer le code qui l'utilise.

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

Discussions similaires

  1. Problème POO utilisation des package
    Par Christophe53 dans le forum Langage
    Réponses: 12
    Dernier message: 10/03/2011, 16h19
  2. Problème affichage image Tkinter
    Par passant dans le forum Tkinter
    Réponses: 5
    Dernier message: 14/10/2010, 21h37
  3. Problème de fenêtres Tkinter
    Par nicogigo dans le forum Tkinter
    Réponses: 2
    Dernier message: 04/04/2010, 04h39
  4. [PHP 5.3] Problème POO avec class Stylo {
    Par éric1 dans le forum Langage
    Réponses: 2
    Dernier message: 27/07/2009, 18h42
  5. Problème POO C++ et SDL
    Par Marneus dans le forum SDL
    Réponses: 9
    Dernier message: 10/10/2006, 07h01

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