Reputation: 41
I am having difficulty understanding how to delete an object from the canvas. A rocket object is created from Class Rocket
and is just a simple oval. After an event, I'm trying to use the canvas.delete()
method with the argument set to rocket
in order to remove this object from the canvas but it doesn't seem to work.
My goal is to create multiple rockets in a list and delete some during the animation.
I have include just main() function. The Class Rocket just creates an oval on the canvas and works fine.
file: constants.py
CANVAS_WIDTH = 600 # Width of drawing canvas in pixels
CANVAS_HEIGHT = 600 # Height of drawing canvas in pixels
ROCKET_SIZE = 30
file: test.py
import tkinter
import time
import random
from constants import *
from Rocket import Rocket
def main():
canvas = make_canvas(CANVAS_WIDTH, CANVAS_HEIGHT, 'Fireworks')
#put a rocket a bottom of canvas
rocket = Rocket(canvas)
canvas.update()
time.sleep(50/50.) #pause to see the rocket
# some event occurs (not important for this example)
canvas.delete(rocket) #this doesn't make the rocket disappear!
canvas.update()
time.sleep(50/50.)
def make_canvas(width, height, title):
top = tkinter.Tk()
top.minsize(width=width, height=height)
top.title(title)
canvas = tkinter.Canvas(top, width=width + 1, height=height + 1)
canvas.pack()
return canvas
if __name__ == '__main__':
main()
file: Rocket.py
import random
from constants import *
class Rocket:
'''
This is the blueprint for a new variable type called "Rocket"
Every rocket has three things: an oval, a change_x and a change_y.
Every rocket supports the "update" method which will move the rocket one step.
'''
def __init__(self, canvas):
# Starting point - screen bottom with slight angle
x_1 = random.randint(CANVAS_WIDTH/2 - 50, CANVAS_WIDTH/2 + 50)
y_1 = CANVAS_HEIGHT - ROCKET_SIZE
x_2 = x_1 + ROCKET_SIZE
y_2 = CANVAS_HEIGHT
self.fill = random.choice(['blue', 'green', 'orange', 'purple', 'red', 'lime'])
self.oval = canvas.create_oval(x_1, y_1, x_2, y_2, fill=self.fill, outline=self.fill)
self.change_x = random.randint(-3, 3)
self.change_y = random.randint(-15, -5)
# again, I pass in canvas.
def update(self, canvas):
# update a single rocket instance (the one given by self)
canvas.move(self.oval, self.change_x, self.change_y)
Upvotes: 2
Views: 4831
Reputation: 41
After helpful feedback and more research, here is my first solution;
add to Class Rocket the following -
# method to get canvas object id (already assigned to self.oval in constructor)
def get_id(self):
return self.oval
change the following line:
canvas.delete(rocket)
in main() to:
canvas.delete(rocket.get_id())
This also worked for multiple rockets created in a list.
I haven't tried deleting the rocket within the Class Rocket as a method, but this seems like the most elegant solution. Either way, the object ID is the required argument for canvas.delete.
Upvotes: 1
Reputation: 385830
When you call canvas.delete(rocket)
, tkinter will convert rocket
to a string before passing it off to the actual delete method. So, you can modify your rocket class to return the canvas object id from the __str__
method:
class Rocket():
...
def __str__(self):
return str(self.oval)
The downside to this is that it only allows you to have a single canvas element for drawing the rocket. If you have more than just a single object, you can instead have __str__
return an id, such as "rocket#1", and associate that id with every object that makes up the rocket.
For example, this uses both an oval and square for the rocket:
def __init__(self, canvas)
...
self.oval = canvas.create_oval(x_1, y_1, x_2, y_2, fill=self.fill, outline=self.fill)
# the id of the oval to create a tag for all rocket pieces
self.tag = f"rocket#{self.oval}"
self.canvas.itemconfigure(self.oval, tags=(self.tag,))
self.square = canvas.create_rectangle(x_1, y_1, x_2, y_1-20, fill="black", tags=(self.tag,))
def __str__(self):
return self.tag
Perhaps a better way would be to give your rocket a delete
method (or distruct
!) so that it is responsible for deleting itself.
This requires saving the canvas, and then having the rocket call self.canvas.delete(self.oval)
when you want the rocket to be destroyed.
class Rocket:
def __init__(self, canvas):
self.canvas = canvas
...
def destruct(self):
self.canvas.delete(self.oval)
...
def main():
...
# some event occurs (not important for this example)
rocket.destruct()
Upvotes: 1