Seite 1 von 1

invalid command name Error

Verfasst: Montag 27. Juli 2020, 09:10
von Fire Spike
Hallo ich habe mir ein kleines Tabellen Widget geschrieben.
In das habe ich auch eine kleine Funktion implementiert die eine Zeile löscht, wenn man darauf doppelklickt.
Leider kommt immer die Meldung das diese Tabelle nicht existiert...
Ich habe unten einen Beispiel Code, könnt ihr mir helfen?

Code: Alles auswählen

import tkinter as tk
from tkinter import ttk

class Table(ttk.Treeview):
    def __init__(self, master, data):
        super().__init__(master)
        yscrollbar = ttk.Scrollbar(master, orient="vertical", command=self.yview)
        yscrollbar.grid(row=0, column=2, sticky="NS")
        self.configure(yscrollcommand=yscrollbar.set)
        self.headers = data[0]
        self.sizes = [int(size) for size in data[1]]
        data = data[2:]
        column_names = tuple([str(number) for number in range(len(self.headers))])
        self["columns"] = column_names
        self["show"] = "headings"
        for header, size, name in zip(self.headers, self.sizes, column_names):
            self.column(name, width=int(size), minwidth=int(size), anchor="w")
            self.heading(name, text=header, anchor="w")

        for i, column in enumerate(data):
            self.insert("", i, text="", values=tuple(column))

        self.bind("<Double-1>", self.on_double_click)

    def insert_column(self, entries):
        data = [entry.get() for entry in entries]
        self.insert("", randrange(1000, 10000000), text="", values=tuple(data))
                    
    def get_data(self):
        data = []
        data.append(self.headers)
        data.append(self.sizes)
        for child in self.get_children():
            data.append(self.item(child)["values"])

        return data
    
    def on_double_click(self, event):
        region = self.identify("region", event.x, event.y)
        if region == "heading":
            pass

        else:
            warning = Warning(title="Bestätigung", message=self.item(event.widget.focus())['values'])
            if warning.value:
                self.delete(event.widget.focus())

class Warning:
    def __init__(self, title, message):
        self.value = None
        self.root = tk.Tk()
        self.root.resizable(False, False)
        self.root.title(title)
        self.root.config(bg="white")
        tk.Label(self.root, text="willst du die folgenden Werte wirklich löschen?", bg="white", fg="red").pack()
        tk.Label(self.root, text=message, bg="white").pack()
        tk.Button(self.root, text="Ja", bg="orange", command=self.yes).pack()
        tk.Button(self.root, text="Nein", bg="white", command=self.no).pack()
        self.root.mainloop()
        
    def yes(self):
        self.value = True
        self.root.destroy()
        
    def no(self):
        self.value = False
        self.root.destroy()
        
def main():
    root = tk.Tk()
    table = Table(root, [["Äpfel", "Bananen", "Orangen"], ["60", "60", "60"], ["12", "7", "16"]])
    table.grid(row=0, column=1)
    
if __name__ == "__main__":
    main()
Fehler:

Code: Alles auswählen

Exception in Tkinter callback
Traceback (most recent call last):
  File "/usr/lib/python3.7/tkinter/__init__.py", line 1705, in __call__
    return self.func(*args)
  File "beispiel.py", line 46, in on_double_click
    self.delete(event.widget.focus())
  File "/usr/lib/python3.7/tkinter/ttk.py", line 1273, in focus
    return self.tk.call(self._w, "focus", item)
_tkinter.TclError: invalid command name ".!table"
invalid command name ".!table"
    while executing
"$w identify row $x $y"
    (procedure "ttk::treeview::DoubleClick" line 2)
    invoked from within
"ttk::treeview::DoubleClick .!table 52 36 "
    (command bound to event)

Re: invalid command name Error

Verfasst: Montag 27. Juli 2020, 09:14
von Sirius3
Es darf nur ein Exemplar von Tk geben und auch nur einen Aufruf von mainloop, wobei dieser Aufruf in `main` fehlt.
Warning will also statt dessen einen modalen Dialog erzeugen, für Ja/Nein-Abfragen hat Tkinter schon etwas fertiges; das ist auch keine sinnvolle Klasse und wäre besser eine einfache Funktion.

Re: invalid command name Error

Verfasst: Montag 27. Juli 2020, 09:27
von Fire Spike
Sirius3 hat geschrieben: Montag 27. Juli 2020, 09:14 Es darf nur ein Exemplar von Tk geben und auch nur einen Aufruf von mainloop, wobei dieser Aufruf in `main` fehlt.
Das zweite Tk wurde zu Toplevel und mainloop ist jetzt auch da :lol: .
Der Fehler bleibt aber der gleiche...
Und wie würdest denn du eine sinnvolle Warning schreiben?-

Re: invalid command name Error

