How do I get user input in a turtle window? - python

I'm doing an assignment for school and would like to know how to collect user input directly from the turtle window rather than from the console. Is there the capacity for buttons in turtle or, if not, click events for certain areas so an area of the screen can act as a button?

User input can be obtained using the two graphic input methods that the turtle module provides:
textinput(title, prompt)
numinput(title, prompt, default=None, minval=None, maxval=None)
These are designed to help prevent some of the errors that console style input needs to trap. These were introduced in Python 3 and are not available in Python 2 turtle. However there are tkinter equivalents you can invoke from Python 2 when running turtle -- search SO for examples.
If you want a graphic button, my recommendation is you throw a turtle, or two, at the problem to become the button. Size, shape and color the turtle appropriately and then add an onclick() handler onto the turtle, not the screen, so that you can then click on your button to invoke an action:
from turtle import Turtle, mainloop
BUTTON_SIZE = 60
CURSOR_SIZE = 20
FONT_SIZE = 18
FONT = ('Arial', FONT_SIZE, 'bold')
STATES = (('red', 'OFF'), ('green', 'ON'))
INITIAL_STATE = STATES[0]
def toggle_power(x, y):
color, state = STATES[button.fillcolor() == 'red']
button.fillcolor(color)
marker.undo()
marker.write(state, align='center', font=FONT)
color, state = INITIAL_STATE
button = Turtle('circle')
button.shapesize(BUTTON_SIZE / CURSOR_SIZE, outline=2)
button.color('black', color)
button.penup()
# button.goto(-200, 200) # move the button into position
marker = Turtle(visible=False)
marker.penup()
marker.goto(button.xcor(), button.ycor() - BUTTON_SIZE/2 - FONT_SIZE - 2)
marker.write(state, align='center', font=FONT)
button.onclick(toggle_power)
mainloop()
The above button logic should work in either Python 3 or Python 2.

x = screen.textinput(title="level", prompt="Which level do you want to play? Type beginner, intermediate, pro")

Related

turtle.onclick lagging 1 cycle behind

When creating a turtle onclick event my clicks lags 1 click behind.
In my example I have two buttons that adds or subtracts 1 from a value, when I click one of the buttons it does the action of the last button I pushed, not the one I just clicked.
Example:
My number is 3.
Start program.
Click "+" -> nothing happens.
Click "+" -> number becomes 4.
Click "-" -> number becomes 5.
Click somewhere blank -> number becomes 4.
Click "+" -> nothing happens.
Click somewhere blank -> number becomes 5.
Example code.
import turtle
num = 3
turtle.setup(400,500)
wn = turtle.Screen()
wn.title("None")
wn.bgcolor("black")
# Functions for what happens clicking the minus or plus button
def num_minus(xcor, ycor):
global num
if num > 1:
num = num-1
num_disp.clear()
num_disp.write("{}".format(num), align="center", font=("Arial", 26, "normal"))
print(num)
def num_plus(xcor, ycor):
global num
if num < 9:
num = num+1
num_disp.clear()
num_disp.write("{}".format(num), align="center", font=("Arial", 26, "normal"))
print(num)
# Creating minus button, left of number
minus_btn = turtle.Turtle()
minus_btn.penup()
minus_btn.color("gray")
minus_btn.shape("square")
minus_btn.goto(-30, 0)
minus_btn.onclick(num_minus)
# Creatig plus button, right of number
plus_btn = turtle.Turtle()
plus_btn.penup()
plus_btn.color("gray")
plus_btn.shape("square")
plus_btn.goto(30, 0)
plus_btn.onclick(num_plus)
# Displays the number
num_disp = turtle.Turtle()
num_disp.penup()
num_disp.color("red")
num_disp.goto(0, -20)
num_disp.write("{}".format(num), align="center", font=("Arial", 26, "normal"))
num_disp.ht()
wn.listen()
wn.mainloop()
Why are my clicks 1 click behind, and how do I fix this?
I was not able to reproduce the errant behavior you describe. Regardless, here's some possibilities to consider:
On some systems, the turtle window does not come up as the key window and you need to click on it once (anywhere) to have it receive events. You should be able to click between the turtle window and another window on your screen to see how the windows visually change as they gain, and lose, key status. If your window needs to be clicked first to receive events, then you may be miscounting that click as a button click.
Your event handlers are open to receive a new event while they are still processing a previous event. They should be disabled until they are ready for a new event to keep events from interrupting one another and messing with your count.
You instruct the turtle window to listen() to keyboard events which are not used in this interface, so don't turn that on.
Below is my rework of your code to address some of the above and restyle it -- see if it fixes any of your issues or not:
from turtle import Screen, Turtle
FONT_SIZE = 26
FONT = ('Arial', FONT_SIZE, 'normal')
number = 3
# Functions for what happens when clicking the minus or plus button
def number_minus(x, y):
global number
minus_button.onclick(None) # disable handler inside handler
if number > 1:
number -= 1
number_display.clear()
number_display.write(number, align='center', font=FONT)
minus_button.onclick(number_minus) # reenable handler on exit
def number_plus(x, y):
global number
plus_button.onclick(None)
if number < 9:
number += 1
number_display.clear()
number_display.write(number, align='center', font=FONT)
plus_button.onclick(number_plus)
screen = Screen()
screen.setup(400, 500)
screen.bgcolor('black')
# Displays the number
number_display = Turtle()
number_display.hideturtle()
number_display.color('red')
number_display.penup()
number_display.sety(-FONT_SIZE/2)
number_display.write(number, align='center', font=FONT)
# Creating minus button, left of number
minus_button = Turtle()
minus_button.shape('triangle')
minus_button.color('gray')
minus_button.left(30)
minus_button.penup()
minus_button.setx(-30)
minus_button.onclick(number_minus)
# Creatig plus button, right of number
plus_button = Turtle()
plus_button.shape('triangle')
plus_button.color('gray')
plus_button.right(30)
plus_button.penup()
plus_button.setx(30)
plus_button.onclick(number_plus)
screen.mainloop()

