【问题标题】:python Tkinter multithreadingpython Tkinter 多线程
【发布时间】:2018-06-26 19:21:19
【问题描述】:

我正在尝试让两个球在屏幕上移动,位置正在用线程更新,主线程正在更新图形这是我的代码:

from tkinter import *
from threading import *
import time

width = 500
height = 500


class Ball(Thread):
    def __init__(self, canvas, x1, y1, x2, y2, color):
        super().__init__()
        self.x1 = x1
        self.y1 = y1
        self.x2 = x2
        self.y2 = y2
        self.x_velocity = 9
        self.y_velocity = 5
        self.canvas = canvas
        self.id = self.canvas.create_oval(self.x1, self.y1, self.x2, self.y2, fill=color)

    def update(self):
        self.canvas.move(self.id, self.x_velocity, self.y_velocity)
        pos = self.canvas.coords(self.id)
        if pos[0] <= 0 or pos[2] >= width:
            self.x_velocity *= -1
        if pos[1] <= 0 or pos[3] >= height:
            self.y_velocity *= -1

    def run(self):
        self.update()


def main():
    master = Tk()
    canvas = Canvas(master=master, bg='Grey', width=width, height=height)
    ball1 = Ball(canvas=canvas, x1=10, y1=10, x2=40, y2=40, color='Black')
    ball2 = Ball(canvas=canvas, x1=50, y1=50, x2=80, y2=80, color='Red')
    canvas.pack()
    ball1.start()
    ball2.start()
    while 1:
        master.update()
        time.sleep(0.04)


if __name__ == '__main__':
    main()

似乎不工作出了什么问题以及如何处理? 错误信息是:

Exception in thread Thread-2: Traceback (most recent call last):   File "/home/muhammad_essam/anaconda3/lib/python3.6/threading.py", line 916, in _bootstrap_inner
    self.run()   File "/mnt/sda6/CSE/Project/GUI/Learnning/GUI101/main.py", line 30, in run
    self.update()   File "/mnt/sda6/CSE/Project/GUI/Learnning/GUI101/main.py", line 22, in update
    self.canvas.move(self.id, self.x_velocity, self.y_velocity)   File "/home/muhammad_essam/anaconda3/lib/python3.6/tkinter/__init__.py", line 2585, in move
    self.tk.call((self._w, 'move') + args)
_tkinter.TclError: out of stack space (infinite loop?)

Exception in thread Thread-1: Traceback (most recent call last):   File "/home/muhammad_essam/anaconda3/lib/python3.6/threading.py", line 916, in _bootstrap_inner
    self.run()   File "/mnt/sda6/CSE/Project/GUI/Learnning/GUI101/main.py", line 30, in run
    self.update()   File "/mnt/sda6/CSE/Project/GUI/Learnning/GUI101/main.py", line 22, in update
    self.canvas.move(self.id, self.x_velocity, self.y_velocity)   File "/home/muhammad_essam/anaconda3/lib/python3.6/tkinter/__init__.py", line 2585, in move
    self.tk.call((self._w, 'move') + args)
_tkinter.TclError: out of stack space (infinite loop?)

【问题讨论】:

  • 您没有按照您认为的方式使用线程。所有的运动都发生在主线程中,因为那是你的无限循环所在。 Tkinter 并非旨在在一个线程中创建小部件,然后在另一个线程中更新它们。
  • 所以我需要的是我有一个多代理,每个代理都在一个线程上运行,每个线程都没有更新它们的位置我需要在 GUI 中更新主题我应该用作库@布莱恩奥克利
  • 说实话,你根本不需要线程。假设你的球不超过几百个,那么一个线程就足够强大了。
  • 查看此示例了解不使用线程的解决方案:stackoverflow.com/a/25431690/7432

标签: python multithreading tkinter python-multithreading tkinter-canvas


【解决方案1】:

您的程序并不难修改,因此它使用 GUI 主循环和after 方法调用。 main 函数中的代码可能应该封装在一个继承自 tkinter.Frame 的类中,但下面的示例是完整的,并演示了一种可能的解决方案:

#! /usr/bin/env python3
import tkinter

FPS = 25
WIDTH, HEIGHT = 500, 500


def main():
    tkinter.NoDefaultRoot()
    root = tkinter.Tk()
    root.resizable(False, False)
    canvas = tkinter.Canvas(root, bg='grey', width=WIDTH, height=HEIGHT)
    canvas.grid()
    balls = (
        Ball(canvas, 10, 10, 40, 40, 'black'),
        Ball(canvas, 50, 50, 80, 80, 'red')
    )
    root.after(1000 // FPS, update_balls, root, balls)
    root.mainloop()


def update_balls(root, balls):
    root.after(1000 // FPS, update_balls, root, balls)
    for ball in balls:
        ball.update()


class Ball:
    def __init__(self, canvas, x1, y1, x2, y2, color):
        self.__canvas = canvas
        self.__x_velocity = 9
        self.__y_velocity = 5
        self.__id = canvas.create_oval(x1, y1, x2, y2, fill=color)

    def update(self):
        self.__canvas.move(self.__id, self.__x_velocity, self.__y_velocity)
        x1, y1, x2, y2 = self.__canvas.coords(self.__id)
        if x1 < 0 or x2 > WIDTH:
            self.__x_velocity *= -1
        if y1 < 0 or y2 > HEIGHT:
            self.__y_velocity *= -1


if __name__ == '__main__':
    main()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-08-03
    • 1970-01-01
    • 2022-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-10
    相关资源
    最近更新 更多