【问题标题】:Using turtle module exitonclick()使用海龟模块 exitonclick()
【发布时间】:2017-01-09 13:08:59
【问题描述】:

我的代码应该在第一部分之后关闭turtle.screen,然后启动另一个屏幕并执行第二部分。但它没有按预期工作。

import turtle

ws = turtle.Screen()
tod_1 = turtle.Turtle()
tod_1.color("red", "green")
tod_1.begin_fill()
for i in range(3):
    tod_1.forward(50)
    tod_1.left(360 / 3)
tod_1.end_fill()
ws.exitonclick()

input("go'press any thing' ")

ws = turtle.Screen()
tod_2 = turtle.Turtle()
tod_2.color("red", "green")
tod_2.begin_fill()
for i in range(6):
    tod_2.forward(50)
    tod_2.left(360 / 6)
tod_2.end_fill()
ws.exitonclick()

第一部分工作正常,但我在 input() 之后得到了这个:

go'press any thing' 
Traceback (most recent call last):
  File "test2.py", line 16, in <module>
    tod_2 = turtle.Turtle()
  File "C:\Users\itt\AppData\Local\Programs\Python\Python36-32\lib\turtle.py", line 3816, in __init__
    visible=visible)
  File "C:\Users\itt\AppData\Local\Programs\Python\Python36-32\lib\turtle.py", line 2557, in __init__
    self._update()
  File "C:\Users\itt\AppData\Local\Programs\Python\Python36-32\lib\turtle.py", line 2660, in _update
    self._update_data()
  File "C:\Users\itt\AppData\Local\Programs\Python\Python36-32\lib\turtle.py", line 2646, in _update_data
    self.screen._incrementudc()
  File "C:\Users\itt\AppData\Local\Programs\Python\Python36-32\lib\turtle.py", line 1292, in _incrementudc
    raise Terminator
turtle.Terminator

我尝试使用以下方法清除所有变量:

import sys
sys.modules[__name__].__dict__.clear()

然后再次导入 turtle 并执行 sec。部分,但没有成功。

【问题讨论】:

  • 你得到了什么?你在 IDLE 中运行它吗?
  • 它是停止所有执行还是以另一种意想不到的方式表现? “未按预期工作”并不能告诉我们您看到了什么。
  • 它执行第一部分没有问题
  • 您的代码在 Python 2.6 中可以正常工作(使用 raw_input 而不是 input),但在 Python 3.6 上不行。
  • 为什么要关闭 Turtle 屏幕然后打开一个新屏幕?为什么不直接重置原始屏幕?

标签: python python-3.x turtle-graphics


【解决方案1】:

似乎当turtle 被导入时,它创建了许多对象,exitonclick() 删除了所有对象——不仅仅是Screen()exitonclick() 是为了结束程序而创建的。

但是您可以使用oscreenclick(function_name) 将功能分配给鼠标单击,这将清除屏幕并绘制下一个对象。 onscreenclick 执行带有两个参数的函数 - 点击位置 - 所以函数必须接收此信息。

import turtle

# --- functions ---

def second(x, y): 
    # clear screen
    tod.reset()

    tod.color("red", "green")
    tod.begin_fill()
    for i in range(6):
        tod.forward(50)
        tod.left(360 / 6)
        tod.end_fill()

    # run another function on click
    #turtle.onscreenclick(third)

    # end program on click 
    turtle.exitonclick()

# --- main ---

tod = turtle.Turtle()

tod.color("red", "green")
tod.begin_fill()
for i in range(3):
    tod.forward(50)
    tod.left(360 / 3)
    tod.end_fill()

# assign function to click on screen
turtle.onscreenclick(second)

# you need it to - it checks if you clicked (and does othere things)
turtle.mainloop()

编辑:如果您必须删除窗口并再次显示,则可以使用tod._screen._root 访问使用tkinter 的主窗口,您可以隐藏/显示它

tod._screen._root.iconify()   # hide
input("Press Enter: ")
tod._screen._root.deiconify() # show again

工作示例:

#!/usr/bin/env python3

import turtle

# --- functions ---

def stop(callback):

    #tod._screen._root.attributes("-topmost", False)

    tod._screen._root.iconify()
    # upper Y in text means that it will be default answer if you press only Enter
    answer = input("Show more images? [Y/n]: ").strip().lower()
    if not answer: # empty string treat as `Y`
        answer = 'y'
    tod._screen._root.deiconify()

    # problem with moving window above other windows
    #tod._screen._root.lift()
    tod._screen._root.attributes("-topmost", True)
    #tod._screen._root.update()

    if answer == 'y':
        callback()
    else:
        #turtle.exitonclick()
        # or
        turtle.bye()

