OOP Workshop
Version5: Keyboard Interaction
import turtle
import random
import math
turtle.setup(500, 500)
screen = turtle.Screen()
turtle.title("Turtle Keys")
turtle.pensize(3)
colors = ("orange", "pink", "yellow", "green", "blue", "purple", "magenta", "cyan")
class Button:
buttonShape = "Line"
buttonColor = "Orange"
buttonX = 0
buttonY = 0
width = 100
height = 50
def __init__(self, buttonShape, buttonColor, buttonX, buttonY, width, height):
self.buttonShape = buttonShape
self.buttonColor = buttonColor
self.buttonX = buttonX
self.buttonY = buttonY
self.width = width
self.height = height
def drawButtonShape(self, aTurtle):
aTurtle.pensize(20)
aTurtle.penup()
aTurtle.goto(self.buttonX, self.buttonY + 10)
aTurtle.pendown()
aTurtle.forward(self.width)
def drawTheButton(self, aTurtle):
global selectedButton
if (self is selectedButton or self is selectedColorButton):
aTurtle.color("Red")
else:
aTurtle.color("Black")
aTurtle.setheading(0)
aTurtle.fillcolor(self.buttonColor)
aTurtle.penup()
aTurtle.goto(self.buttonX, self.buttonY)
aTurtle.pendown()
aTurtle.begin_fill()
self.drawButtonShape(aTurtle) # Potential Polymorphic call to child class
aTurtle.end_fill()
def drawShape(self, x, y, aTurtle):
aTurtle.goto(x, y)
def isClicked(self, x, y):
return self.buttonX < x < self.buttonX + self.width and \
self.buttonY < y < self.buttonY + self.height
def getColor(self):
return self.buttonColor
class RectangleButton(Button):
def __init__(self, buttonColor, buttonX, buttonY, width, height):
super().__init__("Rectangle", buttonColor, buttonX, buttonY, width, height)
def drawRectangle(self, aTurtle, width, height):
aTurtle.setheading(0)
aTurtle.forward(width)
aTurtle.left(90)
aTurtle.forward(height)
aTurtle.left(90)
aTurtle.forward(width)
aTurtle.left(90)
aTurtle.forward(height)
def drawButtonShape(self, aTurtle):
aTurtle.pensize(2)
self.drawRectangle(aTurtle, self.width, self.height)
def drawShape(self, x, y, aTurtle):
self.drawRectangle(aTurtle, x - aTurtle.xcor(), y - aTurtle.ycor())
class TriangleButton(Button):
def __init__(self, buttonColor, buttonX, buttonY, width, height):
super().__init__("Triangle", buttonColor, buttonX, buttonY, width, height)
def drawTriangle(self, aTurtle, width, heading):
aTurtle.setheading(heading)
aTurtle.forward(width)
aTurtle.left(120)
aTurtle.forward(width)
aTurtle.left(120)
aTurtle.forward(width)
def drawButtonShape(self, aTurtle):
aTurtle.pensize(2)
self.drawTriangle(aTurtle, self.width, 0)
def drawShape(self, x, y, aTurtle):
sign = 1 if x - aTurtle.xcor() > 0 else -1
self.drawTriangle(aTurtle, (sign) * math.sqrt((x - aTurtle.xcor()) ** 2 + (y - aTurtle.ycor()) ** 2),
math.degrees(math.atan((y - aTurtle.ycor()) / (x - aTurtle.xcor()))))
class CircleButton(Button):
def __init__(self, buttonColor, buttonX, buttonY, width, height):
super().__init__("Circle", buttonColor, buttonX, buttonY, width, height)
def drawCircle(self, aTurtle, radius, heading):
aTurtle.setheading(heading)
aTurtle.circle(radius)
def drawButtonShape(self, aTurtle):
aTurtle.pensize(2)
aTurtle.penup()
aTurtle.setheading(0)
aTurtle.forward(self.width / 2)
aTurtle.pendown()
self.drawCircle(aTurtle, self.width / 2, 0)
def drawShape(self, x, y, aTurtle):
sign = 1 if x - aTurtle.xcor() > 0 else -1
self.drawCircle(aTurtle, (sign) * math.sqrt((x - aTurtle.xcor()) ** 2 + (y - aTurtle.ycor()) ** 2) / 2,
math.degrees(math.atan((y - aTurtle.ycor()) / (x - aTurtle.xcor()))) - 90)
buttonTurtle = turtle.Turtle()
buttonTurtle.speed(20)
selectedButton = Button("Line", "Orange", -130, 220, 40, 20)
shapeButtons = []
shapeButtons.append(selectedButton)
shapeButtons.append(RectangleButton("Green", -70, 200, 100, 40))
shapeButtons.append(TriangleButton("Blue", 40, 200, 40, 40))
shapeButtons.append(CircleButton("Brown", 90, 200, 40, 40))
def updateButtons():
for i in range(len(shapeButtons)):
shapeButtons[i].drawTheButton(buttonTurtle)
def anyShapeSelected(x, y):
global selectedButton
for i in range(len(shapeButtons)):
shapeB = shapeButtons[i]
if (shapeB.isClicked(x, y)):
print(shapeB.buttonShape, "was clicked")
if (shapeB is selectedButton):
return False
selectedButton = shapeB
return True
return False
class RandomColorButton(CircleButton):
def getColor(self): # Overriding the default behaviour of the getColor method in the Button base class
global colors
return colors[random.randint(0, len(colors) - 1)]
colorButtons = []
selectedColorButton = RandomColorButton("White", -(len(colors) + 1) * 30 / 2, 170, 20, 20)
colorButtons.append(selectedColorButton)
for i in range(len(colors)):
colorButtons.append(CircleButton(colors[i], -(len(colors) + 1) * 30 / 2 + (i + 1) * 30, 170, 20, 20))
def updateColorButtons():
for i in range(len(colorButtons)):
colorButtons[i].drawTheButton(buttonTurtle)
def anyColorSelected(x, y):
global selectedColorButton
for i in range(len(colorButtons)):
colorB = colorButtons[i]
if (colorB.isClicked(x, y)):
print(colorB.buttonColor, "was clicked")
if (colorB is selectedColorButton):
return False
selectedColorButton = colorB
return True
return False
drawing = False
def goto_and_do_whatever_required(x, y):
global drawing
if (drawing):
return
drawing = True
if (y > 170):
if (anyShapeSelected(x, y)):
updateButtons()
if (anyColorSelected(x, y)):
updateColorButtons()
drawing = False
return
turtle.color(selectedColorButton.getColor())
selectedButton.drawShape(x, y, turtle)
drawing = False
screen.onscreenclick(goto_and_do_whatever_required)
updateButtons()
updateColorButtons()
def upkeyfunc():
turtle.forward(15)
def leftkeyfunc():
turtle.left(15)
def rightkeyfunc():
turtle.right(15)
def downkeyfunc():
turtle.back(15)
def u_keyfunc():
turtle.penup()
def d_keyfunc():
turtle.pendown()
turtle.onkeypress(upkeyfunc, "Up")
turtle.onkeypress(leftkeyfunc, "Left")
turtle.onkeypress(rightkeyfunc, "Right")
turtle.onkeypress(downkeyfunc, "Down")
turtle.onkeypress(u_keyfunc, "U")
turtle.onkeypress(u_keyfunc, "u")
turtle.onkeypress(d_keyfunc, "D")
turtle.onkeypress(d_keyfunc, "d")
turtle.listen()
turtle.done()