如何持续将实时更新的串口数据数组传递给多个函数且不阻塞GUI?
解决方案
核心改动点如下:
- 替换阻塞式的
time.sleep()+自定义循环为Tkinter自带的非阻塞after()定时调度,完全不影响GUI渲染 - 串口/模拟数据读取逻辑仅保留1份作为全局数据源,所有需要消费数据的控件统一从该数据源取值,仅在定时调度时触发一次数据更新+所有关联控件刷新,不会产生冗余延迟
修改后的可运行代码:
import numpy as np import time import tkinter as tk import serial # 串口初始化 实际使用时取消注释即可 """ ser = serial.Serial( port='/dev/ttyUSB0', baudrate = 500000, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS, timeout=1 ) ser.flushInput() ser.flushOutput() """ # 唯一数据源读取逻辑 仅保留1份 def get_serial_data(): # 实际使用时替换为下面的串口读取逻辑 # serialData = ser.readline() # serialData = serialData.decode() # floats = [float(value) for value in serialData.split(',')] # arr = np.array(floats) arr = np.random.rand(100) return arr # 全局存储最新的串口数据 latest_arr = get_serial_data() # 存储所有需要刷新的控件回调,方便扩展多控件 update_callbacks = [] def update_data(): global latest_arr # 仅更新一次数据 latest_arr = get_serial_data() # 触发所有绑定的控件刷新 for callback in update_callbacks: callback(latest_arr) # 1000ms后再次调用自身,非阻塞 root.after(1000, update_data) def nextWindow(root): frame1 = tk.Frame(root, width=800, height=500) frame1.pack() text= tk.Text(frame1, width=80, height= 12, bd=0) text.pack() # 定义当前text控件的刷新逻辑 def refresh_text(arr): text.delete("1.0",tk.END) text.insert(tk.INSERT, np.round(arr, 3)) # 把刷新逻辑注册到全局回调列表里 update_callbacks.append(refresh_text) # 首次渲染 refresh_text(latest_arr) root = tk.Tk() root.title('PythonGuides') root.geometry('300x200') root.config(bg='#4a7a8c') nextWindow(root) # 启动定时更新任务 update_data() root.mainloop()
扩展说明
- 如果需要新增其他函数/控件使用串口数据,仅需要两步:定义对应控件的刷新函数,把刷新函数添加到
update_callbacks列表即可,不需要重复编写串口读取逻辑 - 如果串口读取耗时较高,可单独开子线程读取串口数据写入队列,主线程在
update_data中从队列取最新数据即可,进一步避免串口读操作阻塞GUI
内容的提问来源于stack exchange,提问作者Riccardo
相关产品推荐
相关产品推荐

