lig*_*ega 3 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()
Run Code Online (Sandbox Code Playgroud)
当我关闭窗口时,会出现以下错误消息。
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"
Run Code Online (Sandbox Code Playgroud)
我想知道如何避免此类错误消息。
有没有办法像使用来自 tkinter 模块的 Tk 类的“WM_DELETE_WINDOW”选项的“协议”方法一样?
是的,这确实可以通过注册一个函数(我称之为on_close,但您可以选择任何函数名称)来拦截窗口关闭事件来避免。
一个棘手的事情是这protocol是一个Tk类的方法。在非海龟tkinter使用中,您Tk自己创建对象作为顶级(或“根”)小部件。当我们使用turtle模块提供的小部件时,我们如何访问顶级小部件?它可以通过winfo_toplevel画布的方法获得(可以通过turtle模块或屏幕对象访问)。
您观察到的错误是由无限循环在窗口(以及画布)已经消失时尝试绘制内容引起的。所以下一个棘手的事情是,我们如何防止它尝试这样做?正如Apostolos对“如何处理 Tkinter 中的窗口关闭事件?”的回答所建议的那样,我们可以使用全局布尔标志。(就像 Apostolos,我称之为running。但是你可以选择任何对你有意义的名字。)这样,我们的循环不再是无限的,它是一个条件循环。因为窗口可能在三个海龟运动之间关闭,我也检查那里的标志:
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)
Run Code Online (Sandbox Code Playgroud)
在我的电脑上,它也可以在没有两个错误信息的情况下工作
if not running:
break
Run Code Online (Sandbox Code Playgroud)
部分,但这可能只是幸运的时机,所以我不会依赖它。(除非有人可以解释为什么这应该总是足够的。)
注意:我不需要调用root.destroy()in on_close,因为无论如何循环是程序中最后运行的东西。(请注意,我也没有调用mainloop())所以当我们跳出循环,或者循环因为条件不再为真而结束时,程序结束并关闭窗口。