【问题标题】:Why does updating tkinter widgets from a worker thread seem to work?为什么从工作线程更新 tkinter 小部件似乎有效?
【发布时间】:2014-07-15 17:14:37
【问题描述】:

我在研究 tkinter 多线程时看到的所有地方,我发现提到 tkinter 必须在主线程上运行(就像许多 GUI 框架一样),当一个单独的线程需要与 GUI 通信时, 必须使用队列而不是直接从工作线程访问小部件

我试图学习使用队列方法,但当然一开始我想看看如果我做错了会发生什么,所以我写了这段代码,它在几秒钟内逼近 Pi (π):

import tkinter as tk
from tkinter import ttk
from threading import Thread
import math

window = tk.Tk()
window.geometry("300x150")

lbl = tk.Label(window, text="Press Start")
lbl.place(width=280, height=60, x=10, y=10)

pb = ttk.Progressbar(window)
pb.place(width=280, height=25, x=10, y=80)

def calculate():
    """ 1 / i^2 =  PI^2 / 6 """
    s = 0.0
    for i in range(1, 10000001):
        s += (1 / i**2)
        if i % 1000000 == 0:            
            value = math.sqrt(s * 6)
            lbl.config(text=value) #???
            pb.step(10) #???

def start():
    lbl.config(text="Press Start")
    #calculate() #irresponsive GUI this way, obviously
    t = Thread(target=calculate)
    t.start()

btn = tk.Button(window, text="Start", command=start)
btn.place(width=280, height=25, x=10, y=115)

window.mainloop()

据我了解,??? 注释标记的行是问题所在。但是这段代码运行得很好。保持响应,标签和进度条都会更新。

这个跨线程错误是否有时会发生/有时不会发生?这段代码最终可能会破坏吗?还是我天真地认为唯一好的解决方案是排队?我相信在 C# 中这会产生一个cross-thread operation not valid,但 python 似乎没有问题。

【问题讨论】:

  • 在这段代码中,太简单了,没有问题。当您有许多线程试图同时更新同一个小部件时,就会出现问题。
  • @dilbert 我明白了,谢谢。
  • 我写了一个类似的代码,在 Mac (python 3.6) 上运行良好,但在 Linux (python 3.5) 上崩溃了。错误是“ out of stack space (infinite loop?)”

标签: python multithreading tkinter


【解决方案1】:

在普通的消费者应用程序中,有一件事情是不可接受的:当您点击“开始”按钮,然后在进度条完成之前关闭窗口时会发生什么?在具有相互依赖的部分的大型应用程序中,破坏在另一个线程中使用的 gui 元素可能会产生不愉快的后果。我发现在终端中运行时,该程序有时会在意外退出时挂起,以至于 ctrl-c 不起作用。

顺便说一句,

s += (1 / i ** 2)

行进行整数除法,所以s 的值只改变一次。

【讨论】:

  • 谢谢。是的,确实应该是//。我明白你关闭窗口的意思,但这也不能通过队列来解决,不是吗?所以这是一个单独的问题。
猜你喜欢
  • 2018-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-03
  • 2021-06-11
  • 1970-01-01
相关资源
最近更新 更多