how can I change between modes with my button - python

I created 2 drawing modes but they draw at the same time but i want them to work seperateley so i created a button but dont know how to define the mode change for the button to work
how can I define my mode change so I can change between different drawing modes eg freehandmode, circlemode so they dont work at the same time
from turtle import Screen, Turtle
beni=Screen()
beni.setup(400, 400, 10, 10)
beni.setworldcoordinates(-300, -300, 300, 300)
def mode_change(x, y):
#freehandmode
def freehandmode(x, y):
t.ondrag(None)
t.setheading(t.towards(x, y))
t.goto(x, y)
t.ondrag(freehandmode)
#circlemode
def draw_circle(x, y):
beni.onclick(None)
center = turtle.position()
turtle.setposition(x, y)
turtle.setheading(turtle.towards(center) - 90)
turtle.pendown()
turtle.circle(turtle.distance(center))
turtle.penup()
turtle.clearstamps()
beni.onclick(pick_center)
def pick_center(x, y):
beni.onclick(None)
turtle.setposition(x, y)
turtle.stamp()
beni.onclick(draw_circle)
turtle = Turtle()
turtle.hideturtle()
turtle.shape('circle')
turtle.shapesize(0.5)
turtle.penup()
beni.onclick(pick_center)
#freehand turtle
t = Turtle('circle')
t.shapesize(1)
t.speed('fastest')
t.ondrag(freehandmode)
#modechange turtle
modechange = Turtle('circle')
modechange.pu()
modechange.shapesize(0.55, 1.45)
modechange.color('black')
modechange.setpos(0, 290)
modechange.onclick(mode_change)
#modebutton
modebutton = Turtle()
modebutton.shapesize(0.25)
modebutton.pu()
modebutton.setpos(-20, 300)
modebutton.setheading(270)
modebutton.pd()
modebutton.fd(20)
modebutton.setheading(0)
modebutton.fd(45)
modebutton.setheading(90)
modebutton.fd(20)
modebutton.setheading(180)
modebutton.fd(45)
modebutton.pu()
modebutton.setpos(-10, 263)
modebutton.setheading(0)
modebutton.color('green')
modebutton.write('Modi')
modebutton.hideturtle()
beni.mainloop()

It's mostly a matter of accounting -- you need to explicitly list steps necessary to disable one turtle and enable the other every time you switch modes. And you need to keep track of the current mode. Here's my rework and simplification of your (actually, largely my) code to do this:
from turtle import Screen, Turtle, mainloop
def mode_change(x, y):
global mode
if mode == 'freehand':
# disable freehand
freehand.ondrag(None)
freehand.hideturtle()
# enable circle
screen.ontimer(lambda: screen.onclick(pick_center)) # so screen doesn't inherit *this* click
mode = 'circle'
else:
# disable circle
screen.onclick(None)
# enable freehand
freehand.ondrag(freehandmode)
freehand.showturtle()
mode = 'freehand'
# freehand mode
def freehandmode(x, y):
freehand.ondrag(None)
freehand.setheading(freehand.towards(x, y))
freehand.goto(x, y)
freehand.ondrag(freehandmode)
# circle mode
def draw_circle(x, y):
screen.onclick(None)
center = circle.position()
circle.setposition(x, y)
circle.setheading(circle.towards(center) - 90)
circle.pendown()
circle.circle(circle.distance(center))
circle.penup()
circle.clearstamps()
screen.onclick(pick_center)
def pick_center(x, y):
screen.onclick(None)
circle.setposition(x, y)
circle.stamp()
screen.onclick(draw_circle)
screen = Screen()
screen.setup(400, 400)
mode = 'freehand'
circle = Turtle('circle', visible=False)
circle.shapesize(0.5)
circle.speed('fastest')
circle.penup()
freehand = Turtle('circle')
freehand.speed('fastest')
freehand.ondrag(freehandmode)
# modechange turtle
modechange = Turtle('square')
modechange.penup()
modechange.setposition(0, 155)
modechange.pencolor('green')
modechange.write('Modi', align='center')
modechange.shapesize(2.25, 1.0)
modechange.setposition(0, 190)
modechange.onclick(mode_change)
mainloop()

