Question

In my Python 3.3 code I use some comboboxes from the ttk library, and they function fine, but if I use any of them, I got an exception when I close the window with the X button. This is an example:

from tkinter import Tk,Label,Button
from tkinter import ttk
from tkinter.ttk import Combobox

def cbox_do(event):
    'Used for cbox.'
    clabel.config(text=cbox.get())

a = Tk()
cbox = Combobox(a, value=('Luke','Biggs','Wedge'), takefocus=0)
cbox.bind("<<ComboboxSelected>>", cbox_do)
cbox.pack()
clabel = Label(a)
clabel.pack()
a.mainloop()

If you close it without selecting a value, everithing is fine, but try to close it after a value was selected, it exits but prints the following error into the python command line:

can't invoke "winfo" command:  application has been destroyed
    while executing
"winfo exists $w"
    (procedure "ttk::entry::AutoScroll" line 3)
    invoked from within
"ttk::entry::AutoScroll .41024560"
    (in namespace inscope "::" script line 1)
    invoked from within
"::namespace inscope :: {ttk::entry::AutoScroll .41024560}"
    ("uplevel" body line 1)
    invoked from within
"uplevel #0 $Repeat(script)"
    (procedure "ttk::Repeat" line 3)
    invoked from within
"ttk::Repeat"
    ("after" script)

How could I fix it? I would be grateful for any help you could provide.

Update 1: My Python version is v3.3, I use the bundled Tcl/Tk and Tkinter. I tried both the x86 and x64 versions.

Update 2: The exception is thrown only if I run my script from command line. It wont show up in Idle.

Was it helpful?

Solution

This is a problem with the Tcl/Tk binding code used in ttk.

The problem is hinted at by a comment in tcl/tk8.5/ttk/entry.tcl file in a typical python Tkinter installation:

## AutoScroll
#   Called repeatedly when the mouse is outside an entry window
#   with Button 1 down.  Scroll the window left or right,
#   depending on where the mouse is, and extend the selection
#   according to the current selection mode.
#
# TODO: AutoScroll should repeat faster (50ms) than normal autorepeat.
# TODO: Need a way for Repeat scripts to cancel themselves.

Basically a deferred call with after isn't canceled and cannot complete anymore after the last window gets closed and Tk is finalized, because the procedure/function 'winfo' no longer exists. When you run IDLE, there still is a window, so Tk does not get finalized and the error does not show up.

You can fix this with a binding on the WM_DELETE_WINDOW message, which stops the repeat timer. The code for that would be (in Tcl/Tk):

proc shutdown_ttk_repeat {args} {
    ::ttk::CancelRepeat
}
wm protocol . WM_DELETE_WINDOW shutdown_ttk_repeat

For Tkinter it should work in a similar way:

from tkinter import Tk,Label,Button
from tkinter import ttk
from tkinter.ttk import Combobox

def cbox_do(event):
    'Used for cbox.'
    clabel.config(text=cbox.get())

a = Tk()
cbox = Combobox(a, value=('Luke','Biggs','Wedge'), takefocus=0)
cbox.bind("<<ComboboxSelected>>", cbox_do)
cbox.pack()
clabel = Label(a)
clabel.pack()

def shutdown_ttk_repeat():
    a.eval('::ttk::CancelRepeat')
    a.destroy()

a.protocol("WM_DELETE_WINDOW", shutdown_ttk_repeat)
a.mainloop()

OTHER TIPS

I've encountered a similar problem recently. The error message is exactly the same. I solved that by adding a a.quit() in an Exit method. (before that there was only a.destroy() in this method) Maybe you have already solved this question. But schlenk's answer doesn't work well on me. So I hope my answer can give another clue to such question

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top