Search code examples
pythontkinterpycharmtkinter-buttoncustomtkinter

AttributeError: '_tkinter.tkapp' object has no attribute 'sidebar_button_event' error


I'm trying to modify the complex_example.py from the CustomTkinter website/github so that I can get it to eventually modify some file parameters that are used in a feeding machine for fish.

When I run the code in PyCharm I get the window that I'm expecting (ignore the obvious size issues).

enter image description here

However, whenever I click on any button, such as the "Cancel" button I get the following error

File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/tkinter/init.py", line 2345, in getattr return getattr(self.tk, attr)

AttributeError: '_tkinter.tkapp' object has no attribute 'sidebar_button_event'

Strange thing is that when I run the original complex_example.py there is no issue with the buttons.

I'm sure the issue is obvious, but I'm still learning Python and Google has not been my friend.

Any help would be greatly appreciated.

import sys
#import tkinter
#import tkinter.messagebox
import customtkinter

customtkinter.set_appearance_mode("System")  # Modes: "System" (standard), "Dark", "Light"
customtkinter.set_default_color_theme("blue")  # Themes: "blue" (standard), "green", "dark-blue"

class App(customtkinter.CTk):
    current_speed = 0
    current_direction = "Clockwise"
    current_steps = 0

    def __init__(self):
        super().__init__()

#   Begin row count
        r=0

#   Set column to 0
        c=0

#   Set speed entry
        current_speed=0

#   Set direction
        current_direction=f"Clockwise"

#   Set steps per feeding
        current_steps_feeding=200

# configure window
        self.title("Motor Options")
        self.geometry(f"{750}x{385}")

# configure grid layout (4x4)
#        self.grid_columnconfigure((0, 1, 2, 3), weight=1)
#        self.grid_rowconfigure((0, 1, 2), weight=1)

 # create sidebar frame with widgets
        self.sidebar_frame = customtkinter.CTkFrame(self, width=750, corner_radius=0)
        self.sidebar_frame.grid(row=0, column=c, rowspan=3, sticky="nsew")
#        self.sidebar_frame.grid_rowconfigure(9, weight=1)

        self.logo_label = customtkinter.CTkLabel(self.sidebar_frame, text="Motor Options", font=customtkinter.CTkFont(size=20, weight="bold"))
        self.logo_label.grid(row=r, column=c, columnspan=4, padx=20, pady=(10,10))

        r +=1
        self.logo_label = customtkinter.CTkLabel(self.sidebar_frame, text="Speed", font=customtkinter.CTkFont(size=20, weight="bold"))
        self.logo_label.grid(row=r, column=c, padx=20, pady=(10,10))

#   Speed up
        c +=1
        self.sidebar_button_1 = customtkinter.CTkButton(self.sidebar_frame, command=lambda: self.sidebar_button_event(1))
        self.sidebar_button_1.grid(row=r, column=c, padx=20, pady=(10,10))

#   Speed down
        c +=1
        self.sidebar_button_2 = customtkinter.CTkButton(self.sidebar_frame, command=lambda: self.sidebar_button_event(2))
        self.sidebar_button_2.grid(row=r, column=c, padx=20, pady=(10,10))

# create Speed entry box
        c +=1
        self.entry_speed = customtkinter.CTkEntry(self.sidebar_frame, placeholder_text=current_speed)
        self.entry_speed.grid(row=r, column=c,  padx=20, pady=(10,10))

#   Cancel
        r +=1
        self.sidebar_button_16 = customtkinter.CTkButton(self.sidebar_frame, command=lambda: self.sidebar_button_event(16))
        self.sidebar_button_16.grid(row=r, column=c, padx=20, pady=(10,10))

# set default values
        self.sidebar_button_1.configure(text="Faster")
        self.sidebar_button_2.configure(text="Slower")
        self.sidebar_button_16.configure(text="Cancel")

        def sidebar_button_event(buttonNum):

            if buttonNum == 1:
                print(f"Faster")
                print(f"Attempt to increase speed beyond 100, speed set to 100")
            elif buttonNum == 2:
                print(f"Slower")
            elif buttonNum == 16:
                print(f"Cancel")
                sys.exit(0)

if __name__ == "__main__":
    app = App()
    app.mainloop()

Solution

  • sidebar_button_event() is a nested function inside __init__(), not a class method, so it need to be called without prefix self.:

    command=lambda: sidebar_button_event(...)
    

    Or change it to a class method:

    class App(custometkinter.CTk):
        ...
        def __init__(self):
            ...
    
        # same indentation as `__init__()` and added `self` argument
        def sidebar_button_event(self, buttonNum):
            ...