Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Moving balls in Tkinter Canvas

This is a very basic program with which I want to make two moving balls, but only one of them actually moves.

I have tried some variations as well but can't get the second ball moving; another related question - some people use the move(object) method to achieve this, while others do a delete(object) and then redraw it. Which one should I use and why?

This is my code that is only animating/moving one ball:

from Tkinter import *

class Ball:
    def __init__(self, canvas, x1, y1, x2, y2):
    self.x1 = x1
    self.y1 = y1
    self.x2 = x2
    self.y2 = y2
    self.canvas = canvas
    self.ball = canvas.create_oval(self.x1, self.y1, self.x2, self.y2, fill="red")

    def move_ball(self):
        while True:
            self.canvas.move(self.ball, 2, 1)
            self.canvas.after(20)
            self.canvas.update()

# initialize root Window and canvas
root = Tk()
root.title("Balls")
root.resizable(False,False)
canvas = Canvas(root, width = 300, height = 300)
canvas.pack()

# create two ball objects and animate them
ball1 = Ball(canvas, 10, 10, 30, 30)
ball2 = Ball(canvas, 60, 60, 80, 80)

ball1.move_ball()
ball2.move_ball()

root.mainloop()
like image 619
dlohse Avatar asked Aug 21 '14 15:08

dlohse


2 Answers

You should never put an infinite loop inside a GUI program -- there's already an infinite loop running. If you want your balls to move independently, simply take out the loop and have the move_ball method put a new call to itself on the event loop. With that, your balls will continue to move forever (which means you should put some sort of check in there to prevent that from happening)

I've modified your program slightly by removing the infinite loop, slowing down the animation a bit, and also using random values for the direction they move. All of that changes are inside the move_ball method.

from Tkinter import *
from random import randint

class Ball:
    def __init__(self, canvas, x1, y1, x2, y2):
        self.x1 = x1
        self.y1 = y1
        self.x2 = x2
        self.y2 = y2
        self.canvas = canvas
        self.ball = canvas.create_oval(self.x1, self.y1, self.x2, self.y2, fill="red")

    def move_ball(self):
        deltax = randint(0,5)
        deltay = randint(0,5)
        self.canvas.move(self.ball, deltax, deltay)
        self.canvas.after(50, self.move_ball)

# initialize root Window and canvas
root = Tk()
root.title("Balls")
root.resizable(False,False)
canvas = Canvas(root, width = 300, height = 300)
canvas.pack()

# create two ball objects and animate them
ball1 = Ball(canvas, 10, 10, 30, 30)
ball2 = Ball(canvas, 60, 60, 80, 80)

ball1.move_ball()
ball2.move_ball()

root.mainloop()
like image 195
Bryan Oakley Avatar answered Sep 20 '22 16:09

Bryan Oakley


This function seems to be the culprit

def move_ball(self):
    while True:
        self.canvas.move(self.ball, 2, 1)
        self.canvas.after(20)
        self.canvas.update()

You deliberately put yourself in an infinite loop when you call it.

ball1.move_ball()    # gets called, enters infinite loop
ball2.move_ball()    # never gets called, because code is stuck one line above
like image 25
Cory Kramer Avatar answered Sep 18 '22 16:09

Cory Kramer