我只是尝试鼠标悬停功能,一组5个按钮,鼠标悬停颜色 设置运行正常,只有一个按钮样本,但它没有给出正确的结果 当我尝试多个按钮时,它只影响最后一个绑定按钮,任何人都可以 帮我快速解决下面的代码有什么问题,我尝试使用bind和bind_all方法! 两者都未能提供所需的产出。
import os
from Tkinter import *
import Tkinter as tk
global btnPlaceY
btnPlaceY=10
class App():
def __init__ (self):
root['width']=400
root['height']=600
root['bg']='blue'
self.btnGroupCreate()
def btnDisplaymessage1(self):
print "Function testing1"
def btnDisplaymessage2(self):
print "Function testing2"
def btnGroupCreate(self):
btnNameNameGroup="btnSample"
self.btnWidget={}
lstBtnTitle=['A','B','C','D','E']
lstBtnCommands=[ lambda:self.btnDisplaymessage1(),
lambda:self.btnDisplaymessage2() ]
for B in range(5):
btnName=btnNameNameGroup+lstBtnTitle[B]
global btnPlaceY
btnPlaceY=btnPlaceY+70
# Button commands
if B==0:
btnMenuCommand=lstBtnCommands[0]
if B==1:
btnMenuCommand=lstBtnCommands[1]
if B==2:
btnMenuCommand=lstBtnCommands[0]
if B==3:
btnMenuCommand=lstBtnCommands[1]
if B==4:
btnMenuCommand=lstBtnCommands[1]
if B==5:
btnMenuCommand=lstBtnCommands[0]
self.btnWidget[btnName]= tk.Button(root, width=4, height=2,text=lstBtnTitle[B],bg="gray",relief=FLAT,command=btnMenuCommand) #activebackground="red"
widget = self.btnWidget[btnName]
widget.bind_all("<Enter>", lambda event: event.widget.configure(bg="red"))
widget.bind_all("<Leave>", lambda event: event.widget.configure(bg="gray"))
self.btnWidget[btnName].pack()
self.btnWidget[btnName].place(x=40, y = btnPlaceY)
def make_callback(self,btnName):
print "make_callback"
root['bg']='green'
widget = self.btnWidget[btnName]
def callback(event):
print "callback"
widget.configure(bg="red")
root['bg']='green'
return callback
root=tk.Tk()
app = App()
root.mainloop()
答案 0 :(得分:1)
self.btnWidget[btnName].bind_all("<Enter>", lambda event: self.btnWidget[btnName].configure(bg="red"))
self.btnWidget[btnName].bind_all("<Leave>", lambda event: self.btnWidget[btnName].configure(bg="yellow"))
在这些行中的lambda表达式中,btnName
将具有在循环期间保持的 last 值,而不是绑定事件时的值。它将是&#34; btnSampleE&#34;,即使对于按钮A到D.此外,对于特定于窗口小部件的事件,您应该使用bind
而不是bind_all
。
强迫&#34;早期绑定的典型方式&#34;行为,以便btnName
保持其当前值,是为lambda提供一个默认参数,包含你需要的值。
self.btnWidget[btnName].bind("<Enter>", lambda event, x = btnName: self.btnWidget[x].configure(bg="red"))
self.btnWidget[btnName].bind("<Leave>", lambda event, x = btnName: self.btnWidget[x].configure(bg="yellow"))
您可以为此参数使用您想要的任何变量名称;你甚至可以称之为btnName
,因为本地值会使非本地值黯然失色。
self.btnWidget[btnName].bind("<Enter>", lambda event, btnName=btnName: self.btnWidget[btnName].configure(bg="red"))
self.btnWidget[btnName].bind("<Leave>", lambda event, btnName=btnName: self.btnWidget[btnName].configure(bg="yellow"))
答案 1 :(得分:1)
问题是在Python中,诸如lambda函数之类的闭包关闭了周围块中的名称,而不是值。因此,在lambda中观察到的btnName
的值取决于它何时被执行 - 因为事件只能在退出循环后发生,btnName
是最后看到的。
有很多方法可以避免这个问题,其中一个是凯文的默认值技巧。但是,默认值方法容易出错 - 现在函数接受2个参数而不是1,并且可以在某些上下文中错误地调用。
因此,更好的方法是使用回调制造商:
def make_callback(btnName):
def callback(event):
self.btnWidget[btnName].configure(bg="red"))
return callback
self.btnWidget[btnName].bind_all("<Enter>", make_callback(btnName))
然而,有人注意到btnWidget
被重复,所以可以这样做
widget = self.btnWidget[btnName]
def make_callback(btnName):
def callback(event):
widget.configure(bg="red")
return callback
widget.bind_all("<Enter>", make_callback(widget))
可以用lambdas写成:
widget = self.btnWidget[btnName]
widget.bind_all("<Enter>",
(lambda widget: lambda event: widget.configure(bg="red"))(widget))
但是,在这种情况下,这种技巧都不是必需的,因为回调中唯一需要的是事件发生的小部件。这在属性widget
的TkInter事件中很容易获得,所以你需要做的就是
widget = self.btnWidget[btnName]
widget.bind_all("<Enter>", lambda event: event.widget.configure(bg="red"))
widget.bind_all("<Leave>", lambda event: event.widget.configure(bg="yellow"))