Related

Is there a way to avoid the recursion limit in my Turtle-program?

import turtle
from turtle import Turtle
WIDTH = 1000
HEIGHT = 1000
#Screen setup
screen = turtle.Screen()
screen.setup(WIDTH, HEIGHT)
screen.title(" " *150 + "Test_GIU")
screen.bgcolor("black")
screen.setup(1000, 1000)
#Pen
pen = Turtle("circle")
pen.pensize = 5
pen.color("green")
pen.speed(-1)
def dragging(x, y): # These parameters will be the mouse position
pen.ondrag(None)
pen.setheading(pen.towards(x, y))
pen.goto(x, y)
pen.ondrag(dragging)
def click_on_c():
screen.reset()
pen = Turtle("circle")
pen.pensize = 5
pen.color("green")
pen.speed(-1)
pen.ondrag(dragging)
def main(): # This will run the program
turtle.listen()
pen.ondrag(dragging) # When we drag the turtle object call dragging
turtle.onkeypress(click_on_c, "c")
screen.mainloop() # This will continue running main()
main()
This is my code, im pretty new to it, so its not very good, but its my first real project. I´ve already tried to increase the recursin limit, but it crashes even if I set it to 10000. I also tried to catch the error with an try and exept block, but it also doesnt work.
Let's try a simpler design where instead of calling screen.reset() and recreating the turtle, we instead call pen.reset() to clear the drawing:
from turtle import Screen, Turtle
WIDTH = 1000
HEIGHT = 1000
def dragging(x, y): # Parameters are the mouse position
pen.ondrag(None)
pen.setheading(pen.towards(x, y))
pen.goto(x, y)
pen.ondrag(dragging)
def click_on_c():
pen.reset()
pen.pensize = 5
pen.color("green")
pen.speed('fastest')
# Screen setup
screen = Screen()
screen.setup(WIDTH, HEIGHT)
screen.title("Test_GUI")
screen.bgcolor("black")
# Pen
pen = Turtle("circle")
pen.pensize = 5
pen.color("green")
pen.speed('fastest')
pen.ondrag(dragging)
screen.onkeypress(click_on_c, "c")
screen.listen()
screen.mainloop()
We have to reset some aspects of the pen after calling reset() as that call clears the settings back to the defaults.

Turtle true freehand drawing

I want to start drawing with the mouse, and I had the idea to do onclick and then the turtle comes to the mouse, and then ondrag turtle I start the freehand drawing, although turtle doesn't detect the dragging. Here is the code. Can you help?
import turtle
def go_to_mouse(x, y):
my_pen.penup()
my_pen.goto(x, y)
my_pen.pendown()
def click_right(x, y):
my_pen.clear()
def drag_handler(x, y):
my_pen.ondrag(None)
my_pen.goto(x, y)
my_pen.ondrag(drag_handler)
window = turtle.Screen()
window.setup(width=1000, height=1000)
window.title('drawing')
window.delay(0)
my_pen = turtle.Turtle()
my_pen.speed(0)
my_pen.color("red")
my_pen.penup()
my_pen.goto(0, 0)
my_pen.pendown()
my_pen.ondrag(drag_handler)
window.onclick(go_to_mouse, 1)
turtle.onscreenclick(click_right, 3)
window.listen()
turtle.mainloop()
Let's first be clear that your code works if you "click again" after the turtle moves to your position. The issue is you don't want to "click again", but rather continue to hold the screen click and start dragging.
The way I was able to figure out to do this was to install and import pyautogui to simulate the missing click:
from turtle import Screen, Turtle
from pyautogui import mouseDown
def go_to_mouse(x, y):
screen.onclick(None, 1) # disable until turtle.release()
turtle.penup()
turtle.goto(x, y)
turtle.pendown()
turtle.onrelease(release_handler)
screen.ontimer(mouseDown)
def click_right(x, y):
turtle.clear()
def drag_handler(x, y):
turtle.ondrag(None)
turtle.goto(x, y)
turtle.ondrag(drag_handler)
def release_handler(x, y):
turtle.onrelease(None)
screen.onclick(go_to_mouse, 1)
screen = Screen()
screen.setup(width=1000, height=1000)
screen.title('drawing')
turtle = Turtle('turtle')
turtle.speed('fastest')
turtle.color('red')
turtle.ondrag(drag_handler)
screen.onclick(go_to_mouse, 1)
screen.onclick(click_right, 3)
screen.mainloop()
I'm using a larger cursor to make sure we don't missposition the "click again". I can't test the right click functionality on my system.

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

