Python Tkinter 中同样的方法,首次调用正常,第二次调用报错

89 阅读2分钟

在使用 Python Tkinter 开发 GUI 程序时,遇到一个奇怪的问题。当我在 GUI 中添加一个按钮,并将按钮的命令设置为调用某个方法时,第一次按下按钮,程序可以正常运行。但是,当我第二次按下按钮时,程序会报错,提示方法找不到。

  1. 解决方案

经过一番排查,我发现问题出在变量命名上。在代码中,我使用了相同的变量名来表示两个不同的对象。一个变量名表示数值,另一个变量名表示对象。当我在按钮的命令中调用方法时,程序会根据变量名寻找对应的对象,但是由于变量名相同,程序无法区分是哪个对象的方法,因此报错。

为了解决这个问题,我将变量名进行了区分。对于表示数值的变量,我使用了不同的名称。对于表示对象的变量,我使用了不同的名称。这样,程序就可以正确地区分不同的对象,并且可以正常调用方法。

下面是我修改后的代码:

from Tkinter import *
import ttk

# RGB LED 数值
red_value = 0
green_value = 0
blue_value = 0

# RGB LED 对象
red_led = RGB_LED('Red', 0, 0.0)
green_led = RGB_LED('Green', 1, 0.0)
blue_led = RGB_LED('Blue', 2, 0.0)

def test_pwm_set(channel, intensity):
    global red_value, green_value, blue_value
    print "Calling test_pwm_set"

    if channel == 0:
        red_value = intensity
        print "Red = " + str(intensity)
    elif channel == 1:
        green_value = intensity
        print "Green = " + str(intensity)
    elif channel == 2:
        blue_value = intensity
        print "Blue = " + str(intensity)
    else:
        print 'Invalid Channel!'


def set_red_intensity():
    intensity = float(red_input.get())
    print intensity
    print red_led.get_intensity()
    red_led.set_intensity(50.0)

def set_green_intensity():
    intensity = float(green_input.get())
    green_led.set_intensity(intensity)

def set_blue_intensity():
    intensity = float(blue_input.get())
    blue_led.set_intensity(intensity)


class RGB_LED:

    def __init__(self, color, channel, intensity = 0.0):
        self.color = color
        self.channel = channel
        self.intensity = intensity

    def get_channel(self):
        return self.channel

    def get_intensity(self):
        return self.intensity

    def get_color(self):
        return self.color

    def set_channel(self, channel):
        self.channel = channel

    def set_intensity(self, intensity):
        self.intensity = intensity
        test_pwm_set(self.channel, self.intensity)

    def set_color(self, color):
        self.color = color


######## set up GUI ##########
root = Tk()
root.title("RGB LED Control")

mainframe = ttk.Frame(root, padding="3 3 12 12")
mainframe.grid(column=0, row=0, sticky=(N, W, E, S)) #frame fills all of root window
mainframe.columnconfigure(0, weight=1)  #tells Tk if root window is resized
mainframe.rowconfigure(0, weight=1)     #the frame should take up the extra space

# StringVars
red_input = StringVar()
red_input.set(0.0)
green_input = StringVar()
green_input.set(0.0)
blue_input = StringVar()
blue_input.set(0.0)
red_intensity = StringVar()
green_intensity = StringVar()
blue_intensity = StringVar()

# Entry fields
red_entry = ttk.Entry(mainframe, width=5, textvariable=red_input)
red_entry.grid(column=1, row=2, sticky=(W, E))
green_entry = ttk.Entry(mainframe, width=5, textvariable=green_input)
green_entry.grid(column=2, row=2, sticky=(W, E))
blue_entry = ttk.Entry(mainframe, width=5, textvariable=blue_input)
blue_entry.grid(column=3, row=2, stick=(W, E))

# Labels
ttk.Label(mainframe, textvariable=red_intensity).grid(column=1, row=1, sticky=(W, E))
ttk.Label(mainframe, textvariable=green_intensity).grid(column=2, row=1, sticky=(W, E))
ttk.Label(mainframe, textvariable=blue_intensity).grid(column=3, row=1, sticky=(W, E))

# Buttons
ttk.Button(mainframe, text="Red", command= lambda: set_red_intensity()).grid(column=1, row=3, sticky=(W, E))
ttk.Button(mainframe, text="Green", command= lambda: set_green_intensity()).grid(column=2, row=3, sticky=(W, E))
ttk.Button(mainframe, text="Blue", command= lambda: set_blue_intensity()).grid(column=3, row=3, sticky=(W, E))


root.mainloop()

经过修改后,代码可以正常运行。第一次按下按钮时,程序会调用相应的方法,并正确地设置 RGB LED 的强度。第二次按下按钮时,程序也会正常调用方法,并正确地设置 RGB LED 的强度。