_tkinter.TclError: invalid command name “.!label4”

时光怂恿深爱的人放手 提交于 2021-02-11 14:41:23

问题


When I run this and enter the testuser credentials, it all works perfectly and produces this window with the green coloured text on the login status widget.

However, when I then remove the credentials and type in a random password so that I get the error message, it is not red and produces this error stack (same thing happens if i try to reenter the correct credentials)

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Program Files\Python38\lib\tkinter\__init__.py", line 1883, in __call__
    return self.func(*args)
  File (my path to file), line 194, in get_info
    login_status_widget.config(fg="red")
  File "C:\Program Files\Python38\lib\tkinter\__init__.py", line 1637, in configure
    return self._configure('configure', cnf, kw)
  File "C:\Program Files\Python38\lib\tkinter\__init__.py", line 1627, in _configure
    self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
_tkinter.TclError: invalid command name ".!label4"

I don't know why I get this error, especially since it only happens when I change the credentials - sidenote, using a bad login produces the same result, i.e. working red text then anything after doesn't produce colour.

This is my full code, I can't provide relevant section considering I have no clue where the error is coming from although its probably the way I've implemented this in a class or something.

# Stuff to implement: other widgets in root class, actual GUI for program (ideas: restaurant manager, GUI creator)


# Import tkinter as the alias tk, import mainloop from tkinter
import tkinter as tk
from tkinter import mainloop

# Key Aliases for widget.bind("<Key>",function): "<Return>" = Enter key  aka return key

class Root(): # Define Root class for GUI windows
    """
    Root is the main window class for the GUI which returns an instance with a Tk window, which can then be used to run class functions to return a widget on the window.

    Parameters:
    grid_allowed (True/False) e.g. variable = Root(True) which would mean grid_allowed would be set to True 

    Functions:
    add_button(text, command={function name}, grid_coord=[{row number},{column number}], name="{any string}"): 

    add_label(text, grid_coord=[{row},{column}], name="{any string}"): 

    add_entry(bind={alias of key e.g. "<Return>"}, function={function to be called when key is pressed}, show={character}, grid_coord=[{row number},{column number}], name="{any string}"): 

    return_lists(): Returns a list containing label_list, button_list and entry_list

    delete_widget(name): If a widget with the matching name is found, destroy it

    return_widget(name): If a widget with the matching name is found, return it, else return None

    check_widget(name): If a widget with the matching name is found, return True, else return False

    Notes:
    remember to run {Root instance}.window.mainloop() at the end of the program 

    """

    def __init__(self,grid_allowed,title): # Initialise the class
        self.title = title
        self.window = tk.Tk()   
        self.window.title(self.title)
        self.button_list = []
        self.label_list = []  
        self.entry_list = []
        self.grid_allowed = grid_allowed


    def add_button(self,text,command=None,grid_coord=None,name=None): # Function to add a button onto the window of the Root class instance
        self.command = command 
        self.text = text
        self.grid_coord = grid_coord
        self.name = name

        try: # Tries to create a button with a command and if an error is caught, creates a button without a command
            self.button = tk.Button(self.window,text=self.text,command=self.command)
        except Exception:
            self.button = tk.Button(self.window,text=self.text)

        if self.grid_allowed: # Checks if the class attribute self.grid_allowed is True, if so uses grid manager, else uses pack manager
            self.button.grid(row=self.grid_coord[0],column=self.grid_coord[1])
        else:
            self.button.pack()

        if self.name == None: # Checks if the button has not been given a name and if it has adds a name into the list with the button object
            self.button_list.append(self.button)
        else:
            self.button_list.append([self.name,self.button])


    def add_label(self,text,grid_coord=None,name=None): # Function to add a label onto the window of the Root class instance
        self.text = text 
        self.grid_coord = grid_coord
        self.label = tk.Label(self.window,text=self.text)#
        self.name = name

        if self.grid_allowed: # Checks if the class attribute self.grid_allowed is True, if so uses grid manager, else uses pack manager
            self.label.grid(row=self.grid_coord[0],column=self.grid_coord[1])
        else:
            self.label.pack()

        if self.name == None: # Checks if the label has not been given a name and if it has adds a name into the list with the label object
            self.label_list.append(self.label)
        else:
            self.label_list.append([self.name,self.label])


    def add_entry(self,bind=None,function=None,grid_coord=None,show=None,name=None): # Function to add a entry onto the window of the Root class instance
        self.bind = bind
        self.function = function
        self.grid_coord = grid_coord
        self.show = show
        self.name = name

        if not self.show == None: # Checks if the parameter show has been passed, and if it has then force the entry to only show those characters
            self.entry = tk.Entry(self.window,show=self.show)
        else:
            self.entry = tk.Entry(self.window)

        if not self.bind == None: # Checks if the parameter bind has been passed, and if it has then bind the specified key to the specified function
            self.entry.bind(self.bind,self.function)

        if self.grid_allowed: # Checks if the class attribute self.grid_allowed is True, if so uses grid manager, else uses pack manager
            self.entry.grid(row=self.grid_coord[0],column=self.grid_coord[1])
        else:
            self.entry.pack()

        if self.name == None: # Checks if the entry has not been given a name and if it has adds a name into the list with the entry object
            self.entry_list.append(self.entry)
        else:
            self.entry_list.append([self.name,self.entry])


    def return_lists(self): # Function to return a list of the lists containing the widgets created on the Root class instance
        return [self.label_list, self.button_list, self.entry_list]


    def delete_widget(self,name): # Function to iterate over all the widgets created on the Root class instance and delete the one with the same name that is passed as a parameter if found
        self.name = name

        for widget_list in [self.button_list,self.entry_list,self.label_list]: # Iterates over list, of lists of types of widgets
            for widget in widget_list: # Iterates over indiviual widget type list
                try:
                    if widget[0] == self.name: # If the widget has a name and it is the same as the passed parameter, destroy the widget
                        widget[1].destroy()
                except Exception: # If the widget is not found on the current iteration then ignore that widget
                    pass


    def return_widget(self,name): # Function to iterate over all the widgets created on the Root class instance and if one is found with the same name that is passed as a parameter return it
        self.name = name

        for widget_list in [self.button_list,self.entry_list,self.label_list]: # Iterates over list, of lists of types of widgets
            for widget in widget_list: # Iterates over indiviual widget type list
                try:
                    if widget[0] == self.name: # If the widget has a name and it is the same as the passed parameter, return the widget object
                        return widget[1] 
                except Exception:
                    return_bln = None # If the correct widget is not found return None
        return return_bln

    def check_widget(self,name): # Function to iterate over all the widgets created on the Root class instance and if one is found with the same name that is passed as a parameter return True
        self.name = name

        for widget_list in [self.button_list,self.entry_list,self.label_list]: # Iterates over list, of lists of types of widgets
            for widget in widget_list:  # Iterates over indiviual widget type list
                try:
                    if widget[0] == self.name: # If the widget has a name and it is the same as the passed parameter, returns True
                    return True
                except Exception:
                    return_bln = False # If the correct widget is not found return None

        return return_bln





