I want to make a class for turtle buttons and have a field to be the turtle
and here is the code I wrote:
class button:
def __init__(self,color,x,y):
self.turtle=turtle.Turtle()
self.turtle.penup()
self.turtle.shape("square")
self.turtle.color(color)
self.turtle.speed(0)
self.turtle.goto(x,y)
Now I want to use the onclick to a button instance, so how do I do that is it something like this?
def click(self,x,y):
print ("hello world")
self.turtle.onclick()
I'm not that good at classes btw so I just want something simple.
Here's how to bind the class' click() method to mouse-click events. See the documentation for the turtle.onclick() method.
import turtle
SCREENWIDTH = 640
SCREENHEIGHT = 480
class Button:
def __init__(self,color,x,y):
self.turtle = turtle.Turtle()
self.turtle.penup()
self.turtle.shape("square")
self.turtle.color(color)
self.turtle.speed(0)
self.turtle.goto(x,y)
self.turtle.onclick(self.click) # Bind mouse-click event to method.
def click(self, x, y):
print ("hello world")
if __name__ == "__main__":
mainscreen = turtle.Screen()
mainscreen.mode("standard")
mainscreen.setup(SCREENWIDTH, SCREENHEIGHT)
Button('red', 0, 0)
turtle.mainloop()
P.S. I strongly suggest you read and start following the coding suggestions in the PEP 8 - Style Guide for Python Code. It will make your code easier to read and understand.
Related
Hello I am trying to create something like this box with controllable dots
I need to be able to move and interact with the dots. I have tried turtle and pyglet, but neither of them seem to do what I want them to do.
Turtle is letting me create dots but it doesnt seem to play well with oop. I'm a super noob at python oop so maybe I'm just doing it wrong but I can't seem to make an turtle object that I can actually use how I want. I would ideally be able to use my own methods built off of the turtle methods, and create and call on data unique to each turtle.
import turtle
import time
import random
wn = turtle.Screen()
wn.title("simulation")
wn.bgcolor("tan")
def rng(whatisrandom):
match whatisrandom:
case 'coords': return(random.randint(-400,400) , random.randint(-400,400))
case 'heading':return(random.randint(0,359))
case 'forward':return(random.randint(0,50))
class bug():
def __init__(self) -> None:
self = turtle.Turtle(shape = "circle",visible=False)
self.speed(0)
self.penup()
self.setpos(rng('coords'))
self.showturtle()
self.speed(1)
self.forward(20)
def move(self):
self.setheading(rng('heading'))
self.forward(rng('forward'))
bug1 = bug()
bug1.move()
wn.mainloop()
this is the error message.
self.setheading(rng('heading'))
^^^^^^^^^^^^
AttributeError: 'bug' object has no attribute 'heading'
I ultimately want to animate these little bugs with neural nets and train them to do different movements, and eventually interact with each other.
This appears to be a misunderstanding of how to subclass an object in Python. Let's rearrange things a bit:
from turtle import Screen, Turtle
from random import randint
class Bug(Turtle):
def __init__(self):
super().__init__(shape='circle', visible=False)
self.speed('fastest')
self.penup()
self.setposition(Bug.rng('coords'))
self.showturtle()
self.speed('slowest')
self.forward(20)
def move(self):
self.setheading(Bug.rng('heading'))
self.forward(Bug.rng('forward'))
#staticmethod
def rng(whatisrandom):
if whatisrandom == 'coords':
return randint(-400, 400), randint(-400, 400)
if whatisrandom == 'heading':
return randint(0, 359)
if whatisrandom == 'forward':
return randint(0, 50)
return None
screen = Screen()
screen.title("Simulation")
screen.bgcolor('tan')
bug1 = Bug()
bug1.move()
screen.mainloop()
I don't have an issue with your match statement, I'm just unfamiliar with it and haven't updated my Python sufficiently!
I want to make a flappy bird game and am currently trying to turn paddle a into a class but it wont appear while it should.
Im also not getting any error messages and the code can run but without any signs of paddle x(the object from the class).
this is the code:
class Paddle:
Paddle = turtle.Turtle()
Paddle.penup()
Paddle.goto(0,0)
def __init__(self,shape,color,stretch_wid,stretch_len):
self.shape = shape
self.color = color
self.stretch_wid = stretch_wid
self.stretch_len = stretch_len
paddle_x = Paddle("square","white",5,5)
paddle_a = turtle.Turtle()
paddle_a.shape("square")
paddle_a.color("white")
paddle_a.shapesize(stretch_wid=20,stretch_len=5)
paddle_a.penup()
paddle_a.goto(150,-250)
I already tried putting the 3 lines of codes after the "class Paddle:" under the class and then also changing the "Paddle" into paddle_x but then it says "'Paddle' object has no attribute 'penup'".
First time asking a question.
Thanks in advance.
Having worked with object inheritance with some polygon classes, I believe you will need to reference the "Turtle" object within the class definition of your "Paddle" object as in the following code snippet.
import turtle
class Paddle(turtle.Turtle): # Define as a child of the Turtle object
def __init__(self,shape,color,stretch_wid,stretch_len):
turtle.Turtle.__init__(self) # Use the Turtle object's initialization
self.shape = shape
self.color = color
self.stretch_wid = stretch_wid
self.stretch_len = stretch_len
paddle_x = Paddle("square","white",5,5)
paddle_x.penup()
paddle_x.goto(0,0)
print(paddle_x.shape)
paddle_a = turtle.Turtle()
paddle_a.shape("square")
paddle_a.color("white")
paddle_a.shapesize(stretch_wid=20,stretch_len=5)
paddle_a.penup()
paddle_a.goto(150,-250)
It kind of utilizes the C++ method of initializing a child object based upon the parent (or "super") class. When trying that code snippet out, the screen appears briefly with a turtle pointer and prints out the paddle value requested in the test.
#Una:~/Python_Programs/Paddle$ python3 Paddle.py
square
You might give that a try.
Additional notes.
Referring to your comments and getting a better understanding of what you are trying to do with your "Paddle" class with a one-off initialization of the attributes, following is a slightly revised version of the sample code.
import turtle
class Paddle(turtle.Turtle): # Define as a child of the Turtle object
def __init__(self,shape,color,stretch_wid,stretch_len):
turtle.Turtle.__init__(self) # Use the Turtle objects initialization
self.shape(shape)
self.color(color)
self.shapesize(stretch_wid = stretch_wid, stretch_len=stretch_len)
paddle_x = Paddle("square","blue",5,5)
paddle_x.penup()
paddle_x.goto(0,0)
paddle_a = turtle.Turtle()
paddle_a.shape("square")
paddle_a.color("white")
paddle_a.shapesize(stretch_wid=20,stretch_len=5)
paddle_a.penup()
paddle_a.goto(150,-250)
while True:
pass
That produces a square as per your specifications.
I made the square a blue color since my background happened to be white.
Give that a try.
I am trying to create a snake with an edited Turtles class. So I create a SnakeSegment class which has Turtle class as a parent. I then add a variable to the SnakeSegment class and also I set things like the colour and speed of the Turtle.
I then create my snake class where I bring in my SnakeSegments. The problem is the snake segments don't bring in their colour which I initiated in the snake segment class.
I think I have got the inheritance wrong, but I am not sure.
I have 2 files: components.py and main.py
components.py:
from turtle import Turtle
class SnakeSegment(Turtle):
def __init__(self, givenListPosition):
super().__init__()
self.segment = Turtle()
self.segment.shape("square")
self.segment.color('white')
self.segment.speed(1)
self.segment.penup()
self.listPosition = givenListPosition
class Snake:
def __init__(self, screen):
self.theScreen = screen
self.pastPositions = [(0.00, 0.00), (-20.00, 0.00), (-30.00, 0.00)]
self.t1 = SnakeSegment(0)
self.t2 = SnakeSegment(1)
self.t2.goto(self.pastPositions[int(self.t2.listPosition)])
self.t3 = SnakeSegment(2)
self.t2.goto(self.pastPositions[int(self.t3.listPosition)])
main.py:
from components import *
from turtle import Screen
screen = Screen()
screen.setup(width=600, height=600)
screen.bgcolor("black")
screen.title("Snake Game")
snake = Snake(screen)
snake.theScreen.exitonclick()
I'm not sure I get your final goal and you did not show how your Turtle class looks. However, it appears you are using a mix of inheritance and composition which doesn't seem correct whatever your goal is. You have to decide if SnakeSegment is a Turtle (inheritance) or has a Turtle (composition) in your data model.
With inheritance, SnakeSegment will have all methods and attributes of the base Turtle class (which I assume has some of the "shape", "color" etc methods) and will "be" a Turtle from any point of view. You could then write something like this
class SnakeSegment(Turtle):
def __init__(self, givenListPosition):
super().__init__()
self.shape("square")
self.color('white')
self.speed(1)
self.penup()
self.listPosition = givenListPosition
With composition instead, SnakeSegment doesn't inherit from anything, it just has a member which is an instance of the Turtle class. In that case, something like that would be used
class SnakeSegment:
def __init__(self, givenListPosition):
self.segment = Turtle()
self.segment.shape("square")
self.segment.color('white')
self.segment.speed(1)
self.segment.penup()
self.listPosition = givenListPosition
I'd suggest you start from that and before taking a decision on your data model, have a read about mixins as well (i.e. https://www.pythontutorial.net/python-oop/python-mixin/)
I'm trying to create a rectangle with text on top, but the text shows below the rectangle.
How can I make the text go to the front layer?
My code so far:
from turtle import Turtle
class Rectangle(Turtle):
def __init__(self, x, y, width, height, color='white'):
super().__init__()
self.penup()
self.goto(x, y)
self.color(color)
self.shape('square')
self.shapesize(stretch_wid=(height / 20), stretch_len=(width / 20))
class Writer(Turtle):
def __init__(self, x, y):
super().__init__()
self.penup()
self.goto(x, y)
self.hideturtle()
def writetext(self, text, font="Arial", size=8, textType="normal", color="black", x=None, y=None):
if x is None:
x = self.xcor()
if y is None:
y = self.ycor()
self.goto(x, y)
self.color(color)
self.write(text, move=False, align="center", font=(font, size, textType))
class Button(Rectangle):
def __init__(self, position, width, height, text, onclick, color="gray"):
position = list(position)
super().__init__(position[0], position[1], width, height, color)
writer = Writer(position[0], position[1])
writer.writetext(text, color="white")
self.goto(position[0], position[1])
self.color(color)
self.onclick(onclick)
def start_game(_arg1=None, _arg2=None): # requires arguments since Python turtle module passes two in when calling it using onclick
print('game started')
Button((0, 0), 50, 20, 'click me to start the game', start_game)
I've been searching on google for over half an hour and couldn't find anything
I believe the design has some fundamental flaws that arise from subclassing Turtle.
The issue is that the Button drawing is happening outside of the constructor where the text is written. The drawing function is called automatically by the turtle library. Regardless of whether you're hooking into Turtle's classes or not, a constructor isn't typically the ideal place to draw things for this reason. I don't see a clean way to make a Button out of two separate turtles with subclassing.
A quick (but poor) fix is to override the internal method that turtle calls to update the object so your button can inject the text after the super() call draws the rectangle (you could also try to hook into drawing with _drawturtle):
class Button(Rectangle):
# ....
def _update(self):
super()._update()
Writer(*self.position()).writetext("foobar", color="white")
But since the leading _ indicates a private, internal method, this is circumventing the turtle API -- not a good idea.
A second try would be to disable the internal update loop with turtle.tracer(0) and take control of the update loop manually, but then that seems to defeat the purpose of subclassing Turtle, which is that you want things to "just work" automatically.
There's a deeper problem here, though, which is that once you get your text on top of the button as shown above in the workaround, the text blocks clicks from being detected by the rectangle underneath it.
After playing around with it quite a bit, the best alternatives I came up with were to create an image with the text pre-rendered in, or else use a global click listener and use the coordinates to determine if the click occurred on the button. The following code isn't reusable, but it's a proof of concept that you could abstract into a function or class by parameterizing everything:
import turtle
from turtle import Turtle
def handle_btn_click(x, y):
if (x > -btn_size and y > -btn_size / 2 and
x < btn_size and y < btn_size / 2):
print("game started")
turtle.tracer(1)
turtle.clearscreen()
turtle.bye()
turtle.tracer(0)
r = Turtle(shape="square")
btn_size = 80
r.shapesize(btn_size // 20, btn_size // 10)
r.color("black")
turtle.update()
t = Turtle()
t.color("white")
t.ht()
text = "click me to start the game"
t.write(text, move=False, align="center", font=("Arial", 8, "normal"))
turtle.Screen().onclick(handle_btn_click)
turtle.mainloop()
As a final note, if you're only adding a single button, I suggest keeping it simple and imperative. A class structure is often overkill for most turtle apps, and the large parameter lists are a pain to deal with for only a single instance.
The text shows below the button seems to happen when you call any methods of the Button class after you wrote the text.
Try the following code:
class Button(Rectangle):
def __init__(self, position, width, height, text, onclick, color="gray"):
#...
writer.writetext(text, color="red")
self.goto(position[0], position[1])
self.color(color)
self.onclick(onclick)
writer.writetext("abc", color="blue")
If you set turtle.tracer with a bit of delay, you can actually see the grey button being created first, then the text in red on the grey button, then the grey button is brought back up by the three self. methods, then the text "abc" in blue written on top of everything.
Still, as mentioned in ggorlen's answer, the text will block the button from being clicked. Please refer to ggorlen's answer for the alternative solution.
I'm attempting to create Conway's Game of Life in Pyqt5 and am unsure how to update my grid to change the color of a particular cell.
My program has a GUI class, board class, and a class for the Lifeform. This method is in the class with the lifeforms. Should I create another paintevent outside of my GUI class? Do I make some object for the GUI that I should reference instead (this approach doesn't make sense when I say it to myself because making an object for the GUI referenced outside the GUI seems like bad design but idk) I posted my method below because I feel my question may not be complicated and I'm just missing something.
def paintWhite(self): #LifeForm Class
screensize = QDesktopWidget().screenGeometry()
cellwidth = screensize.width()//GLOBAL_N #GlobalN x GlobalN grid
cellheight = screensize.height()//GLOBAL_N
paintObject = QPainter()
paintObject.setPen(QPen(Qt.white, 5, Qt.SolidLine))
paintObject.setBrush(QColor(255,255,255))
paintObject.drawRect(cellwidth * self.row, cellheight * self.col, cellwidth,cellheight)
#Seperate Code Snippets
def paintEvent(self,e): #Gui Class
paintObject = QPainter(self)
paintObject.setPen(QPen(Qt.black, 5, Qt.SolidLine))
paintObject.setBrush(QColor(0,0,0))
n=50
for i in range(n):
for j in range(n):
x = paintObject.drawRect(self.width//n*i, self.height//n*j, self.width//n,self.height//n)
There is just no color change. Thank you for any help.