如何检测python Turtle图形中的X(关闭)按钮?

时间:2018-06-02 08:01:07

标签: 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()

当我关闭窗口时,会显示以下错误消息。

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"

我想知道如何避免这样的错误消息。

是否有任何方法可以使用tkinter模块中Tk类的“WM_DELETE_WINDOW”选项使用“protocol”方法?

1 个答案:

答案 0 :(得分:2)

是的,通过注册一个函数(我称之为on_close,但您可以选择任何函数名称)来拦截窗口关闭事件,确实可以避免这种情况。

一个棘手的问题是protocolTk类的一种方法。在非龟[{1}}用法中,您自己创建tkinter对象作为顶级(或#34; root&#34;)小部件。当我们使用Tk模块提供的小部件时,我们如何访问顶级小部件?它可以通过 turtle方法获得画布(可以通过winfo_toplevel模块或屏幕对象访问)。

你观察到的错误是由于无限循环试图在窗口(以及它,画布)已经消失时绘制东西引起的。所以下一个棘手的问题是,我们怎样才能阻止它尝试呢?正如Apostolos' answer建议的那样,#34;如何处理Tkinter中的窗口关闭事件?&#34;,我们可以使用全局布尔标志。 (就像Apostolos一样,我称之为turtle。但你可以选择任何对你有意义的名字。)有了它,我们的循环就不再那么无限了,它是一个条件循环。因为窗口可能在三个龟运动之间关闭,我也检查那里的旗帜:

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)

部分,但这可能只是幸运时间,所以我不会依赖它。 (除非有人能解释为什么这应该总是足够的。)

注意:我不需要在 if not running: break 中调用root.destroy(),因为无论如何,循环是程序中运行的最后一件事。 (注意我也不要调用on_close )所以当我们突破循环,或循环结束因为它的状况不再是的,程序完成并关闭窗口。