Verfasst: Montag 27. Juli 2020, 09:45
von Sirius3
Naja, schön wäre es gewesen, wenn Du den korrigierten Code auch noch gezeigt hättest.
Nachdem ich die Warning-Klasse durch einen Aufruf von tkinter.messagebox.askyesno ersetzt hatte, funktionierte es bei mir ohne Fehler.

Re: invalid command name Error

Verfasst: Montag 27. Juli 2020, 09:58
von Fire Spike
Wieso geht denn meine nicht?

Re: invalid command name Error

Verfasst: Montag 27. Juli 2020, 10:54
von Sirius3
Das kann niemand sagen, weil es gerade eine globale Kristallkugel-Störung gibt.

Re: invalid command name Error

Verfasst: Montag 27. Juli 2020, 13:32
von Fire Spike

Code: Alles auswählen

import tkinter as tk
from tkinter import ttk, messagebox

class Table(ttk.Treeview):
    def __init__(self, master, data):
        super().__init__(master)
        yscrollbar = ttk.Scrollbar(master, orient="vertical", command=self.yview)
        yscrollbar.grid(row=0, column=2, sticky="NS")
        self.configure(yscrollcommand=yscrollbar.set)
        self.headers = data[0]
        self.sizes = [int(size) for size in data[1]]
        data = data[2:]
        column_names = tuple([str(number) for number in range(len(self.headers))])
        self["columns"] = column_names
        self["show"] = "headings"
        for header, size, name in zip(self.headers, self.sizes, column_names):
            self.column(name, width=int(size), minwidth=int(size), anchor="w")
            self.heading(name, text=header, anchor="w")

        for i, column in enumerate(data):
            self.insert("", i, text="", values=tuple(column))

        self.bind("<Double-1>", self.on_double_click)

    def insert_column(self, entries):
        data = [entry.get() for entry in entries]
        self.insert("", randrange(1000, 10000000), text="", values=tuple(data))
                    
    def get_data(self):
        data = []
        data.append(self.headers)
        data.append(self.sizes)
        for child in self.get_children():
            data.append(self.item(child)["values"])

        return data
    
    def on_double_click(self, event):
        region = self.identify("region", event.x, event.y)
        if region == "heading":
            pass

        else:
            warning = Warning(title="Bestätigung", message=self.item(event.widget.focus())['values'])
            if warning.value:
                self.delete(event.widget.focus())

class Warning:
    def __init__(self, title, message):
        self.value = None
        self.root = tk.Toplevel()
        self.root.resizable(False, False)
        self.root.title(title)
        self.root.config(bg="white")
        tk.Label(self.root, text="willst du die folgenden Werte wirklich löschen?", bg="white", fg="red").pack()
        tk.Label(self.root, text=message, bg="white").pack()
        tk.Button(self.root, text="Ja", bg="orange", command=self.yes).pack()
        tk.Button(self.root, text="Nein", bg="white", command=self.no).pack()
        self.root.mainloop()
        
    def yes(self):
        self.value = True
        self.root.destroy()
        
    def no(self):
        self.value = False
        self.root.destroy()
        
def main():
    root = tk.Tk()
    table = Table(root, [["Äpfel", "Bananen", "Orangen"], ["60", "60", "60"], ["12", "7", "16"]])
    table.grid(row=0, column=1)
    root.mainloop()
    
if __name__ == "__main__":
    main()

Re: invalid command name Error

Verfasst: Dienstag 28. Juli 2020, 06:37
von __blackjack__
@Fire Spike: Es darf immer noch nur einen Aufruf von `mainloop()` geben. Der zweite ist erst zuende wenn das Hauptfenster geschlossen wird. *Dann* wird versucht das `delete()` auszuführen, was natürlich nicht mehr geht, weil das Hauptfenster, und damit auch die Tabelle weg ist. Und das führt dann zu der Ausnahme die Du siehst.

Re: invalid command name Error

Verfasst: Dienstag 28. Juli 2020, 13:32
von Fire Spike
Was sollte ich sonst machen?
Ohne mainloop ist warning.value ja immer None, da es nicht auf das Fenster wartet...

Re: invalid command name Error

Verfasst: Dienstag 28. Juli 2020, 13:56
von Sirius3
Daher habe ich ja schon ganz zu Anfang geschrieben, dass Du einen Dialog verwenden mußt.

Re: invalid command name Error

Verfasst: Dienstag 28. Juli 2020, 19:12
von Fire Spike
Da habe ich Style Probleme weil ich ttk.Style verwende :oops:

Re: invalid command name Error

Verfasst: Mittwoch 29. Juli 2020, 07:15
von Sirius3
Dann mußt Du die Style-Probleme lösen.

Re: invalid command name Error

Verfasst: Mittwoch 29. Juli 2020, 14:11
von peterpy
Hallo Fire Spike,
mit deiner Abfrage:

