How to create function that can be used with switch button in Tkniter GUI?

Question:

I am trying to build a GUI with Tkinter and use it to control my Raspberry Pi robot.
With some help, I managed to get the functionality of the buttons when being pressed and held down but I am struggling with the function that
will allow me to do things with the switch button.
enter image description here

here is a quick snippet of the Tkinter code:

# LED  Lights
self.led_switch = customtkinter.CTkSwitch(master=self.lights_control, text="LED", 
command=lambda: self.led_switch())
self.led_switch.grid(row=0, column=1, pady=10, padx=20, sticky="n")

and here is the function I’m trying to implement:

is_on = True
def led_switch(self, event):
    global is_on

    if is_on:
        print("It is on")
        #is_on = False
    else:
        print("It is off")

        #is_on = True

This doesn’t seem to work since I’m getting the error message:

 self.led_switch = customtkinter.CTkSwitch(master=self.lights_control, text="LED", command=lambda: self.led_switch())

TypeError: ‘CTkSwitch’ object is not callable`.

here is the full code if that helps:

   import tkinter
import tkinter.messagebox
import customtkinter

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

class App(customtkinter.CTk):
    def __init__(self):
        super().__init__()

        # configure window
        self.title("Cool Blue")
        self.geometry(f"{1200}x{560}")

        # configure grid layout (4x4)
        self.grid_columnconfigure(1, weight=1)
        self.grid_columnconfigure((2, 3), weight=0)
        self.grid_rowconfigure((0, 1, 2, 3, 4), weight=1)
        self.bind("<KeyPress>", self.key_pressed)
        self.bind("<KeyRelease>", self.key_released)


        ###################################################################
        # create sidebar frame for controls
        ###################################################################
        self.sidebar_frame = customtkinter.CTkFrame(self, width=100)
        self.sidebar_frame.grid(row=0, column=0, rowspan=1, padx=(5, 5), pady=(10, 10), sticky="nsew")
        self.sidebar_frame.grid_rowconfigure(4, weight=1)

        # Setting up grid label
        self.logo_label = customtkinter.CTkLabel(self.sidebar_frame, text="Motion",  font=customtkinter.CTkFont(size=15, weight="bold"))
        self.logo_label.grid(row=0, column=1, padx=20, pady=(10, 10))

        # Setting up W - Forward button
        self.button_up = customtkinter.CTkButton(self.sidebar_frame, text="W", height=10, width=10)
        self.button_up.grid(row=1, column=1, padx=20, pady=10, ipadx=10, ipady=10)
        self.button_up.bind('<ButtonPress-1>', lambda x: self.motion_event_start(x, 'W'))
        self.button_up.bind('<ButtonRelease-1>', lambda x: self.motion_event_stop(x, 'W'))

        # Setting up S - Backwards buttons
        self.button_down = customtkinter.CTkButton(self.sidebar_frame, text="S", height=10, width=10)
        self.button_down.grid(row=3, column=1, padx=20, pady=10, ipadx=10, ipady=10)
        self.button_down.bind('<ButtonPress-1>', lambda x: self.motion_event_start(x, 'S'))
        self.button_down.bind('<ButtonRelease-1>', lambda x: self.motion_event_stop(x, 'S'))

        # Setting up A - Left button
        self.button_left = customtkinter.CTkButton(self.sidebar_frame, text="A", height=10, width=10)
        self.button_left.grid(row=2, column=0, padx=10, pady=10, ipadx=10, ipady=10)
        self.button_left.bind('<ButtonPress-1>', lambda x: self.motion_event_start(x, 'A'))
        self.button_left.bind('<ButtonRelease-1>', lambda x: self.motion_event_stop(x, 'A'))

        # Setting up D - Right button
        self.button_right = customtkinter.CTkButton(self.sidebar_frame, text="D", height=10, width=10)
        self.button_right.grid(row=2, column=2, padx=10, pady=10, ipadx=10, ipady=10)
        self.button_right.bind('<ButtonPress-1>', lambda x: self.motion_event_start(x, 'D'))
        self.button_right.bind('<ButtonRelease-1>', lambda x: self.motion_event_stop(x,'D'))


        ###################################################################
        # Create Sidebar for arm control
        ###################################################################
        self.arm_control = customtkinter.CTkFrame(self)
        self.arm_control.grid(row=1, column=0, rowspan = 1, padx=(5, 5), pady=(10, 10), sticky="nsew")
        self.arm_control.grid_rowconfigure(2, weight=1)

        # Setting up grid label
        self.arm_label = customtkinter.CTkLabel(self.arm_control, text="Arm",  font=customtkinter.CTkFont(size=15, weight="bold"))
        self.arm_label.grid(row=0, column=0, padx=20, pady=(10, 10))
        self.grip_label = customtkinter.CTkLabel(self.arm_control, text="Grip",  font=customtkinter.CTkFont(size=15, weight="bold"))
        self.grip_label.grid(row=0, column=1, padx=20, pady=(10, 10))

        # Arm Up
        self.button_arm_up = customtkinter.CTkButton(self.arm_control, text="    Up   ", height=10, width=10)
        self.button_arm_up.grid(row=1, column=0, padx=10, pady=10, ipadx=30, ipady=10)
        # Arm Down
        self.button_arm_down = customtkinter.CTkButton(self.arm_control, text=" Down", height=10, width=10)
        self.button_arm_down.grid(row=2, column=0, padx=10, pady=10, ipadx=30, ipady=10)

        self.button_grip_open = customtkinter.CTkButton(self.arm_control, text="Open", height=10, width=10)
        self.button_grip_open.grid(row=1, column=1, padx=10, pady=10, ipadx=30, ipady=10, sticky="w")

        self.button_grip_close = customtkinter.CTkButton(self.arm_control, text="Close", height=10, width=10)
        self.button_grip_close.grid(row=2, column=1, padx=10, pady=10, ipadx=30, ipady=10, sticky="w")


        ###################################################################
        # Create Sidebar for grip
        ###################################################################
        self.lights_control = customtkinter.CTkFrame(self)
        self.lights_control.grid(row=3, column=0, rowspan = 1, padx=(5, 5), pady=(10, 10), sticky="nsew")
        self.lights_control.grid_rowconfigure(1, weight=1)

        # LED  Lights
        self.led_switch = customtkinter.CTkSwitch(master=self.lights_control, text="LED", command=lambda: self.led_switch)
        self.led_switch.grid(row=0, column=1, pady=10, padx=20, sticky="n")

        # Regular Lights
        self.regular_ligths_switch = customtkinter.CTkSwitch(master=self.lights_control, text="Lights", command=lambda: print("switch 1 toggle"))
        self.regular_ligths_switch.grid(row=1, column=1, pady=10, padx=20)

        # Camera
        self.led_switch = customtkinter.CTkSwitch(master=self.lights_control, text="Camera", command=lambda: print("switch 1 toggle"))
        self.led_switch.grid(row=2, column=1, pady=10, padx=20, )

        # create Video Canvas
        self.picam = customtkinter.CTkCanvas(self, width=800, background="gray")
        self.picam.grid(row=0, column=1, rowspan=4, padx=(5, 5), pady=(20, 20), sticky="nsew")
        self.picam.grid_rowconfigure(4, weight=1)

        self.picam_label = customtkinter.CTkLabel(master=self.picam, text="Live Stream", font=customtkinter.CTkFont(size=20, weight="bold"))
        self.picam_label.grid(row=0, column=2, columnspan=1, padx=10, pady=10, sticky="")

        # create radiobutton frame
        self.temperature = customtkinter.CTkFrame(self)
        self.temperature.grid(row=0, column=3, rowspan = 1, padx=(5, 5), pady=(10, 10), sticky="n")
        self.temperature.grid_rowconfigure(2, weight=1)
        self.label_temperature = customtkinter.CTkLabel(master=self.temperature, text="Temperature")
        self.label_temperature.grid(row=0, column=2, columnspan=1, padx=10, pady=10, sticky="")

        # create checkbox and switch frame
        self.pressure = customtkinter.CTkFrame(self)
        self.pressure.grid(row=1, column=3, rowspan = 1, padx=(5, 5), pady=(10, 10), sticky="n")
        self.pressure.grid_rowconfigure(1, weight=1)
        self.label_pressure = customtkinter.CTkLabel(master=self.pressure, text="Pressure")
        self.label_pressure.grid(row=0, column=2, columnspan=1, padx=10, pady=10, sticky="")

        # create checkbox and switch frame
        self.humidity = customtkinter.CTkFrame(self)
        self.humidity.grid(row=3, column=3, rowspan = 1, padx=(5, 5), pady=(10, 10), sticky="")
        self.humidity.grid_rowconfigure(1, weight=1)
        self.label_humidity = customtkinter.CTkLabel(master=self.humidity, text="Humidity")
        self.label_humidity.grid(row=0, column=2, columnspan=1, padx=10, pady=10, sticky="")


    def key_pressed(self, event):
        if event.char in 'wads':
            self.motion_event_start(event, event.char.upper())

    def key_released(self, event):
        if event.char in 'wads':
            self.motion_event_stop(event, event.char.upper())

    def motion_event_start(self, event, button):
        # if button == "W":
        #     kit1.motor1.throttle = 1
        #     kit2.motor1.throttle = 1
        # elif button == "S":
        #     kit1.motor1.throttle = -1
        #     kit2.motor1.throttle = -1

        print(f"{button} Pressed")

    def motion_event_stop(self, event, button):
        print(f"{button} Released")
        # kit1.motor1.throttle = 0
        # kit2.motor1.throttle = 0

    
    # Switch
    
    is_on = True
    def led_switch(self, event):
        global is_on

        if is_on:
            print("It is on")
            #is_on = False
        else:
            print("It is off")

            #is_on = True

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

Any ideas on what I’m doing wrong here?

Asked By: Slavisha84

||

Answers:

There are at least 3 problems with your overall logic.

This line:

self.led_switch=customtkinter.CTkSwitch(master=self.lights_control, text="LED", command=lambda: self.led_switch)

Should be:

self.led_switch=customtkinter.CTkSwitch(master=self.lights_control, text="LED", command=self.led_switch)

This is because lambda is not needed here and your lambda: call was only saving a reference to the function and not actually calling it when triggered.

Next you need to change the function that is receiving the call since you are not explicitly passing an event and it is expecting on.

So change this:

def led_switch(self, event):
    global is_on

    if is_on:
        print("It is on")
        is_on = False
    else:
        print("It is off")
        is_on = True

To this:

# You can use event=None or remove event or use another option if needed.
def led_switch(self, event=None):
    global is_on

    if is_on:
        print("It is on")
        is_on = False
    else:
        print("It is off")
        is_on = True

Lastly you do not actually have is_on = True in the global namespace so it cannot be referenced where you have it.

Either add it to your class init as a class attribute or move it out of the class to the global namespace.

Personally I would go with the class attribute route to avoid using global.
The below version uses a class attribute instead of global.

Here is a corrected version of your code.

import customtkinter

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

class App(customtkinter.CTk):
    def __init__(self):
        super().__init__()

        # configure window
        self.is_on = True
        self.title("Cool Blue")
        self.geometry(f"{1200}x{560}")

        # configure grid layout (4x4)
        self.grid_columnconfigure(1, weight=1)
        self.grid_columnconfigure((2, 3), weight=0)
        self.grid_rowconfigure((0, 1, 2, 3, 4), weight=1)
        self.bind("<KeyPress>", self.key_pressed)
        self.bind("<KeyRelease>", self.key_released)

        ###################################################################
        # create sidebar frame for controls
        ###################################################################
        self.sidebar_frame = customtkinter.CTkFrame(self, width=100)
        self.sidebar_frame.grid(row=0, column=0, rowspan=1, padx=(5, 5), pady=(10, 10), sticky="nsew")
        self.sidebar_frame.grid_rowconfigure(4, weight=1)

        # Setting up grid label
        self.logo_label = customtkinter.CTkLabel(self.sidebar_frame, text="Motion",
                                                 font=customtkinter.CTkFont(size=15, weight="bold"))
        self.logo_label.grid(row=0, column=1, padx=20, pady=(10, 10))

        # Setting up W - Forward button
        self.button_up = customtkinter.CTkButton(self.sidebar_frame, text="W", height=10, width=10)
        self.button_up.grid(row=1, column=1, padx=20, pady=10, ipadx=10, ipady=10)
        self.button_up.bind('<ButtonPress-1>', lambda x: self.motion_event_start(x, 'W'))
        self.button_up.bind('<ButtonRelease-1>', lambda x: self.motion_event_stop(x, 'W'))

        # Setting up S - Backwards buttons
        self.button_down = customtkinter.CTkButton(self.sidebar_frame, text="S", height=10, width=10)
        self.button_down.grid(row=3, column=1, padx=20, pady=10, ipadx=10, ipady=10)
        self.button_down.bind('<ButtonPress-1>', lambda x: self.motion_event_start(x, 'S'))
        self.button_down.bind('<ButtonRelease-1>', lambda x: self.motion_event_stop(x, 'S'))

        # Setting up A - Left button
        self.button_left = customtkinter.CTkButton(self.sidebar_frame, text="A", height=10, width=10)
        self.button_left.grid(row=2, column=0, padx=10, pady=10, ipadx=10, ipady=10)
        self.button_left.bind('<ButtonPress-1>', lambda x: self.motion_event_start(x, 'A'))
        self.button_left.bind('<ButtonRelease-1>', lambda x: self.motion_event_stop(x, 'A'))

        # Setting up D - Right button
        self.button_right = customtkinter.CTkButton(self.sidebar_frame, text="D", height=10, width=10)
        self.button_right.grid(row=2, column=2, padx=10, pady=10, ipadx=10, ipady=10)
        self.button_right.bind('<ButtonPress-1>', lambda x: self.motion_event_start(x, 'D'))
        self.button_right.bind('<ButtonRelease-1>', lambda x: self.motion_event_stop(x, 'D'))

        ###################################################################
        # Create Sidebar for arm control
        ###################################################################
        self.arm_control = customtkinter.CTkFrame(self)
        self.arm_control.grid(row=1, column=0, rowspan=1, padx=(5, 5), pady=(10, 10), sticky="nsew")
        self.arm_control.grid_rowconfigure(2, weight=1)

        # Setting up grid label
        self.arm_label = customtkinter.CTkLabel(self.arm_control, text="Arm",
                                                font=customtkinter.CTkFont(size=15, weight="bold"))
        self.arm_label.grid(row=0, column=0, padx=20, pady=(10, 10))
        self.grip_label = customtkinter.CTkLabel(self.arm_control, text="Grip",
                                                 font=customtkinter.CTkFont(size=15, weight="bold"))
        self.grip_label.grid(row=0, column=1, padx=20, pady=(10, 10))

        # Arm Up
        self.button_arm_up = customtkinter.CTkButton(self.arm_control, text="    Up   ", height=10, width=10)
        self.button_arm_up.grid(row=1, column=0, padx=10, pady=10, ipadx=30, ipady=10)
        # Arm Down
        self.button_arm_down = customtkinter.CTkButton(self.arm_control, text=" Down", height=10, width=10)
        self.button_arm_down.grid(row=2, column=0, padx=10, pady=10, ipadx=30, ipady=10)

        self.button_grip_open = customtkinter.CTkButton(self.arm_control, text="Open", height=10, width=10)
        self.button_grip_open.grid(row=1, column=1, padx=10, pady=10, ipadx=30, ipady=10, sticky="w")

        self.button_grip_close = customtkinter.CTkButton(self.arm_control, text="Close", height=10, width=10)
        self.button_grip_close.grid(row=2, column=1, padx=10, pady=10, ipadx=30, ipady=10, sticky="w")

        ###################################################################
        # Create Sidebar for grip
        ###################################################################
        self.lights_control = customtkinter.CTkFrame(self)
        self.lights_control.grid(row=3, column=0, rowspan=1, padx=(5, 5), pady=(10, 10), sticky="nsew")
        self.lights_control.grid_rowconfigure(1, weight=1)

        # LED  Lights
        self.led_switch = customtkinter.CTkSwitch(master=self.lights_control, text="LED",
                                                  command= self.led_switch)
        self.led_switch.grid(row=0, column=1, pady=10, padx=20, sticky="n")

        # Regular Lights
        self.regular_ligths_switch = customtkinter.CTkSwitch(master=self.lights_control, text="Lights",
                                                             command=lambda: print("switch 1 toggle"))
        self.regular_ligths_switch.grid(row=1, column=1, pady=10, padx=20)

        # Camera
        self.led_switch = customtkinter.CTkSwitch(master=self.lights_control, text="Camera",
                                                  command=lambda: print("switch 1 toggle"))
        self.led_switch.grid(row=2, column=1, pady=10, padx=20, )

        # create Video Canvas
        self.picam = customtkinter.CTkCanvas(self, width=800, background="gray")
        self.picam.grid(row=0, column=1, rowspan=4, padx=(5, 5), pady=(20, 20), sticky="nsew")
        self.picam.grid_rowconfigure(4, weight=1)

        self.picam_label = customtkinter.CTkLabel(master=self.picam, text="Live Stream",
                                                  font=customtkinter.CTkFont(size=20, weight="bold"))
        self.picam_label.grid(row=0, column=2, columnspan=1, padx=10, pady=10, sticky="")

        # create radiobutton frame
        self.temperature = customtkinter.CTkFrame(self)
        self.temperature.grid(row=0, column=3, rowspan=1, padx=(5, 5), pady=(10, 10), sticky="n")
        self.temperature.grid_rowconfigure(2, weight=1)
        self.label_temperature = customtkinter.CTkLabel(master=self.temperature, text="Temperature")
        self.label_temperature.grid(row=0, column=2, columnspan=1, padx=10, pady=10, sticky="")

        # create checkbox and switch frame
        self.pressure = customtkinter.CTkFrame(self)
        self.pressure.grid(row=1, column=3, rowspan=1, padx=(5, 5), pady=(10, 10), sticky="n")
        self.pressure.grid_rowconfigure(1, weight=1)
        self.label_pressure = customtkinter.CTkLabel(master=self.pressure, text="Pressure")
        self.label_pressure.grid(row=0, column=2, columnspan=1, padx=10, pady=10, sticky="")

        # create checkbox and switch frame
        self.humidity = customtkinter.CTkFrame(self)
        self.humidity.grid(row=3, column=3, rowspan=1, padx=(5, 5), pady=(10, 10), sticky="")
        self.humidity.grid_rowconfigure(1, weight=1)
        self.label_humidity = customtkinter.CTkLabel(master=self.humidity, text="Humidity")
        self.label_humidity.grid(row=0, column=2, columnspan=1, padx=10, pady=10, sticky="")

    def key_pressed(self, event):
        if event.char in 'wads':
            self.motion_event_start(event, event.char.upper())

    def key_released(self, event):
        if event.char in 'wads':
            self.motion_event_stop(event, event.char.upper())

    def motion_event_start(self, event, button):
        # if button == "W":
        #     kit1.motor1.throttle = 1
        #     kit2.motor1.throttle = 1
        # elif button == "S":
        #     kit1.motor1.throttle = -1
        #     kit2.motor1.throttle = -1

        print(f"{button} Pressed")

    def motion_event_stop(self, event, button):
        print(f"{button} Released")
        # kit1.motor1.throttle = 0
        # kit2.motor1.throttle = 0

    # Switch

    def led_switch(self, event=None):
        if self.is_on:
            print("It is on")
            self.is_on = False
        else:
            print("It is off")
            self.is_on = True


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

From my testing this fixes your issue:

enter image description here

enter image description here

Answered By: Mike – SMT
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.