Tkinter参数通过私有属性传递给处理程序 - 这样可以吗?

时间:2015-05-22 23:42:29

标签: python tkinter

我已经看到了几种解决方案,用于将其他参数传递给以不同方式使用包装函数的Tkinter事件处理程序。但是对于在事件中传递一些额外静态数据的简单情况,这样做有任何缺点:

widget.my_private_attribute = my_private_data

并从事件处理程序中的事件中恢复数据:

private_data = event.widget.my_private_attribute

我已经尝试了它并且它有效,但它没有出现在我见过的任何建议的解决方案中所以我担心有一些我不知道的缺点。

这是一个代码示例。重新评论“私人”的含义,我猜这是误导。我的意思是“由我组成,而不是标准的tk属性之一”。

:
:
def onClickPosition(event):
    print "you clicked on", event.widget.grid_position
    if event.widget.cget("bg") == "red":
        event.widget.config(bg="yellow")
    else:
        event.widget.config(bg="red")

root = tk.Tk()

buttonList = []

for i in range(16):
    for j in range(16):
        square = tk.PhotoImage(file="small_square_30x30pix.gif")
        l = tk.Label(root, image=square, borderwidth=0, bg="yellow")
        l.save_image = square
        l.grid_position=(i,j)
        l.bind("<1>", onClickPosition)
        l.grid(row=i, column=j)
        buttonList.append(l)
:
:

“grid_position”是我所指的数据。

我在解决方案上看到了几种变体:

http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/extra-args.html

但我这样做的方式似乎更简单。

2 个答案:

答案 0 :(得分:1)

而不是:

l.grid_position=(i,j)
l.bind("<1>", onClickPosition)

...

def onClickPosition(event):
    print "you clicked on", event.widget.grid_position

尝试:

l.bind("<1>", lambda event, i=i, j=j: onClickPosition(event, i, j))

...

def onClickPosition(event, i, j):
    print "you clicked on", (i,j)

lambda定义了一个内联匿名函数,允许我们向onClickPosition()发送更多参数。将i=i, j=j置于定义中会在定义函数时解析这些变量,而不是在调用函数时解析 - lambda event, i, j将始终生成(15, 15)的点击位置。

答案 1 :(得分:1)

它的价值“属于”任何有意义的小部件,然后是的,不仅将它作为属性附加是安全的,它是惯用的。

文档中有很多例子。

首先,使用子类Frame的“标准Tkinter OO惯用法”在__init__方法或其他地方添加属性的每个示例都正在完成您正在做的事情。你没有子类的事实是不相关的;这是一样的想法。

如果您不购买,请参阅Tkinter Book的PhotoImage页面:

  

注意:当Python对垃圾收集PhotoImage对象时(例如,当您从一个将图像存储在局部变量中的函数返回时),即使Tkinter小部件正在显示该图像,该图像也会被清除。

     

为避免这种情况,程序必须对图像对象保留额外的引用。一种简单的方法是将图像分配给窗口小部件属性,如下所示:

label = Label(image=photo)
label.image = photo # keep a reference!
label.pack()

label不是Label的子类,它有另一个名为image的属性,它只是一个Label,我们刚刚动态添加了另一个属性,并且那很好。

这只是我在几秒钟内略读的第一个例子。

完全可以将值“分”回回调本身,就像在TigerhawkT3的回答中一样。 *

*事实上,我认为这是让Guido相信Python 3.x仍需要lambdapartial的论据之一。

那么,您如何决定使用哪一个?这是一个判断电话。以下是我对此的看法:

  • 该值自然是小部件的成员,还是那种延伸?
  • 您是否已经在使用小部件子类?
  • 您是否有多个回调都需要访问相同的值?
  • 可以想象你对这个值有其他用途(例如,在调试输出中),还是没有意义?

如果这些都没有帮助,那么,您最终需要一些默认策略来处理近距离判断调用。我喜欢以两种方式编写它,然后看看哪一个看起来更具可读性,或者想象一下向刚刚注册以帮助我维护代码的新手解释。如果我还是无法决定,我会在交互式解释器中键入random.random() < 0.5。 :)