Tkinter argument passing to handler via private attributes - is this OK?
我已经看到了几种将附加参数传递给以不同方式使用package函数的 Tkinter 事件处理程序的解决方案。但是对于在事件中传递一些额外静态数据的简单情况,这样做有什么缺点:
widget.my_private_attribute = my_private_data
并在事件处理程序中从事件中恢复数据:
private_data = event.widget.my_private_attribute
我已经尝试过了,它可以工作,但它没有出现在我见过的任何建议的解决方案中,所以我担心存在一些我不知道的缺点。
这是一个代码示例。重新评论"私人"的含义,我想这是误导。我的意思是"由我组成,不是标准的 tk 属性之一"。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | : : 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
但我的做法似乎更简单。
如果值在任何有意义的意义上"属于"小部件,那么是的,不仅将其作为属性附加是安全的,而且是惯用的。
文档中有很多例子。
一方面,每个使用子类化
如果您不购买,请参阅 Tkinter Book 的
Note: When a PhotoImage object is garbage-collected by Python (e.g. when you return from a function which stored an image in a local variable), the image is cleared even if it’s being displayed by a Tkinter widget.
To avoid this, the program must keep an extra reference to the image object. A simple way to do this is to assign the image to a widget attribute, like this:
1 2 3 | label = Label(image=photo) label.image = photo # keep a reference! label.pack() |
这只是我在浏览几秒钟后发现的第一个例子。
但也可以将值"部分"放入回调本身,就像 TigerhawkT3 的回答一样。*
* 事实上,我相信这是让 Guido 相信 Python 3.x 仍然需要
那么,您如何决定使用哪一个?这是一个判断电话。以下是我的想法:
- 该值自然是小部件的成员,还是那种延伸?
- 您是否已经在使用小部件子类?
- 您是否有多个回调都需要访问相同的值?
- 是否可以想象该值还有其他用途(例如,在调试输出中),或者这没有任何意义?
如果这些都没有帮助,那么您最终需要一些默认策略来处理密切判断调用。我喜欢两种方式都写,然后看看哪个看起来更易读,或者想象一下向刚刚注册帮助我维护代码的新手解释这两种方式。如果我仍然无法决定,我在交互式解释器中输入
代替:
1 2 3 4 5 6 7 | l.grid_position=(i,j) l.bind("<1>", onClickPosition) ... def onClickPosition(event): print"you clicked on", event.widget.grid_position |
尝试:
1 2 3 4 5 6 | l.bind("<1>", lambda event, i=i, j=j: onClickPosition(event, i, j)) ... def onClickPosition(event, i, j): print"you clicked on", (i,j) |
的点击位置