Python multiple onclick events

I want to be able to have both of my turtle onclick events function, but only one of them functions. I have a function that draws a square at the location the user clicks, and I have a close button that closes the program when you click it. Only one of these functions work at a time.
import turtle
import math
turtle.penup()
def square(x, y):
turtle.up()
turtle.goto(x, y)
turtle.down()
for i in range(4):
turtle.forward(50)
turtle.left(90)
def closebutton(location1):
(x,y) = location1
turtle.up()
turtle.setposition(location1)
turtle.down()
for i in range(2):
turtle.forward(40)
turtle.left(90)
turtle.forward(25)
turtle.left(90)
turtle.up()
turtle.forward(7.5)
turtle.left(90)
turtle.forward(5)
turtle.right(90)
turtle.write("close")
def btnclick(x, y):
if x > 100 and x < 141 and y > -100 and y < -75:
quit()
turtle.onscreenclick(btnclick)
closebutton((100,-100))
turtle.onscreenclick(square)
def square(x, y):
# Check area is Close button
if x > 100 and x < 141 and y > -100 and y < -75:
quit()
turtle.up()
turtle.goto(x, y)
turtle.down()
for i in range(4):
turtle.forward(50)
turtle.left(90)
I think, at square function, we can check that is close button's area
We can solve this the way you attempted, but we have to add the screen click handlers in a specific order and take advantage of the little-used add parameter:
from turtle import Screen, Turtle, mainloop
FONT_SIZE = 20
FONT = ('Arial', FONT_SIZE, 'normal')
def draw_square(x, y):
turtle.penup()
turtle.goto(x, y)
turtle.pendown()
for _ in range(4):
turtle.forward(50)
turtle.left(90)
def button_clicked(x, y):
if 100 < x < 100 + text_width and -FONT_SIZE/2 - 100 < y < FONT_SIZE/2 - 100:
quit()
def make_close_button(x, y):
turtle.penup()
turtle.setposition(x, y - FONT_SIZE / 2)
turtle.write("close", move=True, font=FONT)
width = turtle.xcor() - x # pixel width of text we just wrote
turtle.pendown()
for _ in range(2):
turtle.left(90)
turtle.forward(FONT_SIZE)
turtle.left(90)
turtle.forward(width)
turtle.penup()
turtle.home()
return width
turtle = Turtle()
text_width = make_close_button(100, -100)
screen = Screen()
screen.onscreenclick(button_clicked)
screen.onscreenclick(draw_square, add=True)
mainloop()
But this approach makes it hard to disable the onscreenclick() event inside the event handler code. That is, while one square is still being drawn, you can click elsewhere on the screen and start a second, interfering with the completion of the first. To solve this we might try a completely different approach with a single event handler function that we can disable and reenable as needed:
from turtle import Screen, Turtle, mainloop
FONT_SIZE = 20
FONT = ('Arial', FONT_SIZE, 'normal')
def draw_square():
for _ in range(4):
turtle.forward(50)
turtle.left(90)
def button_clicked(x, y):
screen.onscreenclick(None) # disable event handler inside event handler
if button.distance(x, y) < FONT_SIZE:
quit()
turtle.penup()
turtle.goto(x, y)
turtle.pendown()
draw_square()
screen.onscreenclick(button_clicked)
def make_close_button(x, y):
button = Turtle(visible=False)
button.speed('fastest')
button.penup()
button.setposition(x, y - FONT_SIZE / 2)
button.write("close", move=True, font=FONT)
width = button.xcor() - x # pixel width of text we just wrote
button.pendown()
for _ in range(2):
button.left(90)
button.forward(FONT_SIZE)
button.left(90)
button.forward(width)
button.penup()
button.setposition(x + width / 2, y)
return button
button = make_close_button(100, -100)
turtle = Turtle()
screen = Screen()
screen.onscreenclick(button_clicked)
mainloop()
Here we broke up the functionality a bit to have functions with specific duties. And instead of figuring out if we clicked near the button, we left a turtle behind and just check the distance of the click from that turtle.
Both approaches have their advantages and disadvantages.

