Tkinter / TTK - 防止字符串到 ButtonPress 的转换

Tkinter / TTK - Prevent string to ButtonPress conversion

我正在编写一个简单的脚本来创建一个 ttk Treeview(充当 table),当您双击它时,它会打开一个文件(保存路径在字典中)。但是,当您双击一行时,您会收到此错误:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\Maicol\AppData\Local\Programs\Python\Python36\lib\tkinter\__init__.py",
line 1699, in __call__
    return self.func(*args)
  File "C:\Users\Maicol\Documents\Projects\App_WINDOWS\School_Life_Diary\note.py",
line 195, in <lambda>
    lambda f=nt[x]["URIallegato"]: os.startfile(str(f)))
FileNotFoundError: [WinError 2] Can't find the specified file: '<ButtonPress event state=Mod1 num=1 x=677 y=37>'

问题是这段代码:

t.bind("<Double-1>", lambda f=nt[x]["URIallegato"]: os.startfile(str(f)))

允许双击并打开文件。

这是完整的 Treeview 代码:

t=Treeview(w)
t.pack(padx=10,pady=10)
for x in list(nt.keys()):
    t.insert("",x,text=nt[x]["allegati"])
    if nt[x]["allegati"]!="":
        t.bind("<Double-1>",
               lambda f=nt[x]["URIallegato"]: os.startfile(str(f)))

当事件触发时,tkinter 将传递一个事件对象。您正在尝试打开该事件对象,就好像它是一个文件一样。

这是为什么?让我们首先将您的 lambda 重写为适当的函数。您的 lambda 等效于此函数:

def handle_event(f=default_value):
    os.startfile(str(default_value))

事件触发时,它的作用相当于:

handle_event(event)

您的脚本有一个位置参数 event,它被分配给第一个关键字参数。因此 fevent.

相同

解决方案是确保您的 lambda 接受可以忽略的事件:

lambda event, f=nt[x]["URIallegato"]: os.startfile(str(f)))

通过上述,event 对象将与 event 参数相关联,并且 f 的默认值将作为 f 传递。

主要问题是关于在循环中为 Treeview 创建绑定。

只有一个双击事件可以为树声明和触发,而不是逐行一个,在这里你在每次迭代中覆盖它。


众所周知,此 lambda 模式可为 for/loop 内的小部件声明 命令,并且它可以很好地用于此目的:

lambda f=nt[x]["URIallegato"]: os.startfile(str(f))

但是在这里你声明了一个默认参数 f,并且 lambda 将使用事件绑定给出的 event 参数执行,这就是你在异常中得到的:<ButtonPress event state=Mod1...

无论如何,我们发现即使您使用第二个参数修复 lambda 以接受 event 而不替换您的默认值 f.[=21,这在您的情况下也不起作用=]


我的建议是使用每行的 values 字段来存储信息 URIallegato",而不显示树中的列。

然后您可以将通用事件绑定到 Treeview,通过使用 focus() 获取所选项目,并提取值以获取 URI。

t=Treeview(w)
t.pack(padx=10,pady=10)

def open_item(event):
    item = t.item(t.focus())
    if item['text']:
        os.startfile(item['values'][0])

for x in list(nt.keys()):
    value = ''
    if nt[x]["allegati"]:
        value = str(nt[x]["URIallegato"])
    t.insert("",x,text=nt[x]["allegati"], values=value)

t.bind("<Double-1>", open_item)

如果要检查是否有要打开的 URI,这里几乎不能使用 lambda。