Python | Tkinter : Move multiple and different objects to gether - python

I have searched a lot but, I couldnt find the exact answer whats I need ( or I couldnt understand properly ).
In my code there are 1 rectangle, 8 lines. They are moving synchronously. But I want to add a bunch of circles in my canvas. To do that, Im creating a lot of row ''create_oval'' objects. This is meaningless because in next step may be I need thousand of balls in the canvas. I have tried a lot of loops, etc. to find a way to create circles with shortened method but I couldn't achieve what I need.
This my codes.
from tkinter import *
from random import randint
tk = Tk()
W, H =600, 500
canvas = Canvas(tk, width=W, height=H)
canvas.pack()
rectangle= canvas.create_rectangle(50, 250, 550, 50, fill="blue")
line1 = canvas.create_line(370, 70, 550,70,fill="black")
line2 = canvas.create_line(330, 90, 550,90,fill="black")
line3 = canvas.create_line(290, 110, 550,110,fill="black")
line4 = canvas.create_line(250, 130, 550,130,fill="black")
line5 = canvas.create_line(210, 150, 550,150,fill="black")
line6 = canvas.create_line(170, 170, 550,170,fill="black")
line7 = canvas.create_line(130, 190, 550,190,fill="black")
line8 = canvas.create_line(90, 210, 550,210,fill="black")
line9 = canvas.create_line(50, 230, 550,230,fill="black")
ball1 = canvas.create_oval(550,50,545,55, fill="red")
ball2 = canvas.create_oval(550,50,545,55, fill="red")
ball3 = canvas.create_oval(550,50,545,55, fill="red")
ball4 = canvas.create_oval(550,50,545,55, fill="red")
ball5 = canvas.create_oval(550,50,545,55, fill="red")
ball6 = canvas.create_oval(550,50,545,55, fill="red")
ball7 = canvas.create_oval(550,50,545,55, fill="red")
ball8 = canvas.create_oval(550,50,545,55, fill="red")
Xspeed = 10
Yspeed = 0
def moveTable():
global Xspeed,Yspeed
canvas.move(table, Xspeed, Yspeed)
canvas.move(line1, Xspeed, Yspeed)
canvas.move(line2, Xspeed, Yspeed)
canvas.move(line3, Xspeed, Yspeed)
canvas.move(line4, Xspeed, Yspeed)
canvas.move(line5, Xspeed, Yspeed)
canvas.move(line6, Xspeed, Yspeed)
canvas.move(line7, Xspeed, Yspeed)
canvas.move(line8, Xspeed, Yspeed)
canvas.move(line9, Xspeed, Yspeed)
canvas.move(ball1, Xspeed-randint(5,10),Yspeed+randint(5,10))
canvas.move(ball2, Xspeed-randint(5,10),Yspeed+randint(5,10))
canvas.move(ball3, Xspeed-randint(5,10),Yspeed+randint(5,10))
canvas.move(ball4, Xspeed-randint(5,10),Yspeed+randint(5,10))
canvas.move(ball5, Xspeed-randint(5,10),Yspeed+randint(5,10))
canvas.move(ball6, Xspeed-randint(5,10),Yspeed+randint(5,10))
canvas.move(ball7, Xspeed-randint(5,10),Yspeed+randint(5,10))
canvas.move(ball8, Xspeed-randint(5,10),Yspeed+randint(5,10))
left,top,right,bot = canvas.coords(table)
if(left == 60 or left == 40):
Xspeed = -Xspeed
canvas.after(100, moveTable)
moveTable()
tk.mainloop()
It's probably very simple but I couldn't see it.

If you assign a tag to one or more widgets, you can affect them all at the same time.
Here's an example that moves all of the red items vertically, and all of the green items horizontally, all using only two move commands:
import tkinter as tk
import random
root = tk.Tk()
canvas = tk.Canvas(root, background="black", width=400, height=400)
canvas.pack(fill="both", expand=True)
for i in range(20):
x = random.randint(10, 110)
y = random.randint(10, 110)
width = random.randint(10, 30)
height = random.randint(10, 30)
canvas.create_rectangle(x, y, x+width, y+height, fill="red", tags=("red",))
canvas.create_rectangle(x, y, x+width, y+height, fill="green", tags=("green",))
def animate():
canvas.move("red", 0, 1)
canvas.move("green", 1, 0)
canvas.after(20, animate)
animate()
root.mainloop()
You could also just save the items to a list and iterate over the list
items = []
for i in range(100):
item = canvas.create_oval(...)
items.append(item)
...
for item in items:
canvas.move(item, ...)