Turtle Graphics - Extract Color from onscreenclick

I am using Turtle Graphics in Python for a larger program. I am able to return the point that the user clicks on using turtle.onscreenclick
However, I would like to extract the RGB color of the point that the user clicks on. Can this even be done in turtle graphics and how can this be accomplished? Thank you!
import turtle
# Global variables specifying the point clicked
xclick = 0
yclick = 0
# Draw a rectangle that is red
height = float(50)
length = height *(1.9)
length = round(length,2)
turtle.begin_fill()
turtle.color("red")
turtle.down()
turtle.forward(length)
turtle.right(90)
turtle.forward(height)
turtle.right(90)
turtle.forward(length)
turtle.right(90)
turtle.forward(height)
turtle.right(90)
turtle.end_fill()
# Gets the click
def getcoordinates():
turtle.onscreenclick(turtle.goto)
turtle.onscreenclick(modifyglobalvariables)
# Modifies the global variables
def modifyglobalvariables(rawx,rawy):
global xclick
global yclick
xclick = int(rawx//1)
yclick = int(rawy//1)
print(xclick)
print(yclick)
getcoordinates()
turtle.done()
turtle doesn't have function to get pixel color. It uses tkinter (and widget tkinter.Canvas - turtle.getcanvas()) to display everything but it doesn't have function to get pixel color too.
Canvas keeps all as objects and second answer for "Get pixel colors of tkinter canvas" shows how to get color of object in position (x,y). Maybe it will work for you.
EDIT: I made working example
canvas uses different coordinates - it needed to change y = -y
import turtle
# --- functions --- (lower_case_names)
def get_pixel_color(x, y):
# canvas use different coordinates
y = -y
canvas = turtle.getcanvas()
ids = canvas.find_overlapping(x, y, x, y)
if ids: # if list is not empty
index = ids[-1]
color = canvas.itemcget(index, "fill")
if color != '':
return color.lower()
return "white" # default color
def modify_global_variables(rawx,rawy):
global xclick
global yclick
xclick = int(rawx)
yclick = int(rawy)
print(get_pixel_color(xclick, yclick))
def draw_rect(x1, y1, width, height, color):
y1 = -y1
canvas = turtle.getcanvas()
canvas.create_rectangle((x1, y1, x1+width, y1+height), fill=color, width=0)
# --- main ---
# Global variables specifying the point clicked
xclick = 0
yclick = 0
# Draw a rectangle that is red
height = 50.0 # now it is float
length = height * 1.9
length = round(length, 2)
turtle.down()
turtle.color("RED")
turtle.begin_fill()
for _ in range(2):
turtle.forward(length)
turtle.right(90)
turtle.forward(height)
turtle.right(90)
turtle.end_fill()
# Use tkinter.Canvas to draw rectangle
draw_rect(100, 100, length, height, 'green')
# Gets the click & Modifies the global variables
turtle.onscreenclick(modify_global_variables)
turtle.done()

Categories