python-3.x 如何在Tkniter GUI中创建可与开关按钮一起使用的函数?

cgyqldqp  于 2022-12-14  发布在  Python
关注(0)|答案(1)|浏览(125)

我正在尝试用Tkinter构建一个GUI,并用它来控制我的树莓派机器人。在一些帮助下,我设法获得了按钮在被按下和按住时的功能,但我正在与允许我用开关按钮做事情的功能作斗争。

下面是Tkinter代码的一个简短片段:

# 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")

这是我要实现的函数

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

这似乎不工作,因为我得到的错误消息:

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

TypeError:“CTkSwitch”对象不可调用。
下面是完整的代码,如果有帮助:

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()

你知道我做错了什么吗?

k3bvogb1

k3bvogb11#

你的整体逻辑至少有3个问题。
此行:

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

应为:

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

这是因为这里不需要lambda,并且您的lambda:调用只是保存对函数的引用,而不是在触发时实际调用它。
接下来,您需要更改接收调用的函数,因为您没有显式传递事件,并且它期望on。
所以改变一下:

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

对此:

# 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

最后,全局名称空间中实际上没有is_on = True,因此不能在有它的地方引用它。
要么将其作为class属性添加到类init中,要么将其从类中移到全局名称空间中。
就我个人而言,我会选择类属性来避免使用全局属性。下面的版本使用类属性来代替全局属性。
下面是代码的更正版本。

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()

根据我的测试,这解决了您的问题:

相关问题