def first(x=0, y=0):
    tod.color("red", "green")
    tod.begin_fill()
    for i in range(3):
        tod.forward(50)
        tod.left(360 / 3)
        tod.end_fill()

    # assign function to click on screen
    turtle.onscreenclick(lambda x,y:stop(second))

def second(x=0, y=0):
    # clear screen
    tod.reset()

    tod.color("red", "green")
    tod.begin_fill()
    for i in range(6):
        tod.forward(50)
        tod.left(360 / 6)
        tod.end_fill()

    # assign function to click on screen
    turtle.onscreenclick(lambda x,y:stop(third))

def third(x=0, y=0):
    # clear screen
    tod.reset()

    tod.color("red", "green")
    tod.begin_fill()
    for i in range(12):
        tod.forward(50)
        tod.left(360 / 12)
        tod.end_fill()

    # end program on click
    turtle.exitonclick()

# --- main ---

tod = turtle.Turtle()

first()

# you need it to - it checks if you clicked (and does othere things)
turtle.mainloop()

但是你可以使用tkinter 和它的消息框来代替input()

answer = tkinter.messagebox.askyesno('More?', "Show more images?")

工作示例:

#!/usr/bin/env python3

import turtle
import tkinter.messagebox

# --- functions ---

def stop(callback):

    answer = tkinter.messagebox.askyesno('More?', "Show more images?")
    print('answer:', answer)

    if answer:
        callback()
    else:
        #turtle.exitonclick()
        # or
        turtle.bye()

def first(x=0, y=0):
    tod.color("red", "green")
    tod.begin_fill()
    for i in range(3):
        tod.forward(50)
        tod.left(360 / 3)
        tod.end_fill()

    # assign function to click on screen
    turtle.onscreenclick(lambda x,y:stop(second))

def second(x=0, y=0):
    # clear screen
    tod.reset()

    tod.color("red", "green")
    tod.begin_fill()
    for i in range(6):
        tod.forward(50)
        tod.left(360 / 6)
        tod.end_fill()

    # assign function to click on screen
    turtle.onscreenclick(lambda x,y:stop(third))

def third(x=0, y=0):
    # clear screen
    tod.reset()

    tod.color("red", "green")
    tod.begin_fill()
    for i in range(12):
        tod.forward(50)
        tod.left(360 / 12)
        tod.end_fill()

    # end program on click
    turtle.exitonclick()

# --- main ---

tod = turtle.Turtle()

first()

# you need it to - it checks if you clicked (and does othere things)
turtle.mainloop()

编辑:我检查了turtle的源代码,看来你可以设置

turtle.TurtleScreen._RUNNING = True

exitonclick() 之后再次运行turtle

在有和没有turtle.TurtleScreen._RUNNING = True的情况下试试这个代码

import turtle

turtle.goto(0,50)
turtle.exitonclick()

turtle.TurtleScreen._RUNNING = True

turtle.goto(50,150)
turtle.exitonclick()

turtle.TurtleScreen._RUNNING = True

但也许对于更复杂的代码它不会工作,因为exitonclick() 做了其他事情 - 由exitonclick() 执行的原始函数

def _destroy(self):
    root = self._root
    if root is _Screen._root:
        Turtle._pen = None
        Turtle._screen = None
        _Screen._root = None
        _Screen._canvas = None
    TurtleScreen._RUNNING = False
    root.destroy()

【讨论】:

  • 没有办法退出屏幕再重新打开吗?
  • 没有办法做到这一点。但是turtle使用tkinter,你可以访问它和主窗口tod._screen._root并隐藏它tod._screen._root.iconify()并再次显示tod._screen._root.deiconify()
  • tod._screen._root.iconify()tkinter.messagebox.askyesno('More?', "Show more images?")查看新代码
  • 我尝试使用:sys.modules[__name__].__dict__.clear() 清除所有变量并再次使用import turtle,但得到相同的结果
  • 尝试turtle.TurtleScreen._RUNNING = True - 请参阅答案中的示例。
【解决方案2】:

我刚刚在您的代码中添加了一行,以便重新导入海龟类,并在下一次初始化中将类变量turtle.TurtleScreen._RUNNING 设置为true。

工作代码:

import importlib
import turtle

ws = turtle.Screen()
tod_1 = turtle.Turtle()
tod_1.color("red", "green")
tod_1.begin_fill()
for i in range(3):
    tod_1.forward(50)
    tod_1.left(360 / 3)
tod_1.end_fill()
ws.exitonclick()

importlib.reload(turtle)
input("go'press any thing' ")

ws = turtle.Screen()
tod_2 = turtle.Turtle()
tod_2.color("red", "green")
tod_2.begin_fill()
for i in range(6):
    tod_2.forward(50)
    tod_2.left(360 / 6)
tod_2.end_fill()
ws.exitonclick()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多