Python 基于串行数据动态更新Tkinter窗口
我正在尝试编写一个程序,从串行端口连接获取数据,并根据该数据实时自动更新Tkinter窗口 我尝试为窗口创建一个单独的线程,定期从主线程获取当前数据并更新窗口,如下所示:Python 基于串行数据动态更新Tkinter窗口,python,tkinter,Python,Tkinter,我正在尝试编写一个程序,从串行端口连接获取数据,并根据该数据实时自动更新Tkinter窗口 我尝试为窗口创建一个单独的线程,定期从主线程获取当前数据并更新窗口,如下所示: serialdata = [] data = True class SensorThread(threading.Thread): def run(self): serial = serial.Serial('dev/tty.usbmodem1d11', 9600) try:
serialdata = []
data = True
class SensorThread(threading.Thread):
def run(self):
serial = serial.Serial('dev/tty.usbmodem1d11', 9600)
try:
while True:
serialdata.append(serial.readline())
except KeyboardInterrupt:
serial.close()
exit()
class GuiThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.root = Tk()
self.lbl = Label(self.root, text="")
def run(self):
self.lbl(pack)
self.lbl.after(1000, self.updateGUI)
self.root.mainloop()
def updateGUI(self):
msg = "Data is True" if data else "Data is False"
self.lbl["text"] = msg
self.root.update()
self.lbl.after(1000, self.updateGUI)
if __name == "__main__":
SensorThread().start()
GuiThread().start()
try:
while True:
# A bunch of analysis that sets either data = True or data = False based on serialdata
except KeyboardInterrupt:
exit()
def poll_serial_port(self):
if serial.has_data():
data = serial.readline()
self.lbl.configure(text=data)
self.after(100, self.poll_serial_port)
运行它会导致以下错误:
线程2中的异常:
回溯(最近一次呼叫最后一次):
文件“/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/threading.py”,第522行,在bootstrap\u内部
self.run()
运行中第52行的文件“analysis.py”
self.lbl1.pack()
文件“/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/lib-tk/Tkinter.py”,第1764行,在pack_configure中
+自选配件(cnf,kw))
运行时错误:主线程不在主循环中
当我用谷歌搜索这个错误时,我得到的大多数帖子都是人们试图从两个不同的线程与窗口交互,但我认为我没有这样做。有什么想法吗?非常感谢 不要从线程运行TK gui—从主进程运行它。我把你的例子拼凑成了一个能说明原理的东西
from time import sleep
import threading
from Tkinter import *
serialdata = []
data = True
class SensorThread(threading.Thread):
def run(self):
try:
i = 0
while True:
serialdata.append("Hello %d" % i)
i += 1
sleep(1)
except KeyboardInterrupt:
exit()
class Gui(object):
def __init__(self):
self.root = Tk()
self.lbl = Label(self.root, text="")
self.updateGUI()
self.readSensor()
def run(self):
self.lbl.pack()
self.lbl.after(1000, self.updateGUI)
self.root.mainloop()
def updateGUI(self):
msg = "Data is True" if data else "Data is False"
self.lbl["text"] = msg
self.root.update()
self.lbl.after(1000, self.updateGUI)
def readSensor(self):
self.lbl["text"] = serialdata[-1]
self.root.update()
self.root.after(527, self.readSensor)
if __name__ == "__main__":
SensorThread().start()
Gui().run()
您需要将GUI放在主线程中,并使用单独的线程轮询串行端口。从串行端口读取数据时,可以将其推送到队列对象上 在主GUI线程中,您可以设置轮询以定期检查队列,方法是使用
after
计划轮询。调用一个函数,该函数消耗队列,然后在之后使用调用自身,以有效地模拟无限循环
如果来自传感器的数据以相当慢的速度传输,并且您可以轮询串行端口而不阻塞,那么您可以在主线程中完成这一切—而不是从队列中推拉,您的主线程只需查看是否有可用数据,并在有可用数据时读取即可。只有在可以不阻塞地读取的情况下才能执行此操作,否则GUI将在等待数据时冻结
例如,您可以使其工作如下:
serialdata = []
data = True
class SensorThread(threading.Thread):
def run(self):
serial = serial.Serial('dev/tty.usbmodem1d11', 9600)
try:
while True:
serialdata.append(serial.readline())
except KeyboardInterrupt:
serial.close()
exit()
class GuiThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.root = Tk()
self.lbl = Label(self.root, text="")
def run(self):
self.lbl(pack)
self.lbl.after(1000, self.updateGUI)
self.root.mainloop()
def updateGUI(self):
msg = "Data is True" if data else "Data is False"
self.lbl["text"] = msg
self.root.update()
self.lbl.after(1000, self.updateGUI)
if __name == "__main__":
SensorThread().start()
GuiThread().start()
try:
while True:
# A bunch of analysis that sets either data = True or data = False based on serialdata
except KeyboardInterrupt:
exit()
def poll_serial_port(self):
if serial.has_data():
data = serial.readline()
self.lbl.configure(text=data)
self.after(100, self.poll_serial_port)
上述操作将每秒检查串行端口10次,每次检查一个项目。当然,您必须根据您的实际数据条件对其进行调整。这假设您有一些方法,如has_data
,当且仅当读取不会阻塞时,该方法才能返回True 您是否尝试过在线程中运行TK部件?Ie只是在一个线程中运行串口,TK可以留在主进程中。我怀疑这可能会起作用…比如一个线程用于获取串行端口数据,另一个线程用于数据分析循环?我来试一试。你应该使用线程安全的队列
对象在线程之间进行通信,而不是使用简单的列表变量。这会更好。是的,但我的目的是向OP展示问题的解决方案,而不是教他们python IPC机制;-)