如何在window.mainloop外通过GPIO回调函数修改Tkinter的Label文本
问题根因
- Tkinter 的所有UI操作必须在主线程(即
window.mainloop()所在的线程)执行,GPIO.add_event_detect触发的回调函数是在独立子线程中运行的,直接在回调中修改UI组件、更新Tkinter变量都不会生效,严重时还会导致程序崩溃 - 你的代码仅在初始化时给标签赋值了一次计数器值,没有将标签和
StringVar绑定,后续计数器变化不会自动同步到UI - 代码存在缺项:没有导入
sleep依赖,padding变量未定义
修复方案
- 调整代码执行顺序,先初始化Tkinter窗口,再定义GPIO回调,保证回调中可以访问到窗口对象
- 给显示计数器的标签绑定
textvariable属性,修改StringVar即可自动更新标签显示 - 新增单独的UI更新函数,通过Tkinter内置的
after方法将UI更新操作投递到主线程执行
修复后完整代码
import RPi.GPIO as GPIO from tkinter import ttk import tkinter as tk from time import sleep counter = 0 # 先初始化Tk窗口 window = tk.Tk() window.title("encoder_value") # 定义padding变量 padding = {'padx': 10, 'pady': 10} # 绑定计数器变量 window.Enc_counter_str = tk.StringVar(value=counter) # UI布局 tk.Label(window, text='Enc:',fg = "medium violet red", bg = "light grey", font = "Helvetica 16 bold italic").grid(column=0, row=0, **padding) # 标签绑定textvariable,变量更新时自动刷新显示 window.Enc_label = tk.Label(window, textvariable=window.Enc_counter_str,fg = "medium violet red", bg = "light grey", font = "Helvetica 16 bold italic") window.Enc_label.grid(column=0, row=2, columnspan=1, **padding) # UI更新函数,所有UI操作都放在这个函数里 def update_ui(): window.Enc_counter_str.set(counter) # 如果需要插入listbox,也可以在这里加:listbox.insert(tk.END, counter) # GPIO Pins A = 17 B = 27 # GPIO设置 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) # 将UI更新投递到主线程执行 window.after(0, update_ui) elif (input_A == 1) and (input_B == 1): counter -= 1 print(counter) window.after(0, update_ui) else: return # GPIO事件检测 GPIO.add_event_detect(A, GPIO.RISING, callback=Enc, bouncetime=10) # 启动主循环 window.mainloop() # 程序退出后清理GPIO GPIO.cleanup()
内容的提问来源于stack exchange,提问作者unspecified
相关产品推荐
相关产品推荐