Related

How do I create 4 squares in tkinter so that they start in the middle of the screen and each one of them goes in its own corner and disappears?

Here is the code, I have managed to position the square a little bit but the whole thing is just messy and fast when executed, it doesn't really resemble anything, let alone what I wanted to make.
What do I need to do in order to get these 4 squares to start in the middle and move to each corner, disappearing from the screen? I made an example here:
from tkinter import *
W, H = 500, 500
tk = Tk()
canvas = Canvas(tk,width=W,height=H)
canvas.pack()
class Square:
def __init__(self,size,speedx, speedy, color):
self.square = canvas.create_rectangle(50,50,100,100,fill=color)
self.speedx = speedx
self.speedy = speedy
self.movement()
def movement(self):
canvas.move(self.square,self.speedx,self.speedy)
pos = canvas.coords(self.square)
if pos[2]>=W or pos[0]<=0:
self.speedx *= -1
if pos[3]>=H or pos[1]<=0:
self.speedy *= -1
tk.after(40,self.movement)
square1 = Square(200,150,200,'brown')
square2 = Square(200,200,150,'yellow')
square3 = Square(200,200,200,'green')
square4 = Square(200,150,150,'blue')
tk.mainloop()
You need to define direction for each rectangle separately, so that each of them moves its own way.
import tkinter as tk
W, H = 500, 500
SPEED = 20
window = tk.Tk()
canvas = tk.Canvas(window, width=W, height=H)
canvas.pack()
class Square:
def __init__(self, x, y, color, speed_x, speed_y):
self.speed_x = speed_x
self.speed_y = speed_y
self.square = canvas.create_rectangle(x, y, x+50, y+50, fill=color)
self.movement()
def movement(self):
canvas.move(self.square, self.speed_x, self.speed_y)
window.after(200, self.movement)
Square(200, 200, 'brown', -SPEED, -SPEED)
Square(250, 200, 'yellow', SPEED, -SPEED)
Square(200, 250, 'green', -SPEED, SPEED)
Square(250, 250, 'blue', SPEED, SPEED)
window.mainloop()
Output:

Bouncing dvd logo in python tkinter

I am trying to make a bouncing DVD logo in tkinter, but I don't really know how to make it, it works with a ball, the logo doesn't move. The logo
# 1) create main window
from tkinter import *
from PIL import ImageTk, Image
fen = Tk()
fen.title('AllTech - Bouncing ball')
fen.resizable(False, False)
# 2) create canvas and ball
WIDTH, HEIGHT = 400, 300
canvas = Canvas(fen, width=WIDTH, height=HEIGHT)
canvas.pack()
img = ImageTk.PhotoImage(Image.open("dvd.gif"))
# ball = canvas.create_oval(10, 10, 50, 50, fill='black')
# 3) move the ball
xspeed = yspeed = 3
frame = Frame(fen, width=600, height=400)
frame.pack()
frame.place(anchor='center', relx=0.5, rely=0.5)
label = Label(frame, image = img)
label.pack()
def moveBall():
global xspeed, yspeed
canvas.move(canvas, xspeed, yspeed)
(leftPos, topPos, rightPos, bottomPos) = canvas.coords(img)
if leftPos <= 0 or rightPos >= WIDTH:
xspeed = -xspeed
if topPos <= 0 or bottomPos >= HEIGHT:
yspeed = -yspeed
img.after(30, moveBall)
canvas.after(30, moveBall)
fen.mainloop()
I tried with a ball ad it's work, but I don't know why, it doesn't with the logo.
You need to put the image using canvas.create_image() and then you can move the image using canvas.move().
from tkinter import *
from PIL import ImageTk, Image
fen = Tk()
fen.title('AllTech - Bouncing ball')
fen.resizable(False, False)
WIDTH, HEIGHT = 400, 300
canvas = Canvas(fen, width=WIDTH, height=HEIGHT, bg="white")
canvas.pack()
img = ImageTk.PhotoImage(Image.open("dvd.gif"))
# put the image into canvas
logo = canvas.create_image(0, 0, image=img, anchor="nw")
xspeed = yspeed = 3
def moveLogo():
global xspeed, yspeed
# move the image
canvas.move(logo, xspeed, yspeed)
# get bounding box of the image
(leftPos, topPos, rightPos, bottomPos) = canvas.bbox(logo)
if leftPos <= 0 or rightPos >= WIDTH:
xspeed = -xspeed
if topPos <= 0 or bottomPos >= HEIGHT:
yspeed = -yspeed
canvas.after(30, moveLogo)
canvas.after(30, moveLogo)
fen.mainloop()

