【问题标题】:How to update labels in tkinter dynamically?如何动态更新 tkinter 中的标签?
【发布时间】:2018-07-13 21:24:35
【问题描述】:

我创建了这个代码,它每秒更新一个标签以指示正在加载某些内容(运行代码以了解我的意思)。我正在使用带有 tkinter 的线程模块,但我觉得必须有一种更有效的方法来做到这一点。

这是我的代码:

from tkinter import *
from time import sleep
import threading

root = Tk()
new_var = StringVar()
new_var.set('Loading')

def change_text():
    array = [".", "..", "...", ""]
    while True:
        for num in range(4):
            sleep(1)
            new_var.set(f"Loading{array[num]}")
            root.update_idletasks()

l = Label(root, textvariable = new_var)
l.pack()

Loading_animation = threading.Thread(target=change_text)
Loading_animation.start()
root.mainloop()

另外,如果没有更好的方法来做到这一点,我该如何防止在关闭根窗口时不断收到错误?

谢谢!

【问题讨论】:

  • @IgorS 这并没有解决潜在的错误。我相信潜在的错误是我没有重新加入我创建的第二个线程,但我不知道该怎么做,因为我的代码最后卡在了“root.mainloop()”中。

标签: python multithreading tkinter


【解决方案1】:

这是一个不涉及线程的更简单的方法。

保留一个计数器,每秒调用一次该函数。在函数中,只需通过计数器将文本设置为列表中的每个项目作为索引。

更新:在 cmets 中回答您的问题。

这不会卡在阻止我们到达mainloop() 的循环中,因为此代码仅添加了一个命令,该命令以 1 秒的固定间隔在事件列表上运行。实际发生的是after() 方法将添加一个新的甚至运行不超过 1 秒(1000 毫秒)。因为 Tkinter 是事件驱动的,所以 Tkinter 会在每个 mainloop() 循环之后处理列表中的每一个。

import tkinter as tk

root = tk.Tk()
counter = 0

def change_text():
    global counter
    my_list = [".", "..", "...", ""]
    if counter != 3:
        l.config(text="Loading{}".format(my_list[counter]))
        counter += 1
        root.after(1000, change_text)
    else:
        l.config(text="Loading{}".format(my_list[counter]))
        counter = 0
        root.after(1000, change_text)

l = tk.Label(root, text = "")
l.pack()

change_text()
root.mainloop()

【讨论】:

  • 感谢 Mike,代码完全按照我的意愿工作,但有一件事我不明白。代码不应该卡在change_text()循环中,因此无法执行root.mainloop()来创建窗口吗?
【解决方案2】:

这里的答案与@Mike-SMT 相同,但使用循环功能使其更整洁。

import tkinter as tk
from itertools import cycle

root = tk.Tk()
my_list = cycle([".", "..", "...", ""])

def change_text():
    l.config(text="Loading{}".format(next(my_list)))
    root.after(1000, change_text)

l = tk.Label(root)
l.pack()

change_text()
root.mainloop()

【讨论】:

  • 我和 Mike 有同样的问题 - 脚本如何能够执行 root.mainloop(),因为它不应该卡在无限的 change_test() 循环中吗?
  • 主循环是一个无限循环,它不断检查是否发生了需要响应的事件。它还会检查已安排的事件列表,以查看是否是时候执行其中之一了。 after 函数不是一个循环,它所做的只是将一个事件添加到计划的事件列表中,在您的情况下,它添加“在 current_time + 1000 运行 change_test 函数”。然后它返回。它不会像sleep 那样阻塞。当 mainloop 看到时间大于预定时间时,就运行 change_text,这当然会导致另外一个事件调度。
  • TLDR: after 不是循环,但它修改了主循环,所以我们可以像循环一样使用它。
  • @Novel 我喜欢这个。我知道itertools,但到目前为止从未需要它们,所以我没有想到。
猜你喜欢
  • 1970-01-01
  • 2015-12-08
  • 1970-01-01
  • 1970-01-01
  • 2017-03-21
  • 1970-01-01
  • 2012-12-26
  • 2017-04-12
  • 1970-01-01
相关资源
最近更新 更多