如何检测 python Turtle 图形中的 X(关闭)按钮?
How to detect X (close) button in python Turtle graphics?
当我在 运行 Turtle 图形中无限循环绘图时单击 X(关闭)按钮时,会出现一些错误消息。
这是一个例子:
import turtle
wn = turtle.Screen()
tess = turtle.Turtle()
while True:
tess.forward(50)
tess.left(120)
tess.forward(50)
wn.mainloop()
当我关闭 window 时,会出现以下错误消息。
Traceback (most recent call last):
File "/Users/user/Downloads/test.py", line 8, in <module>
tess.forward(50)
File "/Users/user/anaconda3/lib/python3.6/turtle.py", line 1637, in forward
self._go(distance)
File "/Users/user/anaconda3/lib/python3.6/turtle.py", line 1605, in _go
self._goto(ende)
File "/Users/user/anaconda3/lib/python3.6/turtle.py", line 3178, in _goto
self._pencolor, self._pensize, top)
File "/Users/user/anaconda3/lib/python3.6/turtle.py", line 545, in _drawline
self.cv.coords(lineitem, *cl)
File "<string>", line 1, in coords
File "/Users/user/anaconda3/lib/python3.6/tkinter/__init__.py", line 2463, in coords
self.tk.call((self._w, 'coords') + args))]
_tkinter.TclError: invalid command name ".!canvas"
我想知道如何避免此类错误消息。
有什么方法可以使用 "protocol" 方法和 tkinter 模块中 Tk class 的 "WM_DELETE_WINDOW" 选项吗?
是的,这确实可以通过注册一个函数(我叫它on_close
,但你可以选择任何函数名称)来拦截window关闭事件来避免。
一个棘手的事情是 protocol
是 Tk
class 的一个方法。在非 turtle tkinter
用法中,您自己创建 Tk
对象作为顶级(或 "root")小部件。当我们使用 turtle
模块提供的小部件时,我们如何访问顶级小部件? 它可以通过 winfo_toplevel
canvas 的方法(可以通过 turtle
模块或屏幕对象访问)。
您观察到的错误是由于无限循环试图在 window(以及随之而来的 canvas)已经消失的情况下绘制东西造成的。所以下一个棘手的事情是,我们怎样才能阻止它尝试呢?根据 Apostolos' answer 到 "How do I handle the window close event in Tkinter?" 的建议,我们可以使用全局布尔标志。 (就像 Apostolos,我称它为 running
。但你可以选择任何对你有意义的名称。)这样,我们的循环就不再那么无限了,它是一个条件循环。因为 window 可能在三个海龟移动之间关闭,所以我也检查那里的标志:
import turtle
wn = turtle.Screen()
canvas = wn.getcanvas() # or, equivalently: turtle.getcanvas()
root = canvas.winfo_toplevel()
tess = turtle.Turtle()
def on_close():
global running
running = False
root.protocol("WM_DELETE_WINDOW", on_close)
running = True
while running:
tess.forward(50)
if not running:
break
tess.left(120)
if not running:
break
tess.forward(50)
在我的电脑上,如果没有这两个
,它也可以正常工作而不会出现错误消息
if not running:
break
部分,但这可能只是幸运的时机,所以我不会依赖它。 (除非有人能解释为什么这就足够了。)
注意:我不需要在on_close
中调用root.destroy()
,因为循环是运行中的最后一件事程序,无论如何。 (注意我也不调用mainloop()
)所以当我们跳出循环时,或者循环结束是因为它条件不再为真,程序结束并关闭 window.
当我在 运行 Turtle 图形中无限循环绘图时单击 X(关闭)按钮时,会出现一些错误消息。
这是一个例子:
import turtle
wn = turtle.Screen()
tess = turtle.Turtle()
while True:
tess.forward(50)
tess.left(120)
tess.forward(50)
wn.mainloop()
当我关闭 window 时,会出现以下错误消息。
Traceback (most recent call last):
File "/Users/user/Downloads/test.py", line 8, in <module>
tess.forward(50)
File "/Users/user/anaconda3/lib/python3.6/turtle.py", line 1637, in forward
self._go(distance)
File "/Users/user/anaconda3/lib/python3.6/turtle.py", line 1605, in _go
self._goto(ende)
File "/Users/user/anaconda3/lib/python3.6/turtle.py", line 3178, in _goto
self._pencolor, self._pensize, top)
File "/Users/user/anaconda3/lib/python3.6/turtle.py", line 545, in _drawline
self.cv.coords(lineitem, *cl)
File "<string>", line 1, in coords
File "/Users/user/anaconda3/lib/python3.6/tkinter/__init__.py", line 2463, in coords
self.tk.call((self._w, 'coords') + args))]
_tkinter.TclError: invalid command name ".!canvas"
我想知道如何避免此类错误消息。
有什么方法可以使用 "protocol" 方法和 tkinter 模块中 Tk class 的 "WM_DELETE_WINDOW" 选项吗?
是的,这确实可以通过注册一个函数(我叫它on_close
,但你可以选择任何函数名称)来拦截window关闭事件来避免。
一个棘手的事情是 protocol
是 Tk
class 的一个方法。在非 turtle tkinter
用法中,您自己创建 Tk
对象作为顶级(或 "root")小部件。当我们使用 turtle
模块提供的小部件时,我们如何访问顶级小部件? 它可以通过 winfo_toplevel
canvas 的方法(可以通过 turtle
模块或屏幕对象访问)。
您观察到的错误是由于无限循环试图在 window(以及随之而来的 canvas)已经消失的情况下绘制东西造成的。所以下一个棘手的事情是,我们怎样才能阻止它尝试呢?根据 Apostolos' answer 到 "How do I handle the window close event in Tkinter?" 的建议,我们可以使用全局布尔标志。 (就像 Apostolos,我称它为 running
。但你可以选择任何对你有意义的名称。)这样,我们的循环就不再那么无限了,它是一个条件循环。因为 window 可能在三个海龟移动之间关闭,所以我也检查那里的标志:
import turtle
wn = turtle.Screen()
canvas = wn.getcanvas() # or, equivalently: turtle.getcanvas()
root = canvas.winfo_toplevel()
tess = turtle.Turtle()
def on_close():
global running
running = False
root.protocol("WM_DELETE_WINDOW", on_close)
running = True
while running:
tess.forward(50)
if not running:
break
tess.left(120)
if not running:
break
tess.forward(50)
在我的电脑上,如果没有这两个
,它也可以正常工作而不会出现错误消息 if not running:
break
部分,但这可能只是幸运的时机,所以我不会依赖它。 (除非有人能解释为什么这就足够了。)
注意:我不需要在on_close
中调用root.destroy()
,因为循环是运行中的最后一件事程序,无论如何。 (注意我也不调用mainloop()
)所以当我们跳出循环时,或者循环结束是因为它条件不再为真,程序结束并关闭 window.