Code: Alles auswählen

import tkinter as tk
from tkinter import ttk

class Table(ttk.Treeview):
    def __init__(self, master, data):
        super().__init__(master)
        yscrollbar = ttk.Scrollbar(master, orient="vertical", command=self.yview)
        yscrollbar.grid(row=0, column=2, sticky="NS")
        self.configure(yscrollcommand=yscrollbar.set)
        self.headers = data[0]
        self.sizes = [int(size) for size in data[1]]
        data = data[2:]
        column_names = tuple([str(number) for number in range(len(self.headers))])
        self["columns"] = column_names
        self["show"] = "headings"
        for header, size, name in zip(self.headers, self.sizes, column_names):
            self.column(name, width=int(size), minwidth=int(size), anchor="w")
            self.heading(name, text=header, anchor="w")
        for i, column in enumerate(data):
            self.insert("", i, text="", values=tuple(column))
        self.bind("<Double-1>", self.on_double_click)

    def insert_column(self, entries):
        data = [entry.get() for entry in entries]
        self.insert("", randrange(1000, 10000000), text="", values=tuple(data))
                    
    def get_data(self):
        data = []
        data.append(self.headers)
        data.append(self.sizes)
        for child in self.get_children():
            data.append(self.item(child)["values"])
        return data
    
    def on_double_click(self, event):
        region = self.identify("region", event.x, event.y)
        if region == "heading":
            pass
        else:
            self.warning(title="Bestätigung",
                         message=self.item(event.widget.focus())['values'])            
            if self.warning:                
                self.index=event.widget.focus()                

    def warning(self, title, message):        
        self.root = tk.Toplevel()
        self.root.resizable(False, False)
        self.root.title(title)
        self.root.config(bg="white")
        tk.Label(self.root, text="willst du die folgenden Werte wirklich löschen?", bg="white", fg="red").pack()
        tk.Label(self.root, text=message, bg="white").pack()
        tk.Button(self.root, text="Ja", bg="orange",
                  command=self.yes).pack()
        tk.Button(self.root, text="Nein", bg="white", command=self.no).pack()
        
    def yes(self):
        self.delete(self.index)        
        self.root.destroy()        
        
    def no(self):        
        self.root.destroy()           
        
def main():
    root = tk.Tk()
    table = Table(root, [["Äpfel", "Bananen", "Orangen"], ["60", "60", "60"], ["12", "7", "16"]])
    table.grid(row=0, column=1)
    root.mainloop()
    
if __name__ == "__main__":
    main()
oder mit der Messagebox

Code: Alles auswählen

import tkinter as tk
from tkinter import ttk, messagebox

class Table(ttk.Treeview):
    def __init__(self, master, data):
        super().__init__(master)
        yscrollbar = ttk.Scrollbar(master, orient="vertical", command=self.yview)
        yscrollbar.grid(row=0, column=2, sticky="NS")
        self.configure(yscrollcommand=yscrollbar.set)
        self.headers = data[0]
        self.sizes = [int(size) for size in data[1]]
        data = data[2:]
        column_names = tuple([str(number) for number in range(len(self.headers))])
        self["columns"] = column_names
        self["show"] = "headings"
        for header, size, name in zip(self.headers, self.sizes, column_names):
            self.column(name, width=int(size), minwidth=int(size), anchor="w")
            self.heading(name, text=header, anchor="w")

        for i, column in enumerate(data):
            self.insert("", i, text="", values=tuple(column))

        self.bind("<Double-1>", self.on_double_click)

    def insert_column(self, entries):
        data = [entry.get() for entry in entries]
        self.insert("", randrange(1000, 10000000), text="", values=tuple(data))
                    
    def get_data(self):
        data = []
        data.append(self.headers)
        data.append(self.sizes)
        for child in self.get_children():
            data.append(self.item(child)["values"])
        return data
    
    def on_double_click(self, event):
        region = self.identify("region", event.x, event.y)
        if region == "heading":
            pass
        else:
            frage = "willst du die \nfolgenden Werte \nwirklich löschen?"
            werte = self.item(event.widget.focus())['values']
            meldung = "{}{}".format(frage, werte)
            warning = messagebox.askyesno(title="Bestätigung", message=meldung)
            self.delete(event.widget.focus())
        
def main():
    root = tk.Tk()
    table = Table(root, [["Äpfel", "Bananen", "Orangen"], ["60", "60", "60"], ["12", "7", "16"]])
    table.grid(row=0, column=1)
    root.mainloop()
    
if __name__ == "__main__":
    main()
Was gefällt dir besser?
Gruss
Peter

Re: invalid command name Error

Verfasst: Montag 3. August 2020, 13:47
von Fire Spike
Vielen Dank peterpy :)