Bienvenue sur IndexError.

Ici vous pouvez poser des questions sur Python et le Framework Django.

Mais aussi sur les technos front comme React, Angular, Typescript et Javascript en général.

Consultez la FAQ pour améliorer vos chances d'avoir des réponses à vos questions.

Comment supprimer un tag via l'instance d'une classe donnée?

+1 vote

voici mon code source réédité pour mieux expliquer mon problème:

En fait, l'idée c'est de tracer ou d'effacer une ligne de manière dynamique dans le canevas via l'objet " Bouton".

Dans le premier morceau de code j'instancie un objet (w) dans l'espace de noms principal avec une ligne rouge qui est associée à un tag à sa création.
Ensuite j'ai deux fonctions (cR et delete). La première est appelée lorsqu'on appuie sur le bouton " red"; elle vérifie si la ligne tracée a un tag. Si oui, elle envoie le tag à la fonction "delete" qui efface la ligne. Appuyer une seconde fois sur le bouton permet de tracer une nouvelle ligne, jaune cette fois (parce qu'à priori il n'y a plus de ligne donc plus de tag à effacer).
Là ça marche très bien.

from tkinter import *

def cR():
     if w.find_withtag('one'):
        delete('one')
     else:
         w.create_line(10, 40, 60, 40, fill='yellow', tags='one')

def delete(tag):
    w.delete(w.find_withtag(tag))

root = Tk()
w = Canvas(root, width=200, height=100)
w.pack()
w.create_line(10, 40, 60, 40, fill='red', tags='one')
b= Button(root, text="red", command=cR)
b.pack()
root.mainloop()

Dans le second morceau de code, j'essaie de refaire la même chose, cette fois en tirant partie de la puissance de la POO. Je crée donc ma classe ligne qui hérite de Tk, les différents constructeurs et attributs, puis deux fonctions (tracer et delete).

Quand j'exécute ce code, une ligne rouge apparaît bien dans le canevas, mais quand j'appuie sur le bouton je reçois l'erreur suivante : NameError: name 'find_withtag' is not defined...

class Ligne(Tk):
   # je crée une classe fille (Ligne) qui dérive de la classe des fenêtres Tk du module Tkinter

    def __init__(self, larg, haut):
        Tk.__init__(self)
        self.can =Canvas(self, width = larg, height = haut, bg ="white")
          self.can.pack(side =TOP, padx =5, pady =5)
        Button(self, text ='Bouton', command =self.tracer).pack(side =LEFT, padx =5, pady =5)
          self.can.create_line(10, 40, 60, 40, fill='red', tags='one')
       # par défaut une ligne rouge apparaît dans le canevas

    def tracer(self):
        if find_withtag('one'):
            # l'instruction find_withtag est sensée vérifier si l'objet Tkinter (la ligne rouge ci-dessus) contient un tag. si oui, elle envoie le tag à la fonction delete, qui supprime le tag et par la même occasion la ligne
              delete('one')
        else:
              self.can.create_line(10, 40, 60, 40, fill='yellow', tags='one')

    def delete(self, tag):
         self.delete(self.find_withtag(tag))

w = Ligne(200, 100)
w.mainloop()

Alors je me demande bien ce qui cloche dans le code.
Avec l'espoir d'avoir exposé plus clairement mon problème.

EDIT 1 :

je viens de retravailler le code, le voici:

from tkinter import*

"""
def cR():
    if w.findwithtag('one'):
        delete('one')
    else:
        w.createline(10, 40, 60, 40, fill='yellow', tags='one')

def delete(tag):
    w.delete(w.find_withtag(tag))

root = Tk()
w = Canvas(root, width=200, height=100)
w.pack()
w.create_line(10, 40, 60, 40, fill='red', tags='one')
b= Button(root, text="red", command=cR)
b.pack()

root.mainloop()

"""

class Ligne(Tk): # je crée une classe fille (Ligne) qui dérive de la classe des fenêtres Tk du module Tkinter 
    def init(self, larg, haut): # son constructeur
        Tk.init(self) # j'appelle le constructeur de la classe parente
        self.can =Canvas(self, width = larg, height = haut, bg ="white") # je crée mon canevas avec les dimensions renseignées en paramètre lors de l'instanciation de l'objet w 
        self.can.pack(side =TOP, padx =5, pady =5)
        Button(self, text ='Bouton', command =self.tracer).pack(side =LEFT, padx =5, pady =5) # je crée un bouton 'Bouton'
        self.can.create_line(10, 40, 60, 40, fill='red', tags='one') # par défaut une ligne rouge apparaît dans le canevas

    def tracer(self): # ça c'est ma fonction tracer qui est appellée quand on appuie sur le 'Bouton'
        if self.can.findwithtag('one'): # cette instruction est sensée vérifier si l'objet Tkinter (la ligne rouge ci-dessus) contient un tag 
            self.delete('one') # si oui, elle envoie le tag à la fonction delete, qui supprime le tag et par la même occasion la ligne
        else:
            self.can.createline(10, 40, 60, 40, fill='yellow', tags='one') # si aucun tag n'est trouvé, cela suppose qu'aucune ligne n'est présente dans le canevas
    # par conséquent, on crée une nouvelle ligne (jaune), elle aussi taggée

    def delete(self, tag):
        self.can.delete(self.can.find_withtag(tag)) # la fonction delete reçoit un tag et le supprime.

