Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
240 views
in Technique[技术] by (71.8m points)

python - Tkinter / TTK - Prevent string to ButtonPress conversion

I'm writing a simple script that creates a ttk Treeview (that acts as a table) and, when you double-click it, it opens a file (with the path saved in the dictionary). However, when you double-click a row you'll get this error:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:UsersMaicolAppDataLocalProgramsPythonPython36lib	kinter\__init__.py",
line 1699, in __call__
    return self.func(*args)
  File "C:UsersMaicolDocumentsProjectsApp_WINDOWSSchool_Life_Diary
ote.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>'

The problem is this code:

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

that allows the double-clicking and opening of the file.

Here is the full Treeview code:

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)))
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The main issue is about creating a binding for the Treeview in the loop.

There is only one double click event that can be declared and triggered for the tree, not one by row, and here you are overriding it in each iteration.


This lambda pattern is known to declare commands for widgets inside a for/loop, and it works fine for this purpose:

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

But here you declare a default parameter f, and the lambda will be executed with an event argument given by the event binding, that's what you get in the exception : <ButtonPress event state=Mod1...

Anyway, we saw that this won't work in your case even if you fix the lambda with a second parameter to accept the event without replacing your default value f.


What i suggest is to use the values field of each row to store the information URIallegato" without displaying the column in the tree.

And then you can bind a generic event to the Treeview, by using focus() to get the selected item, and extract the value to get 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)

A lambda could hardly be used here if you want to check if there is an URI to open.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...