不断更新 tkinter 中的图形
Posted
技术标签:
【中文标题】不断更新 tkinter 中的图形【英文标题】:continuously updating graph in tkinter 【发布时间】:2017-12-25 16:01:40 【问题描述】:我有以下 python 代码(在 PyCharm 中),用于从 Arduino
板上读取读数。读数本身很好。我的代码的 tkinter 部分有以下两个问题:
-
代码开始从 Arduino 读取值
已启动,而我想在单击按钮时启动它
('read_data');只要我不按“read_data”按钮,
不显示图表,但会读取读数;我可以看到,当
我在开始运行代码几秒钟后打开图表;
当我关闭绘图
close_plot
时,图形窗口确实是
已关闭,不久后将重新打开。
我认为问题在于Top.after
,因为它在mainloop()
内不断运行,因此read_data
函数不断更新。我该如何解决这个问题?
import serial
from tkinter import *
from matplotlib import pyplot as plt
Top = Tk()
ser = serial.Serial('COM3', baudrate=9600, timeout=1)
x = []
y = []
def read_data():
plt.ion()
new_value = ser.readline().decode('ascii')
if new_value == '':
pass
else:
y.append(eval(new_value[:-2]))
x.append(len(y) - 1)
plt.plot(x, y, 'r-')
plt.show()
plt.pause(0.0001)
Top.after(100, read_data)
def close_plot():
plt.close()
global x, y
x = []
y = []
def quit():
Top.destroy()
Button(Top, text='Read', command=read_data).pack()
Button(Top, text='Close plot', command=close_plot).pack()
Button(Top, text='Quit', command=quit).pack()
Top.after(100, read_data)
mainloop()
编辑:按下read_data
按钮时,我收到以下警告:
C:\ProgramData\Anaconda3\lib\site-packages\matplotlib\backend_bases.py:2445: MatplotlibDeprecationWarning: Using default event loop until function specific to this GUI is implemented warnings.warn(str, mplDeprecation)
【问题讨论】:
1.在mainloop()
之前删除 Top.after(100, read_data)
- 它在程序启动后 100 毫秒开始读取。
顺便说一句:阅读PEP 8 -- Style Guide for Python Code。我们只对Button
、Tk
或Serial
等类名使用“大写名称”,但对Top
等变量不使用。它使代码更具可读性。就连***
都知道这个规则,并且在课堂上使用浅蓝色。
@furas:恐怕你的建议没有帮助,代码一运行就开始阅读
您是否删除了正确的after()
- 在mainloop()
之前。如果您仍然有问题,那么也许您使用的代码与您在问题中显示的代码不同 - 即。你可能在command=read_data()
中有()
尝试在没有 PyCharm 的情况下运行它 - 也许 PyCharm 存在一些问题。或者问题出在 Anaconda - 我仅使用标准 Python 安装进行了测试,没有收到错误 "MatplotlibDeprecationWarning"
。
【参考方案1】:
首先,删除该行:
Top.after(100, read_data)
在mainloop()
之前立即出现,就像furas 建议的那样。
然后添加 after_cancel
方法以停止每 100 毫秒调用一次 read_data
,但要使其正常工作,我们需要先将我们在方法内部使用的 after
分配给全局变量:
func_id = Top.after(100, read_data)
然后最后在close_plot
中调用after_cancel
:
Top.after_cancel(func_id)
你的代码应该和下面完全一样:
import serial
from tkinter import *
from matplotlib import pyplot as plt
Top = Tk()
ser = serial.Serial('COM3', baudrate=9600, timeout=1)
x = []
y = []
func_id = None
def read_data():
global func_id
plt.ion()
new_value = ser.readline().decode('ascii')
if new_value == '':
pass
else:
y.append(eval(new_value[:-2]))
x.append(len(y) - 1)
plt.plot(x, y, 'r-')
plt.show()
plt.pause(0.0001)
func_id = Top.after(100, read_data)
def close_plot():
global func_id
#to no longer update the plot
Top.after_cancel(func_id)
plt.close()
global x, y
del x[:]
del y[:]
def quit():
Top.destroy()
Button(Top, text='Read', command=read_data).pack()
Button(Top, text='Close plot', command=close_plot).pack()
Button(Top, text='Quit', command=quit).pack()
mainloop()
【讨论】:
我会将after()
放在if/else
之外,这样它就可以一直读取 - 但我无法对其进行测试。
顺便说一句:我尝试在 Linux 上使用socat
来测试它以创建假串行端口 - 就像在回答 ***.com/a/23255001/1832058 中一样
感谢您的帮助,但即使我复制了您的代码,我也无法正常工作。错误重复出现。此外,我收到以下警告: MatplotlibDeprecationWarning: Using default event loop until function specific to this GUI is implemented warnings.warn(str, mplDeprecation)
@DenGor 请附加导致该错误的 MCVE 代码片段,并在您的问题中发布完整的错误消息。
@DenGor 在这里更新了答案,现在应该可以了。以上是关于不断更新 tkinter 中的图形的主要内容,如果未能解决你的问题,请参考以下文章
使用带有 pylab/matplotlib 嵌入的 Tkinter 播放、暂停、停止功能的彩色绘图动画:无法更新图形/画布?