How to limit bullet fire

This is my code. It is a program that fires bullets until there aren't any left.
from tkinter import *
from time import sleep
import random
class Ball:
def __init__(self, canvas, color, size, x, y, xspeed, yspeed):
self.canvas = canvas
self.color = color
self.size = size
self.x = x
self.y = y
self.xspeed = xspeed
self.yspeed = yspeed
self.id=canvas.create_oval(x,y,x+size,y+size,fill=color)
def move(self):
self.canvas.move(self.id, self.xspeed, self.yspeed)
(x1, y1, x2, y2)=self.canvas.coords(self.id)
(self.x, self.y)=(x1, y1)
if x1<=0 or x2>=WIDTH:
self.xspeed=-self.xspeed
if y1<=0 or y2>=HEIGHT:
self.yspeed=-self.yspeed
WIDTH=800
HEIGHT=400
bullets=[]
def fire(event):
bullets.append(Ball(canvas, 10, "red", 100, 200, 10, 0))
window = Tk()
canvas = Canvas(window, width=WIDTH, height=HEIGHT)
canvas.pack()
canvas.bind("<Button-1>", fire)
spaceship = Ball(canvas, "green", 100, 100, 200, 0, 0)
enemy = Ball(canvas, "red", 100, 500, 200, 0, 5)
while True:
for bullet in bullets:
bullet.move()
if (bullet.x+bullet.size) >= WIDTH:
canvas.delete(bullet.id)
bullets.remove(bullet)
if (bullet_count<9):
bullet_count+=1
else:
id=canvas.create_text(100,50, fill="red",font="Times 30 italic
bold",text="Hello World")
break
enemy.move()
window.update()
sleep(0.03)
I just want to fire 10 bullets and if there are no remaining bullets, I want to create a message box like id = canvas.create_text(100, 50, fill="red",font="Times 30 italic bold",text="Out of bullets").
How can I accomplish this goal? I am not particularly experienced at Python.
You need to check the number of bullets fired inside fire(), not in the while loop.
Also better not use while loop in a tkinter application, use .after() instead.
bullet_count = 10
def fire(event):
global bullet_count
if bullet_count > 0:
bullets.append(Ball(canvas, "red", 10, 100, 200, 10, 0))
bullet_count -= 1
else:
# show out of bullets
canvas.itemconfig(message, text="Out of bullets")
...
# text object to show the "Out of Bullets" message
message = canvas.create_text(100, 50, anchor="nw", fill="red", font="Times 30 italic bold")
# function to replace the while loop
def move_bullets():
for bullet in bullets:
bullet.move()
if bullet.x+bullet.size >= WIDTH:
canvas.delete(bullet.id)
bullets.remove(bullet)
enemy.move()
window.after(30, move_bullets)
move_bullets() # start the bullets animation
window.mainloop()
Plese provide more context. But here is a hint
for bullet in bullets[:10]:
# we try to fire 10 bullets
# if we have less bullets we fire them
# but we have more, here we only fire 10 of them
bullet.move()
if (bullet.x+bullet.size) >= WIDTH:
canvas.delete(bullet.id)
bullets.remove(bullet)
# If we had less bullets and we fired less than 10 bullets
if len(bullets) <= 0:
id = canvas.create_text(100, 50, fill="red", font="Times 30 italicbold",text="you have less than 10 bullets")

Moving image in python tkinter

I am writing a simple program in which I want the (ball image png) to bounce off the walls. So far, I have writen this code:
import tkinter as tk
root = tk.Tk()
WIDTH = 500
HEIGHT = 500
canvas = tk.Canvas(root,bg="white",width=WIDTH,height=HEIGHT)
canvas.pack()
img = tk.PhotoImage(file="images/ball1.png")
ball = canvas.create_image(0,0,anchor="nw",image=img)
yspeed = 2
xspeed = 2
def move_ball():
global xspeed,yspeed,ball
canvas.move(ball,xspeed,yspeed)
canvas.after(10,move_ball)
move_ball()
root.mainloop()
You can get the current position with the coords method, then code in a check for each of the 4 walls. Here's the first one:
def move_ball():
global xspeed,yspeed,ball
xpos, ypos = canvas.coords(ball)
if xpos + width_of_ball > WIDTH:
# ball hit the right edge, reverse x direction
xspeed *= -1
canvas.move(ball,xspeed,yspeed)
canvas.after(10,move_ball)
This answer is the same thing as #Novel answer (even though I wrote it before I saw theirs). The only difference is in the fact that the logic of update doesn't expect you to make any edits for it to work, it considers both horizontal and vertical directions, and resizing the main window is compensated for.
import tkinter as tk
root = tk.Tk()
root.title('Infinite Bounce Simulator')
root.geometry('400x300+300+300')
xspeed = 4
yspeed = 3
canvas = tk.Canvas(root, highlightthickness=0, bg='#111')
canvas.pack(expand=True, fill='both')
ball = canvas.create_oval((0, 0, 20, 20), fill='red')
def update():
global xspeed, yspeed, ball
canvas.move(ball, xspeed, yspeed)
#Left, Top, Right, Bottom coordinates
l, t, r, b = canvas.coords(ball)
#flip speeds when edges are reached
if r > canvas.winfo_width() or l < 0:
xspeed = -xspeed
if b > canvas.winfo_height() or t < 0:
yspeed = -yspeed
#do it all again in 10 milliseconds
root.after(10, update)
root.after_idle(update)
root.mainloop()

How do we delete a shape that's already been created in Tkinter canvas?

Consider:
from Tkinter import *
a = Tk()
canvas = Canvas(a, width = 500, height = 500)
canvas.pack()
canvas.create_rectangle(0, 0, 100, 100)
How do we delete this rectangle that's been created?
This is in reference to a game I am creating. It's a simple game where if the ball hits the block, the block should disappear. But if I do something like this:
class Block:
def __init__(self,canvas,color):
self.canvas = canvas
self.id = canvas.create_rectangle(10, 10, 110, 20, fill=color )
self.id1 = canvas.create_rectangle(115, 10, 215, 20, fill=color)
self.id2 = canvas.create_rectangle(220, 10, 320, 20, fill=color)
self.id3 = canvas.create_rectangle(325, 10, 425, 20, fill=color)
self.id4 = canvas.create_rectangle(430, 10, 530, 20, fill=color)
self.id5 = canvas.create_rectangle(100, 150, 200, 160, fill=color)
self.id6 = canvas.create_rectangle(350, 150, 450, 160, fill=color)
self.x = 0
And then:
def hit_block(self,pos):
block_pos = self.canvas.coords(self.block.id)
List = [block_pos]
for i in List:
if pos[0] >= i[0] and pos[2] <= i[2]:
if pos[1] >= i[1] and pos[1] <= i[3]:
canvas.delete(block.id)
self.score()
global a
a += 1
return True
return False
It doesn't work. How can I delete the block when the ball hits it?
Assign the create_rectangle() to a variable, and then call canvas.delete() on that variable:
from Tkinter import *
a = Tk()
canvas = Canvas(a, width = 500, height = 500)
canvas.pack()
myrect = canvas.create_rectangle(0,0,100,100)
canvas.delete(myrect) #Deletes the rectangle
Window before deletion:
Window after deletion:
In my opinion better option is add a Option tags= to function create_rectangle() and u can avoid creating new variables.
from Tkinter import *
a = Tk()
canvas = Canvas(a, width = 500, height = 500)
canvas.pack()
canvas.create_rectangle(0,0,100,100, tags="square")
canvas.delete("square") #Deletes the rectangle wchich have tags option named "square"
myrect = canvas.create_rectangle(0,0,100,100)
Btw. it's a problem when u "delete" an object from myrect to "create" them again in the same variable.

Categories

Resources