Reputation: 1
I have been using the John Zelle graphics module for some time now, however this is my first time attempting to use the threading module. I am trying to make multiple objects (circles) that have different starting positions move along my screen simultaneously. This code will also contain recursion and jumping to multiple functions in its final product.
Here is an example of what I am trying to do:
from graphics import *
from random import randint
import time
import threading
class Particle:
def __init__(self):
self.xpos = randint(0,50)
self.ypos = randint(0,50)
self.graphic = Circle(Point(self.xpos,self.ypos),5)
self.graphic.draw(window)
def move(self):
for step in range(5):
self.xpos += 1
self.ypos += 1
self.graphic.move(self.xpos,self.ypos)
time.sleep(0.5)
window = GraphWin("window",500,500)
threading.Thread(target=Particle()).start()
threading.Thread(target=Particle()).start()
After different attempts of trying to use threading, I contnued to get two different errors.
This (from the code above):
Exception in thread Thread-1:
Traceback (most recent call last):
Thread-2 File "/usr/lib/python3.11/threading.py", line 1038, in _bootstrap_inner
:
Traceback (most recent call last):
File "/usr/lib/python3.11/threading.py", line 1038, in _bootstrap_inner
self.run()
File "/usr/lib/python3.11/threading.py", line 975, in run
self._target(*self._args, **self._kwargs)
TypeError: 'Particle' object is not callable
self.run()
File "/usr/lib/python3.11/threading.py", line 975, in run
self._target(*self._args, **self._kwargs)
TypeError: 'Particle' object is not callable
and also:
"RuntimeError: main thread is not in main loop"
I have tried many suggestions from stack overflow and other websites such as:
note: if you are certain that these methods should work please show me how it should be done and I am new to using the thread module.
thanks for any help!
Upvotes: 0
Views: 100
Reputation: 41872
It's rough but I believe it gives you a working starting point:
from queue import Queue
from random import randint
from threading import Thread
from time import sleep
from graphics import *
class Particle:
def __init__(self):
xpos = randint(0, 50)
ypos = randint(0, 50)
self.graphic = Circle(Point(xpos, ypos), 5)
self.graphic.draw(window)
def move(self):
while True:
graphic_commands.put((self.graphic.move, randint(1, 5), randint(1, 5)))
sleep(0.25) # sleep *this* thread
def process_queue():
while not graphic_commands.empty():
graphic, *arguments = graphic_commands.get()
graphic(*arguments)
window.after(100, process_queue)
graphic_commands = Queue(1) # size = ~ number of hardware threads you have - 1
window = GraphWin("window", 500, 500)
process_queue()
Thread(target=Particle().move, daemon=True).start()
Thread(target=Particle().move, daemon=True).start()
Thread(target=Particle().move, daemon=True).start()
window.getMouse()
window.close()
It's based on a similar solution I did for turtle, but with additional twists for graphics.py. The (thread safe) queue is used to make sure all the threads' drawing requests are executed in the main thread for tkinter.
Upvotes: 0
Reputation: 87
I tried your code,it need some fixes:
Particle.__init__()
or Particle().move()
as actionparticle1 = Particle()
class and then use it's methods like target=particle1.move()
thread1.join()
, main thread will wait till that perticular thread completes it's targeted action (daemon=True or False doesn't matter in this case)Here I am giving you some corrected version of code:
# ... same other code
threading.Thread(target=Particle().__init__()).start()
threading.Thread(target=Particle().__init__()).start()
or
# ... same other code
threading.Thread(target=Particle().move()).start()
threading.Thread(target=Particle().move()).start()
or
# ... same other code
particle1 = Particle()
particle2 = Particle()
threading.Thread(target=particle1.move()).start()
threading.Thread(target=particle2.move()).start()
or
# ... same upper code
particle1 = Particle()
particle2 = Particle()
thread1 = threading.Thread(target=particle1.move()).start()
thread2 = threading.Thread(target=particle2.move()).start()
thread1.join()
thread2.join()
In last snippet, you your window will be opened till your move function completes execution or you close it manually.
If you want to dig deeper in Pytohn Threading, check this guide: https://superfastpython.com/threading-in-python/
Upvotes: 0