在tkinter列表框中获取事件延迟



我正在创建一个简单的列表框,其中包含从0到9的数字。我想在点击时打印数字,所以我用Button-1绑定了列表框。我面临的问题是,当我选择任何数字并尝试使用list_box.curselection()获取其位置时,它不会打印任何东西(返回空元组),如果我点击任何其他数字,它就会打印以前选择的数字。我想获取当前选定的号码。

from tkinter import *
root = Tk()
root.title("test listbox")

list_box = Listbox(root)
list_box.pack()
for i in range(0,10):
list_box.insert("end",i)
def def_fun(event):
print(list_box.curselection())
list_box.bind("<Button-1>",def_fun)
root.mainloop()

您不必绑定到<Button-1>或任何东西,Listbox有一个虚拟事件,您可以在这里使用:

def def_fun(event):
print(event.widget.curselection()) # The widget that triggers the event is event.widget
list_box.bind("<<ListboxSelect>>",def_fun) # Gets triggered each time something is selected

如果你想知道Button-1为什么不起作用,那是因为有延迟,延迟可能是由于绑定订单,你可以在这里阅读更多信息,但这里有一个要点:

在默认情况下,<Key>上的绑定发生在类绑定之前,并且它是文本实际插入小部件的类绑定。这就是为什么你的绑定似乎总是落后一个字符。

将绑定更改为释放鼠标按钮,这也将更加用户友好(例如,如果他们不小心点击了不想选择的选项,他们可以将鼠标移动到他们想要的位置,只有释放才会调用该函数):

from tkinter import Tk, Listbox

def def_fun(event=None):
print(list_box.curselection())

root = Tk()
root.title("test listbox")
list_box = Listbox(root)
list_box.pack()
for i in range(0, 10):
list_box.insert("end", i)
list_box.bind("<ButtonRelease-1>", def_fun)
root.mainloop()

如果你想在select时调用函数,另一个选项是使用@CoolCloud答案,或者你也可以设置这样的延迟(尽管它在99.9%的情况下肯定会起作用,但也有可能不起作用):

list_box.bind("<Button-1>", lambda e: root.after(10, def_fun))

原因是.curselection()获得当前选择,但Button-1在选择任何内容之前都会被触发,因此它将打印上一个选择,因为这是以前选择的内容,也是当前选择现在的位置,然后紧接着,它将把当前选择移动到您单击的项。

重要提示(因为这可能会导致难以调试的问题):
我强烈建议在导入某些内容时不要使用通配符(*),您应该导入您需要的内容,例如from module import Class1, func_1, var_2等,或者导入整个模块:import module。然后您也可以使用别名:import module as md或类似的东西,重点是,除非您真正知道自己在做什么,否则不要导入所有内容;名称冲突是个问题。

此外:
我强烈建议遵循PEP 8-Python代码风格指南。函数名和变量名应在snake_case中,类名应在CapitalCase中。如果=用作关键字参数(func(arg='value'))的一部分,则其周围没有空格,但如果用于赋值(variable = 'some value'),则使用。在函数和类声明周围有两行空白。

最新更新