【问题标题】:Python two loops simultaneously with tkinterPython 使用 tkinter 同时循环两个循环
【发布时间】:2025-12-01 11:00:02
【问题描述】:

我有两个框架的 Tkinter GUI 应用程序。我想要做的是同时运行两个无限循环。 而一个循环可以从另一个循环中获取数据。

我有 main.py

class Main(tk.Tk):

    def __init__(self, *args, **kwargs):
        
        tk.Tk.__init__(self, *args, **kwargs)
        container = tk.Frame(self)
.....
.....

app = Main()
app.mainloop()

然后两个帧首先是 startPage.py,其中只有一个按钮重定向到experimentPage.py。 最后一个重要的框架。 ExperimentPage.py 这两个循环在哪里。

class experimentPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        // ButtonX that start two loops //
    .... 
    ....
    def loop1(self)
    def loop2(self) // Getting data from loop1

我要做的基本上是同时运行loop1和loop2,而loop2可以从loop1获取数据。现在我不确定如何实现这一点,我所有的尝试都失败了。

如果我理解正确,我必须使用 asyncio 修改 main.py mainloop。并用 asyncio 修改实验页面。使用async def loop1(self) 就可以了。但无论我尝试什么都以错误结束。

编辑 1 - 在这我只有一个循环。但是在那个循环中,我从眼球追踪器获取数据,将它们绘制在屏幕上并进行一些计算。问题是它从我实际查看的位置和绘制的内容中得到了一些延迟。这就是为什么我想要两个循环。一个用于来自眼球追踪器的实时数据。还有一个用于绘图和计算的东西。

编辑 2 - 问题是我不知道如何正确编辑 mainloop 以运行异步任务,因为我发现的所有内容也都与线程有关。我尝试了 app.asyncio.mainloop() 之类的东西,它以 AttributeError 之类的错误结束:'_tkinter.tkapp' object has no attribute 'asyncio' 我只使用 python 几天,所以我可能会遗漏一些基本的东西。

【问题讨论】:

  • 您能否更具体地了解循环,而不仅仅是 tkinter。为什么需要两个循环?他们在做什么单循环不会做的事情。
  • 您要解决的问题是什么?您的问题暗示了一种有缺陷的方法。
  • 感谢您的反应,我将它们添加为对我的问题的编辑。
  • 为什么不想使用线程?这不是显而易见的解决方案吗?
  • @wuerfelfreak 我认为异步方法比线程更容易,这就是我决定使用异步的原因。但我可能会切换到线程感谢您的评论。

标签: python python-3.x asynchronous tkinter async-await


【解决方案1】:

可以这样使用:

def loop2(self):
    while !self.stopSignal:
        #do stuff here

def start_loops():
    self.stopSignal = False
    
    thread = threading.Thread(target=loop2, args=(self,))
    thread.start()
    loop1(self)
    self.stopSignal = True
    thread.join()

【讨论】:

    【解决方案2】:

    您可以使用计时器来实现这一点。

    在 Tkinter 中,你可以使用tk.after

    from tkinter import *
    import cv2
    from PIL import Image,ImageTk
    
    
    def take_snapshot():
        print("some one like it")
    
    def video_loop():
        success, img = camera.read()  # read image with camera
        if success:
            # cv2.waitKey(1) # this line is not necessary in Tkinter
            cv2image = cv2.cvtColor(img, cv2.COLOR_BGR2RGBA) #convert color from BGR to RGBA
            current_image = Image.fromarray(cv2image) #convert to Image for Tkinter
            imgtk = ImageTk.PhotoImage(image=current_image)
            panel.imgtk = imgtk
            panel.config(image=imgtk)
            root.after(1, video_loop)
    
    
    camera = cv2.VideoCapture(0)    #camera
    
    root = Tk()
    root.title("opencv + tkinter")
    #root.protocol('WM_DELETE_WINDOW', detector)
    
    panel = Label(root)  # initialize image panel
    panel.pack(padx=10, pady=10)
    root.config(cursor="arrow")
    btn = Button(root, text="Like!", command=take_snapshot)
    btn.pack(fill="both", expand=True, padx=10, pady=10)
    
    video_loop()
    
    root.mainloop()
    # before quit the program, release all the resources
    camera.release()
    cv2.destroyAllWindows()
    

    【讨论】: