【问题标题】:Mutli-threading python with Tkinter使用 Tkinter 的多线程 python
【发布时间】:2013-01-17 12:27:05
【问题描述】:

我正在使用这些功能在画布上绘制小圆圈:

这是绘制圆圈的函数:

class Fourmis:

def __init__(self, can, posx, posy, name, radius):
    self.can = can

    self.largeur_can = int(self.can.cget("width"))
    self.hauteur_can = int(self.can.cget("height"))

    self.posx = posx
    self.posy = posy
    self.name = name 
    self.radius = radius

    self.ball1 = self.can.create_oval(self.posy, self.posx, self.posy+radius, self.posx+radius, outline=self.name, fill=self.name, width=2)

    self.nx = randrange(-10,10,1)
    self.nx /= 2.0
    self.ny = randrange(-10,10,1)
    self.ny /= 2.0

    #self.can.bind("<Motion>", self.destruction, add="+") 
    self.statut = True

    self.move()

def move(self):
    if self.statut == True :
        self.pos_ball = self.can.coords(self.ball1)
        self.posx_ball = self.pos_ball[0]
        self.posy_ball = self.pos_ball[1]

        if self.posx_ball < 0 or (self.posx_ball + self.radius) > self.largeur_can:
            self.nx = -self.nx         
        if self.posy_ball < 0 or (self.posy_ball + self.radius) > self.hauteur_can:
            self.ny = -self.ny

        self.can.move(self.ball1, self.nx, self.ny)

        self.can.after(10, self.move)

这个创建了画布和圆圈:

class App(Frame):

def __init__(self):
    self.root=Tk()
    self.can=Canvas(self.root,width=800,height=600,bg="black")
    self.can.pack()

    self.create(50, "green")
    self.create(50, "purple")



def mainloop(self):
    self.root.mainloop()


def create(self, i, name):
    for x in range(i):
        self.x=Fourmis(self.can,100,400, name,0)

我调用这些行来运行项目:

jeu = App()
jeu.mainloop()

在不同线程中执行self.create(50, "green")和self.create(50, "purple")的正确方法是什么?

我尝试了以下方法,但无法正常工作。:

class FuncThread(threading.Thread):
def __init__(self, i, name):
    self.i = i
    self.name = name
    threading.Thread.__init__(self)

def run(self):
    App.create(self, self.i, self.name)

有人能告诉我如何运行这些线程吗?

【问题讨论】:

    标签: python multithreading tkinter


    【解决方案1】:

    当需要此功能时,您所做的就是安排您希望执行的事件,方法是将它们放入线程共享的队列中。这样,在给定线程中,您指定要通过排队来运行“create(50, ...)”,然后主线程将事件出列并执行。

    这是在第二个线程中创建移动球的基本示例:

    import threading
    import Queue
    import random
    import math
    import time
    import Tkinter
    
    random.seed(0)
    
    class App:
        def __init__(self, queue, width=400, height=300):
            self.width, self.height = width, height
            self.canvas = Tkinter.Canvas(width=width, height=height, bg='black')
            self.canvas.pack(fill='none', expand=False)
            self._oid = []
            self.canvas.after(10, self.move)
    
            self.queue = queue
            self.canvas.after(50, self.check_queue)
    
        def check_queue(self):
            try:
                x, y, rad, outline = self.queue.get(block=False)
            except Queue.Empty:
                pass
            else:
                self.create_moving_ball(x, y, rad, outline)
            self.canvas.after(50, self.check_queue)
    
        def move(self):
            width, height = self.width, self.height
            for i, (oid, r, angle, speed, (x, y)) in enumerate(self._oid):
                sx, sy = speed
                dx = sx * math.cos(angle)
                dy = sy * math.sin(angle)
                if y + dy + r> height or y + dy - r < 0:
                    sy = -sy
                    self._oid[i][3] = (sx, sy)
                if x + dx + r > width or x + dx - r < 0:
                    sx = -sx
                    self._oid[i][3] = (sx, sy)
                nx, ny = x + dx, y + dy
                self._oid[i][-1] = (nx, ny)
                self.canvas.move(oid, dx, dy)
            self.canvas.update_idletasks()
            self.canvas.after(10, self.move)
    
        def create_moving_ball(self, x=100, y=100, rad=20, outline='white'):
            oid = self.canvas.create_oval(x - rad, y - rad, x + rad, y + rad,
                    outline=outline)
            oid_angle = math.radians(random.randint(1, 360))
            oid_speed = random.randint(2, 5)
            self._oid.append([oid, rad, oid_angle, (oid_speed, oid_speed), (x, y)])
    
    def queue_create(queue, running):
        while running:
            if random.random() < 1e-6:
                print "Create a new moving ball please"
                x, y = random.randint(100, 150), random.randint(100, 150)
                color = random.choice(['green', 'white', 'yellow', 'blue'])
                queue.put((x, y, random.randint(10, 30), color))
            time.sleep(0) # Effectively yield this thread.
    
    root = Tkinter.Tk()
    running = [True]
    
    queue = Queue.Queue()
    
    app = App(queue)
    app.create_moving_ball()
    app.canvas.bind('<Destroy>', lambda x: (running.pop(), x.widget.destroy()))
    
    thread = threading.Thread(target=queue_create, args=(queue, running))
    thread.start()
    
    root.mainloop()
    

    【讨论】:

    • 递归不会导致maximum recursion depth exceeded 错误吗?如果需要实时更新,比如从串行读取输入时怎么办?
    • 这个答案已经有一段时间了,你指的是哪个递归? after 调用使用 Tcl 来安排未来的调用,它不应该导致您所指的错误。
    猜你喜欢
    • 2016-08-03
    • 2018-06-26
    • 1970-01-01
    • 2022-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多