w = Ligne(200, 100) # j'instancie un objet (w) de la classe Ligne, avec en paramètre: la largeur et la hauteur du canevas
w.mainloop()

En fait, l'idée c'est de tracer ou d'effacer une ligne de manière dynamique dans le canevas via l'objet " Bouton".
Dans le premier morceau de code entre """ """, j'instancie un objet (w) dans l'espace de noms principal avec une ligne rouge qui est associée à un tag à sa création. Ensuite j'ai deux fonctions (cR et delete). La première est appelée lorsqu'on appuie sur le bouton " red"; elle vérifie si la ligne tracée a un tag. Si oui, elle envoie le tag à la fonction "delete" qui efface la ligne. Appuyer une seconde fois sur le bouton permet de tracer une nouvelle ligne, jaune cette fois (parce qu'à priori il n'y a plus de ligne donc plus de tag à effacer). Là ça marche très bien.

Dans le second morceau de code, j'essaie de refaire la même chose, cette fois en tirant partie de la puissance de la POO. Je crée donc ma classe ligne qui hérite de Tk, les différents constructeurs et attributs, puis deux fonctions (tracer et delete).
Quand j'exécute ce code, une ligne rouge apparaît dans le canevas, mais quand j'appuie sur le bouton je reçois l'erreur suivante : NameError: name 'find_withtag' is not defined...

Alors je me demande bien ce qui cloche dans le code.
Avec l'espoir d'avoir exposé plus clairement mon problème.

demandé 21-Oct-2016 par Tobin (122 points)
edité 9-Nov-2016 par Tobin

pas sûr de l'indentation mais c'était illisible

En quoi ça ne marche pas? ça affiche quoi ? ya t il un code d'erreur ? "Ne marche pas" c'est vraiment pas très clair =/ ...

Et c'est quoi la bonne indentation ??

J'ai fixé l'indentation, au plus probable. Mais il manque toujours une explication de ce qui marche pas, et de ce qu'est censée faire la fonction delete.

Je note également que la méthode Ligne.delete est récursive. L'erreur levée est probablement en rapport avec une récursion infinie. J'imagine que dans le corps de la méthode, c'est delete et non self.delete qu'il faut appeler.

Si tu cherche à clarifier ta question, il vaudrait mieux éditer ta question plutôt qu'ajouter une réponse au problème. Fait également attention à l'indentation du code, ce qui donne dans l'éditeur:

bla bla bla mon code:

    # ceci est considéré comme du code
    # ne pas oublier d'ajouter quatre espace d'indentation

bla bla bla

Note bien la présence de deux lignes vides avant et après.

Regarde les autres questions, pour voir comment l'interface devrait être utilisée.

Peut-on avoir toute l'erreur, avec la stack trace ?

voici l'erreur quand j'exécute le code avec le self (if self.find_withtag...)

Exception in Tkinter callback
Traceback (most recent call last):
    File "C:\Python34\lib\tkinter\__init__.py", line 1533, in __call__
    return self.func(*args)
    File "D:\Mes Projets\Projets\MES PROJETS PYTHON\CLASSES, OBJETS,       ATTRIBUTS\tag_ess.py", line 32, in tracer
    if self.find_withtag('one'): # cette instruction est sensée vérifier si l'objet Tkinter (la ligne rouge ci-dessus) contient un tag
    File "C:\Python34\lib\tkinter\__init__.py", line 1932, in __getattr__
    return getattr(self.tk, attr)
AttributeError: 'tkapp' object has no attribute 'find_withtag'

voici à présent l'erreur quand je l'exécute sans le self

Exception in Tkinter callback                                                   
Traceback (most recent call last):
   File "C:\Python34\lib\tkinter\__init__.py", line 1533, in __call__  
       return self.func(*args)
   File "D:\Mes Projets\Projets\MES PROJETS PYTHON\CLASSES, OBJETS, ATTRIBUTS\tag_ess.py", line 32, in tracer       
     if find_withtag('one'): # cette instruction est sensée vérifier si l'objet Tkinter (la ligne rouge ci-dessus) contient un tag       
     NameError: name 'find_withtag' is not defined     

1 Réponse

+2 votes

Je suis à peu près sûr que l'erreur NameError: name 'find_withtag' is not defined viens de la première ligne de la méthode tracer :

 if findwithtag('one'):

Qui devrait être probablement :

 if self.findwithtag('one'):
répondu 25-Oct-2016 par lucas (2,206 points)
...