Python tkinter.ttk 下拉框退出时抛出异常
在我的Python 3.3代码中,我使用了ttk库的一些下拉框,它们运行得很好。但是,如果我使用了其中的任何一个,下关闭窗口时点击X按钮就会出现一个异常。这是一个例子:
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()
如果在没有选择任何值的情况下关闭窗口,一切都正常。但如果在选择了一个值后再关闭窗口,就会退出,但在Python命令行中会打印出以下错误信息:
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)
我该如何解决这个问题呢?如果你能提供任何帮助,我将非常感激。
更新 1:
我的Python版本是v3.3,我使用的是捆绑的Tcl/Tk和Tkinter。我尝试了x86和x64两个版本。
更新 2:
这个异常只有在我从命令行运行我的脚本时才会出现。在Idle中不会显示。
3 个回答
我也遇到过同样的问题,不过我用了一种方法解决了它。你可以试试把
a=Tk()
换成
a=Toplevel()
。我知道我说这个有点晚,但在我的情况下,这个方法确实解决了问题。
我最近也遇到了类似的问题。错误信息完全一样。 我通过在退出的方法里加了一个 a.quit() 来解决这个问题。(在此之前,这个方法里只有 a.destroy()) 也许你已经解决了这个问题。但schlenk的回答对我来说效果不太好。所以我希望我的回答能给这个问题提供另一个线索。
这是一个关于Tcl/Tk绑定代码在ttk中出现的问题。
这个问题在典型的Python Tkinter安装中的tcl/tk8.5/ttk/entry.tcl文件里有个注释提到:
## 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.
简单来说,当你使用after
这个方法来延迟调用某个功能时,如果最后一个窗口关闭了,Tk也就结束了,这个延迟调用就无法取消,也无法完成,因为相关的功能' winfo'已经不存在了。当你运行IDLE的时候,窗口还在,所以Tk没有结束,这个错误就不会出现。
你可以通过在WM_DELETE_WINDOW
消息上绑定一个操作来解决这个问题,这样可以停止重复的计时器。对应的代码是(在Tcl/Tk中):
proc shutdown_ttk_repeat {args} {
::ttk::CancelRepeat
}
wm protocol . WM_DELETE_WINDOW shutdown_ttk_repeat
在Tkinter中,应该也能以类似的方式工作:
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()