# Actual GUI creation below

def main():
    main_window = Root(True,"Login") # Create an instance of Root class and assign main_window to it
    main_window.window.resizable(0,0) # Prevent user from resizing the window
    main_window.window.geometry("300x90") # Setting the original size of the window to '300x90'

    user_dict = {
        "testuser":"test",
}

    def check_login(username,password): # Function to take a username and password as parameters and return True if they are a valid user, else return False
        try:
            if user_dict[username] == password: # If the username exists check if the password is correct and return True if it is, False if it isn't
                return True
            else:
                return False
        except Exception: 
            return False # If the user doesn't exist return False

    def get_info(): # Function to handle login event on button click
        password = main_window.return_widget("password").get() # Get the current value of the password widget from main_window
        username = main_window.return_widget("username").get() # Get the current value of the username widget from main_window
        email = main_window.return_widget("email").get() # Get the current value of the email widget from main_window

        login_status = check_login(username,password) # Calls function with the username and password obtained from the widgets and assigns login_status to result

        if main_window.check_widget("login status"): # If the error message/success message already exist, delete the widget
            main_window.delete_widget("login status")

        if login_status: # If the username and password were correct, add a label widget to the window saying 'Login successful', else add a label widget to the window saying 'Your username or password is incorrect'
            main_window.add_label("Login successful",grid_coord=[3,1],name="login status")
            login_status_widget = main_window.return_widget("login status")
            login_status_widget.config(fg="green")
        else:
            main_window.add_label("Your username or password is incorrect",grid_coord=[3,1],name="login status")
            login_status_widget = main_window.return_widget("login status")
            login_status_widget.config(fg="red")


    main_window.add_label("Username",grid_coord=[0,0])  # Create the basic layout of the window
    main_window.add_entry(grid_coord=[0,1],name="username") 
    main_window.add_label("Password",grid_coord=[1,0]) 
    main_window.add_entry(show="*",grid_coord=[1,1],name="password")
    main_window.add_label("Email",grid_coord=[2,0])
    main_window.add_entry(grid_coord=[2,1],name="email")
    main_window.add_button(text="Login",command=get_info,grid_coord=[3,0])

    list_array = main_window.return_lists() # Get the lists of all the widgets from main_window

    main_window.window.mainloop() # Start the mainloop of the GUI to show the window 

if __name__ == "__main__": # If the python script is being run in cmd, call main function
    main()

回答1:


When I was deleting the widget I didn't use the delete_widget function which I specifically created, but rather returned the widget then called widget.destroy().

I have now fixed this and it is working fine.

Thanks to Bryan Oakley for helping me to realise the stem of the error.



来源:https://stackoverflow.com/questions/59435804/tkinter-tclerror-invalid-command-name-label4

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!