A Key press event in Turtle is causing other key events to stop working

Viewed 358

I am trying to make a very basic version of MS-Paint using Turtle. I have a few key and mouse events but one key event, i.e. the turtle.numinput() for turtle.width, is causing my other key events to stop working after I type the desired integer for my pen width. The mouse events continue to work though.

The turtle.numinput() is asked first when the turtle window opens up but the other key events work fine afterwards. It's after I press the required key to change my pen width that the other key events stop working.

I tried changing the sequence a bit and even copied the width piece of the code to another python file based around Turtle to check. I got the same problem there as well.

I have no idea what's causing this and would really appreciate the help

import turtle, random

wn = turtle.Screen()
wn.screensize(600, 600)

paint = turtle.Turtle('turtle')
colors = ['Red', 'Yellow', 'Green', 'Blue']
paint.width(turtle.numinput('width', 'Type line size (in numbers): '))
paint.speed(0)

# Arrow-Keys control function
def up():
    paint.setheading(90)
    paint.forward(100)

def down():
    paint.setheading(270)
    paint.forward(100)

def left():
    paint.setheading(180)
    paint.forward(100)

def right():
    paint.setheading(0)
    paint.forward(100)

# Color change
def colorChange():
    paint.color(random.choice(colors))

# Size change
def size():
    paint.width(turtle.numinput('width', 'Type line size (in numbers): '))

# Mouse Control (Clear + Drag) function
def clearScreen(x, y):
    paint.clear()

def dragging(x, y):
    paint.ondrag(None)
    paint.setheading(paint.towards(x, y))
    paint.goto(x, y)
    paint.ondrag(dragging)

# Shapes with random size
def square():
    for i in range(4):
        paint.forward(50)
        paint.left(90)

def circle():
    paint.circle(random.randrange(50, 100))

def rectangle():
    for i in range(2):
        paint.forward(50)
        paint.left(90)
        paint.forward(100)
        paint.left(90)

turtle.listen()

# Key-events

turtle.onkey(up, 'Up')
turtle.onkey(down, 'Down')
turtle.onkey(left, 'Left')
turtle.onkey(right, 'Right')

turtle.onkey(size, 'q')

turtle.onkey(colorChange, 'c')

# Mouse-events
turtle.onscreenclick(clearScreen, 3)
paint.ondrag(dragging)

# Shape-events
turtle.onkey(square, 's')
turtle.onkey(circle, 'o')
turtle.onkey(rectangle, 'r')

turtle.mainloop()
2 Answers

You might want to replace turtle.numinput() with plain input(), it takes input from the terminal and not from the actual module, which allows all key actions to take place as normal

Calls to numinput() (and textinput()) undo what listen() does, as the pop up input window has to become the active listener. The fix is to redo your listen() calls after each numinput() (and textinput()) call.

Below is my rework of your code with this fix and some style tweaks:

from turtle import Screen, Turtle
from random import choice, randrange

COLORS = ['Red', 'Yellow', 'Green', 'Blue']

# Arrow-Keys control function
def up():
    paint.setheading(90)
    paint.forward(100)

def down():
    paint.setheading(270)
    paint.forward(100)

def left():
    paint.setheading(180)
    paint.forward(100)

def right():
    paint.setheading(0)
    paint.forward(100)

# Color change
def colorChange():
    paint.color(choice(COLORS))

# Size change
def size():
    paint.width(screen.numinput("width", "Type line size (in numbers):"))
    screen.listen()

# Mouse Control (Clear + Drag) function
def clearScreen(x, y):
    paint.clear()

def dragging(x, y):
    paint.ondrag(None)
    paint.setheading(paint.towards(x, y))
    paint.goto(x, y)
    paint.ondrag(dragging)

# Shapes with random size
def square():
    for _ in range(4):
        paint.forward(50)
        paint.left(90)

def circle():
    paint.circle(randrange(50, 100))

def rectangle():
    for _ in range(2):
        paint.forward(50)
        paint.left(90)
        paint.forward(100)
        paint.left(90)

screen = Screen()
screen.screensize(600, 600)

paint = Turtle('turtle')
paint.width(screen.numinput("width", "Type line size (in numbers):"))
paint.speed('fastest')

# Key-events

screen.onkey(up, 'Up')
screen.onkey(down, 'Down')
screen.onkey(left, 'Left')
screen.onkey(right, 'Right')

screen.onkey(size, 'q')
screen.onkey(colorChange, 'c')

# Shape-events
screen.onkey(square, 's')
screen.onkey(circle, 'o')
screen.onkey(rectangle, 'r')

screen.listen()

# Mouse-events
screen.onclick(clearScreen, 3)
paint.ondrag(dragging)

screen.mainloop()
Related