4

I have tried to make functions for turtle to make it extremely easy to draw shapes. The code looks like this:

import turtle as t

def square():
     tw = t.Screen()
     for i in range(4):
          t.forward(100)
          t.right(90)
     tw.exitonclick()
def triangle():
     tw = t.Screen()
     for i in range(3):
          t.forward(100)
          t.right(120)
     tw.exitonclick()
def star():
     tw = t.Screen()
     for i in range(5):
          t.forward(150)
          t.right(144)
     tw.exitonclick()

When I run this code in shell a Terminator error occurs:

>>> square()
>>> triangle()
Traceback (most recent call last):
  File "<pyshell#1>", line 1, in <module>
    triangle()
  File "C:\Users\Manop\Desktop\XENON\turtleg.py", line 11, in triangle
    t.forward(100)
  File "<string>", line 5, in forward
turtle.Terminator
>>> star()
>>> square()
Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module>
    square()
  File "C:\Users\Manop\Desktop\XENON\turtleg.py", line 5, in square
    t.forward(100)
  File "<string>", line 5, in forward
turtle.Terminator
>>> 

I can't understand what the problem is, because I even used exitonclick().

ggorlen
  • 44,755
  • 7
  • 76
  • 106
  • Minimal reproduction of a Terminator error on Python 3.10.2: `import turtle;turtle.exitonclick();turtle.done()`. The error is raised when calling turtle methods after closing the window with `done()`, `bye()`, `exitonclick()`, `mainloop()`, etc. Typically, only use exactly one of these calls at the very end of the application, then stop using turtle afterwards. – ggorlen Sep 21 '22 at 03:11

5 Answers5

5

Your turtle program is structured incorrectly. You needn't do:

tw = t.Screen()
...
tw.exitonclick()

in every function. Screen() only needs to be called once; exitonclick() should only ever be called once. Try this restructuring:

import turtle as t

def square():
    for i in range(4):
        t.forward(100)
        t.right(90)

def triangle():
    for i in range(3):
        t.forward(100)
        t.right(120)

def star():
    for i in range(5):
        t.forward(150)
        t.right(144)

t.penup()
t.goto(150, 150)
t.pendown()
square()

t.penup()
t.goto(-150, 150)
t.pendown()
triangle()

t.penup()
t.goto(150, -150)
t.pendown()
star()

screen = t.Screen()
screen.exitonclick()

If you want to execute the code interactively, that's fine too. Just drop everything after the function definitions, load it into Python interactively and do:

>>> star()

or whatever you want to run. You don't need the call to Screen() and the exitonclick() doesn't make sense when working interactively.

cdlane
  • 40,441
  • 5
  • 32
  • 81
  • Doesn't work (I have copy-pasted and run the code as it is). Clicking anywhere on he turtle screen -- even many times -- is just ignored. – Apostolos Apr 12 '18 at 21:35
  • 1
    @Apostolos, after drawing completes, clicking anywere on the screen exits the program cleanly (in Python3). You seem to be solving a different problem: being able to exit cleanly any time during the drawing process. I don't see anything in the OP's question that implies that desire. Though that is an interesting problem, if that's what he really wants. – cdlane Apr 13 '18 at 02:13
  • Yes, only when all drawing is completed and not anytime until then. This is not OK, esp. in case the drawing takes long. Please try my code below to see that you can exit anytime. – Apostolos Apr 17 '18 at 06:24
5

I had the same error while I was working on a school project. After some research on the turtle library I have found a variable called TurtleScreen._RUNNING, if this variable is set to True a turtle window opens, if not you get the turtle.Terminator error. Every time you close a turtle screen, TurtleScreen._RUNNING is automatically set to True, if you want to avoid that, you can simply write this line of code TurtleScreen._RUNNING = True (of course you need to import turtle before).

ori adereth
  • 71
  • 1
  • 3
  • This method isn't in the docs. Best not to mess with implementation details. Instead of a workaround by flipping an undocumented internal flag that could change at any time and might have unexpected side effects, it seems better to use `exitonclick` as it was intended, [as the last statement in the program](https://stackoverflow.com/a/45535795/6243352) that is the final exit. If OP is trying to pause until a click event occurs, there are better ways to do that. – ggorlen Aug 10 '22 at 15:02
1

Let the method screen.exitonclick() be the last statement in your code without indenting it.

You use this method when your using a Python IDE such as Pycharm, Spyder etc.

I don't know if you have heard of the method screen.mainloop()

This method enables you see the output of your code when you run it in a Python IDE.

Without this method, your output would appear in a flash.

I rewrote your code and here's mine

from turtle import Turtle

t=Turtle()

def square():
    t.up()
    t.setpos(-50,-50)
    t.down()
    for i in range(4):
        t.forward(100)
        t.right(90)

def triangle():
    t.up()
    t.setpos(50,50)
    t.down()
    for i in range(3):
        t.forward(100)
        t.right(120)

def star():
    t.up()
    t.setpos(-200,100)
    t.down()
    for i in range(5):
        t.forward(150)
        t.right(144)

square()
triangle()
star()
t.screen.exitonclick()

Here's the output output of my program

You can also check this excellent guide in Python turtle

1

When you interrupt the turtle drawing, it gets angry and produces "abnormal termination" error. Use a "running" flag to stop the process at any point:

from turtle import Turtle

t=Turtle()

def square():
    global running
    t.up()
    t.setpos(-50,-50)
    t.down()
    for i in range(4):
        if not running: break; # Check 'running' here
        t.forward(100)
        t.right(90)

def triangle():
    global running
    t.up()
    t.setpos(50,50)
    t.down()
    for i in range(3):
        if not running: break; # Check 'running' here
        t.forward(100)
        t.right(120)

def star():
    global running
    t.up()
    t.setpos(-200,100)
    t.down()
    for i in range(5):
        if not running: break; # Check 'running' here
        t.forward(150)
        t.right(144)

def stop(x,y): # x,y are dummy but they are requested
  global running
  running = False  # Disable running

t.screen.onclick(stop) # Set a function for 'running'

running = True  # Enable running

square()
triangle()
star()

I tested the above code. Termination was smooth at all times.

Apostolos
  • 3,115
  • 25
  • 28
0

This is because the turtle module (most reference implementations as of today) uses a class variable called _RUNNING. This becomes false during the exitonclick() method.

Changing your code to below should help to run in the way you want:

import turtle as t

def square():
    t.TurtleScreen._RUNNING=True
    tw = t.Screen()
    for i in range(4):
        t.forward(100)
        t.right(90)
    tw.exitonclick()

def triangle():
    t.TurtleScreen._RUNNING=True
    tw = t.Screen()
    for i in range(3):
        t.forward(100)
        t.right(120)
    tw.exitonclick()

def star():
    t.TurtleScreen._RUNNING=True
    tw = t.Screen()
    for i in range(5):
        t.forward(150)
        t.right(144)
    tw.exitonclick()
Flair
  • 2,609
  • 1
  • 29
  • 41
William
  • 464
  • 2
  • 16