Tkinter Turtles and Threads
world! In turtle graphics in python, there's possible to create various Turtle objects and manipulate them with their methods, forward, backward... I wanted to experiment with threads so I wrote a threaded class called MyTurtleManipulator.
from threading import Thread
from cTurtle import Turtle
import random
class MyTurtleManipulator(Thread):
def __init__(self, turtle):
Thread.__init__(self)
self.turtle=turtle
def run(self):
actions=[Turtle.forward, Turtle.right, Turtle.left]
while True:
action=random.choice(actions)
action(self.turtle, random.randint(1,25))
turtles=[Turtle() for i in range(5)]
threads=[MyTurtleManipulator(turtle) for turtle in turtles]
for thread in threads:
print(thread)
thread.start()
With the experiment I expected to see all the turtles moving "simultaneously" and randomly but When I run the program i get these errors:
<MyTurtleManipulator(Thread-1, initial)>
<MyTurtleManipulator(Thread-2, initial)>
<MyTurtleManipulator(Thread-3, initial)>
<MyTurtleManipulator(Thread-4, initial)>
<MyTurtleManipulator(Thread-5, initial)>
>>> Exception in thread Thread-1:
Traceback (most recent call last):
File "/usr/lib/python3.1/threading.py", line 516, in _bootstrap_inner
self.run()
File "/home/rfrm/test.py", line 13, in run
action(self.turtle, random.randint(1,25))
File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 1162, in forward
checkargs((int, float))
File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 1131, in _go
ende = self._position + self._orient * distance
File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 2266, in _goto
(start, self._position),
File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 419, in _drawline
cl.append(-y)
File "<string>", line 1, in coords
File "/usr/lib/python3.1/tkinter/__init__.py", line 2123, in coords
self.tk.call((self._w, 'coords') + args)))
RuntimeError: main thread is not in main loop
Exception in thread Thread-2:
Traceback (most recent call last):
File "/usr/lib/python3.1/threading.py", line 516, in _bootstrap_inner
self.run()
File "/home/rfrm/test.py", line 13, in run
action(self.turtle, random.randint(1,25))
File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 1203, in right
checkargs((int, float))
File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 2300, in _rotate
self._orient = self._orient.rotate(delta)
File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 2085, in _update
for t in screen._turtles:
File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 2219, in _drawturtle
screen._drawpoly(titem, shape, fill=fc, outline=oc,
File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 384, in _drawpoly
cl.append(-y)
File "<string>", line 1, in coords
File "/usr/lib/python3.1/tkinter/__init__.py", line 2123, in coords
self.tk.call((self._w, 'coords') + args)))
RuntimeError: main thread is not in main loop
Exception in thread Thread-3:
Traceback (most recent call last):
File "/usr/lib/python3.1/threading.py", line 516, in _bootstrap_inner
self.run()
File "/home/rfrm/test.py", line 13, in run
action(self.turtle, random.randint(1,25))
File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 1162, in forward
checkargs((int, float))
File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 1131, in _go
ende = self._position + self._orient * distance
File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 2270, in _goto
screen._drawline(self.drawingLineItem, ((0, 0), (0, 0)),
File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 419, in _drawline
cl.append(-y)
File "<string>", line 1, in开发者_运维百科 coords
File "/usr/lib/python3.1/tkinter/__init__.py", line 2123, in coords
self.tk.call((self._w, 'coords') + args)))
RuntimeError: main thread is not in main loop
Exception in thread Thread-4:
Traceback (most recent call last):
File "/usr/lib/python3.1/threading.py", line 516, in _bootstrap_inner
self.run()
File "/home/rfrm/test.py", line 13, in run
action(self.turtle, random.randint(1,25))
File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 1162, in forward
checkargs((int, float))
File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 1131, in _go
ende = self._position + self._orient * distance
File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 2270, in _goto
screen._drawline(self.drawingLineItem, ((0, 0), (0, 0)),
File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 419, in _drawline
cl.append(-y)
File "<string>", line 1, in coords
File "/usr/lib/python3.1/tkinter/__init__.py", line 2123, in coords
self.tk.call((self._w, 'coords') + args)))
RuntimeError: main thread is not in main loop
Exception in thread Thread-5:
Traceback (most recent call last):
File "/usr/lib/python3.1/threading.py", line 516, in _bootstrap_inner
self.run()
File "/home/rfrm/test.py", line 13, in run
action(self.turtle, random.randint(1,25))
File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 1203, in right
checkargs((int, float))
File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 2300, in _rotate
self._orient = self._orient.rotate(delta)
File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 2085, in _update
for t in screen._turtles:
File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 2219, in _drawturtle
screen._drawpoly(titem, shape, fill=fc, outline=oc,
File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 384, in _drawpoly
cl.append(-y)
File "<string>", line 1, in coords
File "/usr/lib/python3.1/tkinter/__init__.py", line 2123, in coords
self.tk.call((self._w, 'coords') + args)))
RuntimeError: main thread is not in main loop
What does this means, what does "main thread is not in main loop" means. Thank you for your help.
this seems to be a python/tkinter limitation as described here, turtle and threads are not friends
This has its limitations but may still be possible. The answer is in your error messges:
RuntimeError: main thread is not in main loop
Limit your turtle/tkinter operations to the main thread. In my rework of your example below, I've used the thread safe queue data structure to communicate between the threads and turtle:
from threading import Thread, active_count
from turtle import Turtle, Screen
import queue
import random
QUEUE_SIZE = 1 # set higher the more hardware threads you have
ACTIONS = [Turtle.forward, Turtle.right, Turtle.left]
COLORS = ['red', 'black', 'blue', 'green', 'magenta']
class MyTurtleManipulator(Thread):
def __init__(self, turtle):
super().__init__()
self.turtle = turtle
def run(self):
for _ in range(100):
actions.put((self.turtle, random.choice(ACTIONS), random.randint(1, 30)))
def process_queue():
while not actions.empty():
turtle, action, argument = actions.get()
action(turtle, argument)
if active_count() > 1:
screen.ontimer(process_queue, 100)
actions = queue.Queue(QUEUE_SIZE)
for color in COLORS:
turtle = Turtle('turtle')
turtle.color(color)
turtle.setheading(random.randint(0, 360))
MyTurtleManipulator(turtle).start()
screen = Screen()
process_queue()
screen.mainloop()
I set the QUEUE_SIZE to 1 as I'm on a machine with only two threads! I'm curious to know if everything works correctly on a machine with more threads and a QUEUE_SIZE ~= #threads - 1
精彩评论