Turtle colour doesn't change with variable and list

So this is my code right now and the problem should be somwehere between Line 18 and 37. What I want to do is that when the user clicks on the top left turtle, it changes to the next colour. The turtle in the top left is only optical and has no other function than telling the user where to click (at least that's the idea). The problem is that it doesn't do that and I don't really get why
import turtle
from turtle import *
# def on_click_handler(x,y):
# print("Clicked: " , [x,y])
# t1.goto(x,y)
sc = Screen()
sc.setup(400, 400, 10, 10)
sc.setworldcoordinates(-300, -300, 300, 300)
# sc.onscreenclick(on_click_handler)
t1 = Turtle("turtle")
t1.shape("circle")
t1.shapesize(0.25, 0.25)
t1.speed(-1)
#changing turtle colour
tcolour = Turtle("turtle")
tcolour.penup()
tcolour.shape("square")
tcolour.shapesize(1, 1.5)
tcolour.setpos(-275, 285)
colour_list = ["#000000", "#0101DF", "#04B404", "#FF0000", "#FF8000", "B40486"] #black, blue, green, red, orange, purple
n = 0
def colourchange(x, y):
if (x < -275 and x > -300 and y > 284 and y < 300):
global n
n += 1
turtle.onscreenclick(colourchange, 1)
turtle.listen()
t1.color(colour_list[0+n])
def dragging(x, y):
t1.ondrag(None)
t1.setheading(t1.towards(x, y))
t1.goto(x, y)
t1.ondrag(dragging)
def clickright(x, y):
t1.clear()
def main():
turtle.listen()
t1.ondrag(dragging)
turtle.onscreenclick(clickright, 3)
sc.mainloop()
main()
And also I don't think I'm allowed to import tkinter, atleast I think that's what our prof said
Whenever you import the same module two different ways, you're already in trouble:
import turtle
from turtle import *
You're having problems distinguishing between the turtle and the screen -- using the above facilitates those problems. I recommend instead that you only use turtle's object-oriented interface and turn off the functional interface:
from turtle import Screen, Turtle
You're trying to use a turtle as a button, which is fine, but you put the click handler on the screen and had the handler test if you clicked the turtle. Instead, put the click handler on the turtle so you needn't test. (Again, part of the problem of not being clear about what the turtle does and what the screen does.)
Though you call it twice, listen() doesn't apply here as were not dealing with keyboard input (yet).
Finally, your color change handler updated the color index but never actually changed any colors. Below is my rework and simplification of your code to address the above issues:
from turtle import Screen, Turtle
COLOUR_LIST = ['black', 'blue', 'green', 'red', 'orange', 'purple']
colour_index = 0
def colour_change(x, y):
global colour_index
colour_index = (colour_index + 1) % len(COLOUR_LIST)
t1.color(COLOUR_LIST[colour_index])
def dragging(x, y):
t1.ondrag(None)
t1.setheading(t1.towards(x, y))
t1.goto(x, y)
t1.ondrag(dragging)
def click_right(x, y):
t1.clear()
t1 = Turtle('circle')
t1.shapesize(0.5)
t1.speed('fastest')
t1.color(COLOUR_LIST[colour_index])
t1.ondrag(dragging)
# changing colour turtle
tcolour = Turtle('square')
tcolour.penup()
tcolour.shapesize(1, 1.5)
tcolour.setpos(-275, 285)
tcolour.onclick(colour_change, 1)
screen = Screen()
screen.onclick(click_right, btn=3)
screen.mainloop()

Turtle graphic screen not responding

So I'm trying to draw some text on the screen and everytime I press the turtle graphic screen it becomes unresponsive. When I tried fixing it by adding the mainloop it won't continue with rest of the code. I saw somewhere I should add
done()
at the end of the block but python says it doesn't exist and I tried putting turtle.done() but nothing.
Here is the code:
def draw_robot(choice_robot,robots):
stats = robots[choice_robot]
style = 'Arial',14,'bold'
t.setheading(-90)
t.write('Name: '+choice_robot,font=style,align = 'center')
t.forward(25)
t.write('Battery: '+stats[0],font=style,align = 'center')
t.forward(25)
t.write('Intelligence: '+stats[1],font=style,align = 'center')
turtle.mainloop()
how can i fix this?
The turtle.mainloop() should not appear in a subroutine. Generally, it should be the last thing executed on a page of turtle code. I.e., either literally the last statement or the last thing a main() routine does. It turns control over to tkinter's event handler where upon all interaction with turtle is through events (key strokes, mouse motion, etc.)
Below is roughly how I would expect a proper turtle program to be laid out:
from turtle import Turtle, Screen # force Object-oriented interface
STYLE = ('Arial', 14, 'bold')
def draw_robot(choice_robot, robots):
stats = robots[choice_robot]
t.setheading(-90)
t.write('Name: ' + choice_robot, font=STYLE, align='center')
t.forward(25)
t.write('Battery: ' + stats[0], font=STYLE, align='center')
t.forward(25)
t.write('Intelligence: ' + stats[1], font=STYLE, align='center')
screen = Screen()
t = Turtle()
my_choice_robot = None # whatever ...
my_robots = None # whatever ...
draw_robot(my_choice_robot, my_robots)
screen.mainloop()

Trigger event when text is clicked in Python Turtle

I'm currently making a program in python's Turtle Graphics. Here is my code in case you need it
import turtle
turtle.ht()
width = 800
height = 800
turtle.screensize(width, height)
##Definitions
def text(text, size, color, pos1, pos2):
turtle.penup()
turtle.goto(pos1, pos2)
turtle.color(color)
turtle.begin_fill()
turtle.write(text, font=('Arial', size, 'normal'))
turtle.end_fill()
##Screen
turtle.bgcolor('purple')
text('This is an example', 20, 'orange', 100, 100)
turtle.done()
I want to have click events. So, where the text 'This is an example' is wrote, I want to be able to click that and it prints something to the console or changes the background. How do I do this?
I don't want to install anything like pygame, it has to be made in Turtle
Use the onscreenclick method to get the position then act on it in your mainloop (to print or whatever).
import turtle as t
def main():
t.onscreenclick(getPos)
t.mainloop()
main()
Also see : Python 3.0 using turtle.onclick
Also see : Turtle in python- Trying to get the turtle to move to the mouse click position and print its coordinates
Since your requirement is to have onscreenclick around text area, we need
to track mouse position. For that we are binding function onTextClick to the screenevent.
Within function, if we are anywere around text This is an example , a call is made to turtle.onscreenclick to change color of the background to red.
You can change lambda function and insert your own, or just create external function and call within turtle.onscreenclick as per this documentation
I tried to change your code as little as possible.
Here is a working Code:
import turtle
turtle.ht()
width = 800
height = 800
turtle.screensize(width, height)
##Definitions
def text(text, size, color, pos1, pos2):
turtle.penup()
turtle.goto(pos1, pos2)
turtle.color(color)
turtle.begin_fill()
turtle.write(text, font=('Arial', size, 'normal'))
turtle.end_fill()
def onTextClick(event):
x, y = event.x, event.y
print('x={}, y={}'.format(x, y))
if (x >= 600 and x <= 800) and ( y >= 280 and y <= 300):
turtle.onscreenclick(lambda x, y: turtle.bgcolor('red'))
##Screen
turtle.bgcolor('purple')
text('This is an example', 20, 'orange', 100, 100)
canvas = turtle.getcanvas()
canvas.bind('<Motion>', onTextClick)
turtle.done()

Conceptual bug in a turtle program using resetscreen()

Criteria I'm trying to meet:
The screen resets when the user presses the SPACEBAR, meaning the drawn lines go away and the unnamed turtle returns to the center but it doesn’t return to the default turtle color and shape!
""" A simple drawing program
Click and drag the center turtle to draw
Click the colorful buttons to change the
turtle's color,
and then draw different shapes.
Press the SPACEBAR key to reset the
drawing.
"""
from turtle import *
turtle_1 = Turtle()
turtle_2 = Turtle()
turtle_3 = Turtle()
def callback_1(x,y):
color("red")
shape("circle")
circle(100)
def callback_2(x,y):
color("blue")
shape("square")
circle(100,steps=4)
def callback_3(x,y):
color("green")
shape("triangle")
circle(100,steps=3)
def place_turtles():
turtle_1.color("red")
turtle_1.shape("circle")
turtle_1.penup()
turtle_1.goto(-200,-200)
turtle_2.color("blue")
turtle_2.shape("square")
turtle_2.penup()
turtle_2.goto(0,-200)
turtle_3.color("green")
turtle_3.shape("triangle")
turtle_3.penup()
turtle_3.goto(200,-200)
def start_over():
resetscreen()
place_turtles()
listen()
onkey(start_over, "space")
ondrag(goto)
place_turtles()
This code allows the user to drag the turtle, press buttons, and reset the screen when they press SPACEBAR. For some reason, though, resetting the screen also resets the color of the turtle. How can I prevent this from happening?
Basically what I want to happen is if, say, the user clicks on the blue square button, then resets the screen to hide the shape drawn by the button, all of the turtles return to their original positions, but the unnamed turtle does not change its previous color and shape. Let me know if I need to elaborate further.
With a "better late than never" attitude, I believe I've reworked your code to get the behavior you desired. I also reworked your drag logic to give you better drawing capability:
from turtle import Turtle, Screen, getturtle
def callback_1(x, y):
anonymous.color(*turtle_1.color())
anonymous.shape(turtle_1.shape())
anonymous.circle(100)
def callback_2(x, y):
anonymous.color(*turtle_2.color())
anonymous.shape(turtle_2.shape())
anonymous.circle(100, steps=4)
def callback_3(x, y):
anonymous.color(*turtle_3.color())
anonymous.shape(turtle_3.shape())
anonymous.circle(100, steps=3)
def setup_turtles():
turtle_1.onclick(callback_1)
turtle_1.color("red")
turtle_1.penup()
turtle_1.goto(-200, -200)
turtle_2.onclick(callback_2)
turtle_2.color("blue")
turtle_2.penup()
turtle_2.goto(0, -200)
turtle_3.onclick(callback_3)
turtle_3.color("green")
turtle_3.penup()
turtle_3.goto(200, -200)
def start_over():
colors = anonymous.color()
anonymous.reset()
anonymous.color(*colors)
def drag_handler(x, y):
anonymous.ondrag(None) # disable event inside event handler
anonymous.goto(x, y)
anonymous.ondrag(drag_handler) # reenable event on event handler exit
anonymous = getturtle()
anonymous.ondrag(drag_handler)
turtle_1 = Turtle(shape="circle")
turtle_2 = Turtle(shape="square")
turtle_3 = Turtle(shape="triangle")
setup_turtles()
screen = Screen()
screen.onkey(start_over, "space")
screen.listen()
screen.mainloop()
Many of the changes are just for personal style reasons. The two key changes are: just reset the anonymous turtle itself, not the screen; rather than use goto as an event handler, wrap it in a function that turns off drag events during the goto call.

Categories