Python tkinter中的连续更新图

Python tkinter中的连续更新图,python,tkinter,pyserial,Python,Tkinter,Pyserial,我有以下python代码(在PyCharm中),用于从Arduino板读取数据。读数本身很好。我对代码的tkinter部分有以下两个问题: 代码一启动就开始从Arduino读取值 已启动,而我希望通过单击按钮启动此操作 (“读取数据”);只要我不按“读取数据”按钮 不显示图形,但读取读数;我可以看到,当 我在开始运行代码几秒钟后打开图形 当我关闭绘图close\u plot时,图形窗口确实处于关闭状态 已关闭,但不久后将重新打开 我认为问题在于Top.after,因为它在mainloop()中连

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

  • 代码一启动就开始从Arduino读取值 已启动,而我希望通过单击按钮启动此操作 (“读取数据”);只要我不按“读取数据”按钮 不显示图形,但读取读数;我可以看到,当 我在开始运行代码几秒钟后打开图形
  • 当我关闭绘图
    close\u plot
    时,图形窗口确实处于关闭状态 已关闭,但不久后将重新打开
  • 我认为问题在于
    Top.after
    ,因为它在
    mainloop()
    中连续运行,因此,
    read\u 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)
    
    它紧跟在
    mainloop()之前,就像建议的那样

    然后添加
    after\u cancel
    方法停止调用
    read\u data
    每100毫秒一次,但要使其起作用,我们需要在方法内部使用的
    之后首先将
    赋值给全局变量:

    func_id = Top.after(100, read_data)
    
    然后在
    close\u plot
    中取消后调用

    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()
    

    1.移除
    Top.after(100,读取数据)
    before
    mainloop()
    -它在程序启动后100毫秒开始读取。顺便说一下:读取。我们仅将“大写名称”用于类名称,如
    按钮
    Tk
    序列
    ,但不用于
    Top
    等变量。它使代码更具可读性。即使是
    Stackoverflow
    也知道这条规则,并对类使用浅蓝色。@furas:恐怕你的建议没有帮助,代码一运行就开始阅读。你是否删除了正确的
    after()
    -before
    mainloop()
    。如果您仍然有问题,那么可能您使用了与问题中显示的不同的代码-即,您可能在
    command=read_data()
    中使用了
    ()
    ,请尝试在没有PyCharm的情况下运行它-可能PyCharm存在一些问题。或者问题是Anaconda-我只使用标准Python安装进行了测试,没有得到错误
    “MatplotlibDeprecationWarning”
    。我会在()后面加上
    external
    if/else
    所以它会一直读-但我不能测试它。顺便说一句:我尝试在Linux上使用
    socat
    创建假串行端口来测试它-就像在回答中一样,我感谢你的帮助,但我无法让它工作,即使我复制了你的代码。这些错误重复出现。此外,我还收到以下警告:MatplotlibDeprecationWarning:在实现此GUI特定的函数之前使用默认事件循环警告。warn(str,mpldprecation)@DenGor请将导致该错误的MCVE代码段附加到您的问题中,并发布完整的错误消息。@DenGor在此处更新了答案,现在它应该可以工作了。