【问题标题】:Change label value permanently in tkinter在 tkinter 中永久更改标签值
【发布时间】:2019-06-26 00:13:05
【问题描述】:

我想在我的 gui 上显示一个永久更改(温度)的动态数字。如何使我的标签动态化?

我尝试设置其他值,但知道在调用 mainLoop 后程序处于无限状态。我已经阅读了函数 .after() 但我不知道如何准确地使用它,因为我不想定义新函数。我得到一个返回值,只是想更新它。

import tkinter as tk
from src import SerialPort as sp

HEIGHT = 300
WIDTH = 500

root = tk.Tk()

canvas = tk.Canvas(root, height = HEIGHT, width = WIDTH)
canvas.pack()

aktTemp = tk.Label(root, text=str(sp.read_current_Temperature())+"°C", fg="red") 
aktTemp.pack()

root.mainloop()

sp.read_current_Temperature() - 它将返回当前温度,因此我希望标签基于此函数调用每秒刷新一次。

【问题讨论】:

    标签: python tkinter


    【解决方案1】:

    因此,在 tkinter 中不断更新某些内容的主要问题是,至少对于您的大部分程序,您都被锁定在主循环中。

    出于所有意图和目的,这基本上意味着在您的程序中,您永远不会真正调用最后一行,因为 Python 正在等待主循环结束。

    正如您正确推测的那样,我们解决此问题的方法是使用after() 函数。如果您还不知道如何使用它(并计划继续使用 tkinter),您绝对应该将它添加到您的工具包中。


    首先,我对您的程序进行了快速更改,以便获得作为温度返回的值。我这样做是为了演示如何更新文本小部件,它涉及添加一个仅返回随机值的新函数。

    import tkinter as tk
    import random
    
    def read_current_Temperature():
        return random.randint(1, 100)
    
    HEIGHT = 300
    WIDTH = 500
    
    root = tk.Tk()
    
    canvas = tk.Canvas(root, height = HEIGHT, width = WIDTH)
    canvas.pack()
    
    aktTemp = tk.Label(root, text=str(read_current_Temperature())+"°C", fg="red") 
    aktTemp.pack()
    
    root.mainloop()
    
    read_current_Temperature()
    

    现在,正如您在运行上述程序时看到的那样,我们基本上得到了与您的原始程序相同的结果。 读取温度(读取:随机生成),然后更新小部件,然后 . . .其他不多。


    所以,首先我们需要找到在哪里使用after()。有很多方法可以做到这一点,但最简单的方法(主观地,在这种情况下。我建议尽可能使用class,但这需要更多实质性的重写)是添加一个新函数,像下面这样:

    import tkinter as tk
    import random
    
    def read_current_Temperature():
        return random.randint(1, 100)
    
    def update():
        aktTemp.config(text=str(read_current_Temperature())+"°C")
        aktTemp.after(1000, update)
    
    HEIGHT = 300
    WIDTH = 500
    
    root = tk.Tk()
    
    canvas = tk.Canvas(root, height = HEIGHT, width = WIDTH)
    canvas.pack()
    
    aktTemp = tk.Label(root, text=str(read_current_Temperature())+"°C", fg="red") 
    aktTemp.pack()
    
    update()
    
    root.mainloop()
    

    让我们逐行看一下。


    update()
    

    我们点击的第一个新行(运行时,而不是读取时)是对我定义的新函数的调用,说到 . . .

    def update():
        aktTemp.config(text=str(read_current_Temperature())+"°C")
        aktTemp.after(1000, update)
    

    这个函数的第一行。 . .

        aktTemp.config(text=str(read_current_Temperature())+"°C")
    

    。 . .只是告诉程序去获取新温度并将其分配为标签小部件aktTemptext 属性。这是实际上在 GUI 中进行更改的行。

    另一方面,这条线。 . .

        aktTemp.after(1000, update)
    

    。 . .是我上面提到的after的使用。所有这一切都在说“每 1000 毫秒,调用函数 update()”,正如我们从上面所知道的,然后将标签更新为新的温度并开始另一个 1000 毫秒的延迟,然后再次调用自身。


    You can read more about after() here.

    【讨论】:

    • 我曾经在 Java 中编写类。这是必要的。但在 Python 中,我不需要它,它可以在不使用类 A_Class 的情况下工作。使用类重要吗?我的意思是我可以通过像 import Serialport as sp 这样导入然后使用 sp.Function() 或 sp.var 访问来访问我的所有函数或变量。
    • 类是我在 Python 中长期避免使用的东西。但是在某个时刻(尤其是使用 tkinter),我厌倦了不得不不断地来回传递变量以实际对现有小部件进行任何更改。这不是必需的,但很多生活 after() 如果您打算继续使用 tkinter,您应该将其添加到您的工具包中。
    【解决方案2】:

    不幸的是,要正确执行此操作,您必须至少定义一个新函数。我赞赏@EthanField 的详细解释(+1),但这是我使用 Tk 的 tracing 功能的替代实现:

    import tkinter as tk
    from src import SerialPort as sp
    
    WIDTH, HEIGHT = 500, 300
    
    def refresh_temperature(string):
        temperature.set(string.format(sp.read_current_Temperature()))
        root.after(1000, refresh_temperature, string)
    
    root = tk.Tk()
    
    canvas = tk.Canvas(root, height=HEIGHT, width=WIDTH)
    canvas.pack()
    
    temperature = tk.StringVar()
    
    aktTemp = tk.Label(root, textvariable=temperature, fg="red")
    aktTemp.pack()
    
    refresh_temperature("{} °C")
    
    root.mainloop()
    

    【讨论】:

    • 我将使用这个实现。我是否需要所有要更新上述显式函数的变量?我猜 refresh_temperature("{} °C") 中的 {} 类似于我刷新值的占位符?
    • @ebug38,如果您的其他变量以相同的频率(每秒一次)更新,您可以将它们添加到现有的 refresh_temperature() 函数中(根据需要重命名。)如果您还需要更新不同的频率,这可能是添加另一个功能的原因。 "{} °C" 只是一个 Python 3 str.format() 格式字符串。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多