如何使用 window.mainloop 之外的回调函数更改 Tkinter 中的标签文本

how to change label text in Tkinter with callback function out of window.mainloop

im 触发回调函数 读取编码器输出 使用 GPIO.add_event_detect 所以 global counter 具有当前值,但我不能像使用 listbox.insert(END,counter)

那样将它传递给 tkinter
import RPi.GPIO as GPIO
from tkinter import ttk
import tkinter as tk

counter = 0

# GPIO Pins #
A = 17  
B = 27
#-----------#

# GPIO settings
GPIO.setwarnings(True)
GPIO.setmode(GPIO.BCM)
#
GPIO.setup(A, GPIO.IN)
GPIO.setup(B, GPIO.IN)

def Enc(A):
    global counter
    sleep(0.002)
    input_A = GPIO.input(A)
    input_B = GPIO.input(B)
    if (input_A == 1) and (input_B == 0):
        counter += 1
        print  (counter)

        #listbox.insert(END,counter)

    elif (input_A == 1) and (input_B == 1):
        counter -= 1
        print  (counter)

        #listbox.insert(END,counter)
    else:
        return

# GPIO output detection
GPIO.add_event_detect(A, GPIO.RISING, callback=Enc, bouncetime=10)

# window settings
window = tk.Tk()
window.title("encoder_value")

# string value?
window.Enc_counter_str = tk.StringVar(value=counter)

# label
tk.Label(window, text='Enc:',fg = "medium violet red", bg = "light grey", font = "Helvetica 16 bold italic").grid(column=0, row=0, **padding)

# output label
window.Enc_label = tk.Label(window)
window.Enc_label.grid(column=0, row=2, columnspan=1, **padding)
window.Enc_label.config(text=window.Enc_counter_str.get(),fg = "medium violet red", bg = "light grey", font = "Helvetica 16 bold italic")

# tk window loop
window.mainloop()

只需在 Enc 函数中使用 window.Enc_label["text"] = str(counter)

因此,根据我在阅读您的问题后的理解,您似乎在每次计数器值更改时尝试更新 window.Enc_label 的值。

这里的问题是这一行 -:

window.Enc_counter_str = tk.StringVar(value=counter)

此处,当您将字符串 var 的值设置为计数器时,您所做的只是分配计数器的“那个时间”值(假设执行此行时计数器为 1,因此字符串变量的值被分配为 1 而不是对实际变量的引用。)

但它有效,因为您确实希望初始值也相同。 另一个问题是您没有更新字符串 var 的值,因为您假设字符串 var 存储了计数器的引用,但它没有。

所以每次修改计数器的值时都可以这样做-:

def Enc(A):
    global counter
    sleep(0.002)
    input_A = GPIO.input(A)
    input_B = GPIO.input(B)
    if (input_A == 1) and (input_B == 0):
        counter += 1
        print  (counter)
    elif (input_A == 1) and (input_B == 1):
        counter -= 1
        print  (counter)
    else:
        return
    window.Enc_counter_str.set(counter)

现在您还希望 Label 对象立即知道字符串变量是从中获取值的位置,因此它会定期检查它是否有更新,您可以像这样传递 textvariable 参数来实现-:

window.Enc_label = tk.Label(window, textvariable = window.Enc_counter_str)

还有另一种方法,虽然不是很简洁,但也是一个可行的解决方案,就是你 运行 每次更新计数器时都使用这一行 -:

window.Enc_label.config(text=window.Enc_counter_str.get(),fg = "medium violet red", bg = "light grey", font = "Helvetica 16 bold italic")

现在这一行目前您只是 运行正在初始化 Label 对象,因此文本不会更新。

但是使用我们的第一种方法,这一行可以缩短为 -:

window.Enc_label.config(fg = "medium violet red", bg = "light grey", font = "Helvetica 16 bold italic")

现在还要确保将标签声明放在函数之前,以便 python 已经知道您引用的字符串变量。

最终代码变为-:

import RPi.GPIO as GPIO
from tkinter import ttk
import tkinter as tk

counter = 0

# GPIO Pins #
A = 17  
B = 27
#-----------#

# GPIO settings
GPIO.setwarnings(True)
GPIO.setmode(GPIO.BCM)
#
GPIO.setup(A, GPIO.IN)
GPIO.setup(B, GPIO.IN)

# window settings
window = tk.Tk()
window.title("encoder_value")

# string value?
window.Enc_counter_str = tk.StringVar(value=counter)

# label
tk.Label(window, text='Enc:',fg = "medium violet red", bg = "light grey", font = "Helvetica 16 bold italic").grid(column=0, row=0, **padding)

# output label
window.Enc_label = tk.Label(window, textvariable = window.Enc_counter_str) # CHANGE 1
window.Enc_label.grid(column=0, row=2, columnspan=1, **padding)
window.Enc_label.config(fg = "medium violet red", bg = "light grey", font = "Helvetica 16 bold italic") # CHANGE 2

def Enc(A):
    global counter
    sleep(0.002)
    input_A = GPIO.input(A)
    input_B = GPIO.input(B)
    if (input_A == 1) and (input_B == 0):
        counter += 1
        print  (counter)
    elif (input_A == 1) and (input_B == 1):
        counter -= 1
        print  (counter)
    else:
        return
    window.Enc_counter_str.set(counter) # CHANGE 3

# GPIO output detection
GPIO.add_event_detect(A, GPIO.RISING, callback=Enc, bouncetime=10)

# tk window loop
window.mainloop()