I'm trying to create a subclass of Rectangle in the Zelle graphics library in Python:
from graphics import*
win =GraphWin('tower of haoi',1000,600)
class DISC(Rectangle):
def __init__(self,pt1,pt2,color):
self.pt1=pt1
self.pt2=pt2
self.color=color
def createdisc(self):
self.setFill(self.color)
self.draw(win)
disc1=DISC(Point(0,0),Point(28,10),color_rgb(230, 255, 245))
disc1.createdisc()
win.getMouse()
win.close()
But the created object doesn't accept any methods and gives the error:
AttributeError: 'DISC' object has no attribute 'config'
The problem is that DISC.__init__() doesn't call the __init__() method of it's super class:
from graphics import *
class DISC(Rectangle):
def __init__(self, p1, p2, color):
super().__init__(p1, p2)
self.color = color
def createdisc(self):
self.setFill(self.color)
self.draw(win)
win = GraphWin('Tower of Hanoi', 1000, 600)
disc1 = DISC(Point(0, 0), Point(28, 10), color_rgb(230, 255, 245))
disc1.createdisc()
win.getMouse()
win.close()
You don't need to store the two points in your object as you're already storing them because your object is a Rectangle.
Related
This question already has answers here:
Why does Tkinter image not show up if created in a function?
(5 answers)
Closed 1 year ago.
I wanted to create a chess program using OOP. So I made a superclass Pieces, a subclass Bishop, and a UI class GameUI. I created a canvas in the class GameUI. I wanted, that when I instantiate an object bishop in the class GameUI, it shows an Image from a bishop, on the canvas.
The problem is, when I instantiate the Bishop, I don't see any image. So I tried to do the same with a text : instead of using the method create_image from the class Canvas, I used the method create_text, and it worked : I saw a text on the canvas. That means, the problem comes from the method create_image, and I don't understand it.
If I create an Image directly in the class GameUi, it works! but that's not what I want...
So I don't have any error message. I see the canvas (with a blue background), but no image on it.
Here's the code :
from tkinter import PhotoImage, Tk, Canvas
class Pieces:
def __init__(self, can, color, x_position, y_position):
self.color = color
self.x_position = x_position
self.y_position = y_position
class Bishop(Pieces):
def __init__(self, can, color, x_position, y_position):
super().__init__(can, color, x_position, y_position)
if color == "black":
icon_path = 'black_bishop.png'
elif color == "white":
icon_path = 'white_bishop.png'
icon = PhotoImage(file=icon_path) # doesn't see the image
can.create_image(x, y, image=icon)
class GameUI:
def __init__(self):
self.windows = Tk()
self.windows.title("My chess game")
self.windows.geometry("1080x720")
self.windows.minsize(300, 420)
self.can = Canvas(self.windows, width=1000, height=600, bg='skyblue')
icon = PhotoImage(file=icon_path) # here I create the image in this class, and
can.create_image(x, y, image=icon) # we can see it very well
self.bishop = Bishop(self.can, "black", 50, 50)
self.can.pack()
self.windows.mainloop()
app = GameUI()
To make your code work, I decided to sort of rewrite it based on this answer. It works now, but really the only thing that you needed to add was self.icon instead of icon. icon gets garbage collected since there is no further reference to it, while self.icon remains. Also, it's not entirely the same as yours was, so it probably needs a bit of rewriting too.
from tkinter import *
from random import randint
class Piece:
def __init__(self, canvas, x1, y1):
self.x1 = x1
self.y1 = y1
self.canvas = canvas
class Bishop(Piece):
def __init__(self, canvas, x1, y1, color):
super().__init__(canvas, x1, y1)
if color == "black":
icon_path = 'black_bishop.png'
elif color == "white":
icon_path = 'white_bishop.png'
self.icon = PhotoImage(file=icon_path)
self.ball = canvas.create_image(self.x1, self.y1, image=self.icon)
def move_piece(self):
deltax = randint(0,5)
deltay = randint(0,5)
self.canvas.move(self.ball, deltax, deltay)
self.canvas.after(50, self.move_piece)
class GameUI:
def __init__(self):
# initialize root Window and canvas
root = Tk()
root.title("Chess")
root.resizable(False,False)
canvas = Canvas(root, width = 300, height = 300)
canvas.pack()
# create two ball objects and animate them
bishop1 = Bishop(canvas, 10, 10, 'white')
bishop2 = Bishop(canvas, 60, 60, 'black')
bishop1.move_piece()
bishop2.move_piece()
root.mainloop()
app = GameUI()
I'm a beginner in Python and I'm using the Zelle's Graphics library. I wish to draw multiple shapes and make them behave as one. For example, I might call a group of shapes 'x' and when I use the builtin move() method the entire collection of shapes move.
The solution I envision is a new GraphicsObject that is actually a group of graphics objects. Below is a skeletal example with just enough code to demonstrate the idea:
from graphics import *
class GraphicsGroup(GraphicsObject):
def __init__(self):
super().__init__(options=[])
self.components = []
def draw(self, graphwin):
for component in self.components:
component.draw(graphwin)
return self
def move(self, dx, dy):
for component in self.components:
component.move(dx, dy)
def add_component(self, component):
if isinstance(component, GraphicsObject):
self.components.append(component)
win = GraphWin("Group Test", 200, 200)
# Some example objects borrowed from graphics.py source docstrings
text = Text(Point(35, 35), "Centered Text")
polygon = Polygon(Point(10, 10), Point(50, 30), Point(20, 70))
circle = Circle(Point(50, 50), 10)
rectangle = Rectangle(Point(25, 60), Point(60, 25))
group = GraphicsGroup()
group.add_component(text)
group.add_component(polygon)
group.add_component(circle)
group.add_component(rectangle)
group.draw(win)
win.getMouse() # Pause to view result
group.move(100, 100)
win.getMouse() # Pause to view result
win.close()
Since GraphicsGroup isn't really a graphic object itself, we override draw and move instead of _draw and _move like a proper graphics entity.
I am trying to make a turtle race, but I get an error that the class "turtles" has no attribute "forward". Here is my code:
class turtles:
def __init__(self, color, posX):
self = turtle.Turtle(shape='turtle', visible=False)
self.color(color)
self.penup()
self.shape('turtle')
self.goto(posX, -300)
self.showturtle()
self.setheading(90)
def start_race(self):
self.forward(random.randrange(0,10))
t1 = turtles('red',-150)
t2 = turtles('orange', -100)
t3 = turtles('yellow',-50)
t4 = turtles('green', 0)
t5 = turtles('light blue', 50)
t6 = turtles('blue',100)
t7 = turtles('purple', 150)
def begin_race():
t1.start_race()
t2.start_race()
t3.start_race()
t4.start_race()
t5.start_race()
t6.start_race()
t7.start_race()
begin_race()
Replace your turtles class with this:
class turtles(turtle.Turtle):
def __init__(self, color, posX):
self.color(color)
self.penup()
self.shape('turtle')
self.goto(posX, -300)
self.showturtle()
self.setheading(90)
def start_race(self):
self.forward(random.randrange(0,10))
Inheritance in Python is done by specifying a class in brackets after declaring a class name.
In this case, your turtles class inherits from the turtle.Turtle class and then has its attributes changed. Seems there was also some repetition with specifying the turtle's colour and visibility (I removed that for you)
The reason you get this error is because there is no attribute (i.e. a variable or method) called forward in your turtles class. The forward method is part of the turtle.Turtle class. You could solve this in different ways:
Method 1: using inheritance
You could derive your turtles class from the existing turtle.Turtle class. To do that, you should make the following changes:
The class turtles should be defined as class turtles(turtle.Turtle) to derive from it.
In the __init__() method you should not reassign self, because this is a reference to the actual object that's being initialized.
You should call the __init__() method of the original Turtle class.
So the full code could be like below. I renamed start_race() to advance_race() because that better describes what it does. And I added an infinite loop so you'll see the turtles "racing". This is just for demonstration, of course.
import random
import turtle
class turtles(turtle.Turtle):
def __init__(self, color, posX):
super().__init__(shape='turtle', visible=False)
self.color(color)
self.penup()
self.goto(posX, -300)
self.showturtle()
self.setheading(90)
def advance_race(self):
self.forward(random.randrange(0,10))
t1 = turtles('red', -150)
t2 = turtles('orange', -100)
t3 = turtles('yellow', -50)
t4 = turtles('green', 0)
t5 = turtles('light blue', 50)
t6 = turtles('blue', 100)
t7 = turtles('purple', 150)
while True:
t1.advance_race()
t2.advance_race()
t3.advance_race()
t4.advance_race()
t5.advance_race()
t6.advance_race()
t7.advance_race()
Method 2: using a wrapper class
Alternatively, you could create a new class that "holds" a turtle object. Using this method, you should store the turtle "inside" self and access it as self.turtle (or any other name).
class turtles:
def __init__(self, color, posX):
self.turtle = turtle.Turtle(shape='turtle', visible=False)
self.turtle.color(color)
self.turtle.penup()
self.turtle.goto(posX, -300)
self.turtle.showturtle()
self.turtle.setheading(90)
def advance_race(self):
self.turtle.forward(random.randrange(0,10))
(rest of the code same as above)
I am trying to create turtle objects with a class for my project which is a game. Each "Plane" object consists of:
plane3 = RawTurtle(screen)
plane3.ht()
plane3.color("red")
plane3.shape("plane.gif")
plane3.penup()
plane3.speed('fastest')
plane3.setposition(-270, 200)
plane3.setheading(360)
When putting this into a class and looking at other stack overflows questions to find out what to do, i threw together the following code:
class planes():
def __init__(self):
self.RawTurtle = RawTurtle(screen)
#self.hideturtle()
self.color = "red"
self.shape = ("plane.gif")
#self.penup()
self.speed = "fastest"
self.setposition = (-270, 100)
self.setheading = 360
Plane4 = planes()
When the code is run the turtle takes no shape or colour and is just a black triangle even though it causes no errors. However, errors do occur with the plane.hideturtle and plane.penup() functions which is why they are commented out.
File "C:/Users/marco/Desktop/Trooper shooter/TrooperShooter.py", line 694, in init
self.hideturtle()
AttributeError: 'planes' object has no attribute 'hideturtle'
Planes outside the class work perfectly and all planes are exactly identical. Any help is appreciated!
hideturtle() and penup() are both methods for the RawTurtle class, you haven't defined them for your planes class. So instead of this:
self.hideturtle()
self.penup()
you should have this:
self.RawTurtle.hideturtle()
self.RawTurtle.penup()
I believe your real problem is that your designed your plane class such that it has a turtle instead of designing it such that it is a turtle.
Taking the has a approach, every time you want to enable some additional turtle feature on your plane, you have to add a method to pass the call through to the contained turtle. Taking the is a approach, all turtle methods are in play:
from turtle import RawTurtle, TurtleScreen
from tkinter import Tk, Canvas, RIGHT
class Plane(RawTurtle):
def __init__(self):
super().__init__(screen)
self.hideturtle()
self.color('red')
self.shape('plane.gif')
# self.speed('fastest') # commented out while debugging
self.penup()
self.setposition(-270, 100)
self.setheading(0)
self.showturtle()
root = Tk()
canvas = Canvas(root, width=600, height=400)
canvas.pack(side=RIGHT)
screen = TurtleScreen(canvas)
screen.register_shape('plane.gif')
plane4 = Plane()
plane4.forward(400)
screen.mainloop()
I don't understand why the following code will not construct a graphics window with the circle. It does construct an object, but not graphically, when I run SomeObject = Tracker()
Why is that? This is a simple snippet of code, just for me to understand why I'm not getting a graphics window.
# tracker.py
from graphics import *
class Tracker:
def __inti__(self):
self.win = GraphWin('tracker', 500, 500)
self.circle = Circle(Point(0, 0), 0.5)
self.circle.draw(self.win)
You cannot see your circle because:
The radius of your circle (0.5) is too small
You placed the center of this small circle at (0, 0), which is at the top left corner
Your class's initializer was mispelled inti, hence the code was not called when you created your object.
Here is code that works:
from graphics import *
class Tracker:
def __init__(self):
# Window of size 500 x 500
self.win = GraphWin('tracker', 500, 500)
# Circle of radius 10 centered at (250, 250)
self.circle = Circle(Point(250, 250), 10)
self.circle.draw(self.win)
self.win.getMouse() # Pause to view result
self.win.close()
def main():
tracker = Tracker()
if __name__ == "__main__":
main()
Where graphics.py is presumably taken from this link.
I modified the sample code from the above link (which is probably also what you did) to call getMouse() to keep the window around.
The result is