Reputation: 737
As seen in my code below, I have a function that produces an animation of a circle when the user clicks on the window. My problem is, for me to have another circle appear and move after one is already spawned, I have to wait for the previous one to finish its loop of movement. After one circle has finished its "i in range" loop at the end of the snowfall function, then I can click and produce another circle. I want to be able to click at any time and have as many circles moving simultaneously as I want (I'm aware I've limited it to 10 times in the code under the function). It looks like I need away to run the same method multiple times concurrently.
from graphics import*
from random import*
win = GraphWin("Graphics Practice", 500, 500)
colours = ["blue", "red", "orange", "purple", "green", "black", "brown", "yellow", "pink"]
def snowfall(randColour):
point = win.getMouse()
circle = Circle(point, 40)
circle.draw(win)
circle.setFill(colours[randColour])
for i in range(1000):
circle.move(0, 1)
time.sleep(0.002)
randColour = randint(0, 8)
for i in range (10):
repeatColour = randColour
snowfall(randColour)
randColour = randint(0, 8)
while randColour == repeatColour:
randColour = randint(0, 8)
win.getMouse()
win.close()
One of my failed attempts at multithreading this:
from graphics import*
from random import*
win = GraphWin("Graphics Practice", 500, 500)
colours = ["blue", "red", "orange", "purple", "green", "black", "brown", "yellow", "pink"]
def snowfall(randColour):
point = win.getMouse()
circle = Circle(point, 40)
circle.draw(win)
circle.setFill(colours[randColour])
for i in range(1000):
circle.move(0, 1)
time.sleep(0.002)
randColour = randint(0, 8)
t1 = threading.Thread(target = snowfall, args = randColour)
for i in range (10):
repeatColour = randColour
t1.start()
t1.join()
randColour = randint(0, 8)
while randColour == repeatColour:
randColour = randint(0, 8)
win.getMouse()
win.close()
Most recent code:
from graphics import*
from random import*
win = GraphWin("Graphics Practice", 500, 500)
colours = ["blue", "red", "orange", "purple", "green", "black", "brown", "yellow", "pink"]
class Snowflake(object):
def __init__(self, randColour):
self.circle = Circle(point, 40)
self.circle.draw(win)
self.circle.setFill(colours[randColour])
def next_frame(self):
self.circle.move(0, 1)
randColour = randint(0, 8)
sprites = []
for i in range (100):
repeatColour = randColour
point = win.getMouse()
sprites.append(Snowflake(randColour))
randColour = randint(0, 8)
while randColour == repeatColour:
randColour = randint(0, 8)
for s in sprites:
while True:
s.next_frame()
time.sleep(0.02)
win.getMouse()
randColour = randint(0, 8)
sprites.append(Snowflake(randColour, point))
win.getMouse()
win.close()
Upvotes: 0
Views: 713
Reputation: 1822
One problem is that you are attempting to join
thread t1
immediately after starting it. To join
a thread is to wait for it to finish, so instead of starting ten threads, you are starting and then waiting for a thread ten times.
However, threading is the wrong approach here. Most graphics packages do not allow multiple threads to draw to the same graphics context, for good reasons of performance and fluidity. This means that you need to turn your drawing threads "inside out", putting the state of each animated object in a "sprite", so that the state of each animated object is in its own instance. Then, instead of using separate threads for each sprite, you run through all your sprites and update them in a single loop, as shown below.
(Note that I introduced win.checkMouse()
, which does a non-blocking check for a mouse event, and therefore allows you to add a sprite per click, which is what I believe you intended.)
from graphics import *
from random import *
win = GraphWin("Graphics Practice", 500, 500)
colours = ["blue", "red", "orange", "purple", "green", "black", "brown", "yellow", "pink"]
class Snowflake(object):
def __init__(self, randColour, point):
self.circle = Circle(point, 40)
self.circle.draw(win)
self.circle.setFill(colours[randColour])
def next_frame(self):
self.circle.move(0, 1)
randColour = randint(0, 8)
sprites = []
for i in range(100):
point = win.checkMouse()
if point:
randColour = randint(0, 8)
sprites.append(Snowflake(randColour, point))
for s in sprites:
s.next_frame()
time.sleep(0.1)
win.close()
Upvotes: 2