Using turtle module exitonclick()

最后都变了- 提交于 2019-12-12 06:31:51

问题


My code should close the turtle.screen after first part then start another screen and do the second part. but there it is not working as intend.

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()

the first part works fine but I get this after the 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

I tried to clear all variables using:

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

then import turtle again and do the sec. part, but without success.


回答1:


It seems that when turtle is imported it creates many objects and exitonclick() removes all of them - not only Screen(). exitonclick() was created to end program.

But you can use oscreenclick(function_name) to assign function to mouse click which will clear screen and draw next object. onscreenclick execute function with two arguments - position of click - so function has to receive this information.

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()

EDIT: if you have to remove window and show again than you can use tod._screen._root to get access to main window which use tkinter, and you can hide/show it

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

Working example:

#!/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()

But instead of input() you can use tkinter and its messageboxes

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

Working example:

#!/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()

EDIT: I checked source code of turtle and it seems that you can set

turtle.TurtleScreen._RUNNING = True

to run turtle again after exitonclick()

Try this code with and without 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

But maybe with more complex code it will not work because exitonclick() does other things - oryginal function which is executed by 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()


来源:https://stackoverflow.com/questions/41548813/using-turtle-module-exitonclick

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!