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
,它被分配给第一个关键字参数。因此 f
与 event
.
相同
解决方案是确保您的 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。
我正在编写一个简单的脚本来创建一个 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
,它被分配给第一个关键字参数。因此 f
与 event
.
解决方案是确保您的 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。