在 tkinter 中不断更新图形

continuously updating graph in tkinter

我有以下 python 代码(在 PyCharm 中),用于从 Arduino 板上获取读数。读数本身很好。我在代码的 tkinter 部分有以下两个问题:

  1. 代码一开始就开始从Arduino读取值 已启动,而我想通过单击按钮启动它 ('read_data');只要我不按 'read_data' 按钮, 不显示图形,但会读取读数;我可以看到当 我在开始 运行 代码后几秒钟打开图表;
  2. 当我关闭图 close_plot 时,图 window 确实是 关门了,过一会儿才重新开门。

我认为问题出在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)

首先,删除行:

Top.after(100, read_data)

furas 建议的那样 立即 mainloop() 之前。

然后添加 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()