Search code examples
pythontkintertreeviewttk

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:\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>'

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)))

Solution

  • When the event fires, tkinter will pass along an event object. You are trying to open that event object as if it were a file.

    Why is that? Let's start by rewriting your lambda as a proper function. Your lambda is the equivalent of this function:

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

    When the event fires, it does the equivalent of this:

    handle_event(event)
    

    Your script is given a single positional argument, event, which is assigned to the first keyword argument. Thus f is the same as event.

    The solution is to make sure your lambda accepts the event, which it can simply ignore:

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

    With the above, the event object will be associated with the event parameter, and your default value for f will be passed as f.