【问题标题】:Problems with matplotlib and tkinter: Exception in Tkinter callbackmatplotlib 和 tkinter 的问题:Tkinter 回调中的异常
【发布时间】:2020-07-09 01:41:55
【问题描述】:

我使用 tkinter 构建了一个带有 3 个按钮的简单 GUI 窗口,并使用 matplotlib 显示了一个简单的图形。过程是:按下第一个按钮启用第二个按钮。按第二个按钮显示一个数字,然后启用第三个按钮。按第三个按钮显示图形并保存图形。 但是,按下第二个按钮后,第三个按钮将无法启用。如果我关闭程序,则会发生错误。 另一个问题:为什么保存的图片是空的?谢谢。

import matplotlib.pyplot as plt
from tkinter import *
import numpy as np

class MyGUI:
    def __init__(self):
        Win=Tk()
        Win.geometry('750x640')
        Win.resizable(False,False)
        Win.update()
        w=Win.winfo_width()
        h=Win.winfo_height()

        Btn1=Button(Win,text='enable button 2',command=self.Btn1Listener)
        Btn1.place(x=20,y=20)
        Btn1.update()

        self.Btn2=Button(Win,text='Plot 1',command=self.Btn2Listener)
        self.Btn2.place(x=Btn1.winfo_x()+Btn1.winfo_width()+10,y=20,width=150)
        self.Btn2.configure(state='disabled')
        self.Btn2.update()

        self.Btn3=Button(Win,text='plot 2',command=self.Btn3Listener)
        self.Btn3.place(x=self.Btn2.winfo_x()+self.Btn2.winfo_width()+10,y=20,width=150)
        self.Btn3.configure(state='disabled')
        self.Btn3.update()        

        mainloop()

    #------------------------------------------------------- 
    def Btn1Listener(self):
        self.Btn2.configure(state='normal')

    def Btn2Listener(self):
        global v,s
        v,s=self.B1()
        self.Btn3.configure(state='normal')

    def Btn3Listener(self):
        self.B2(s,v)

    #-------------------------------------------------------------
    def B1(self):                  
        x=np.arange(0,5,0.1)
        y1=np.sin(x)
        plt.plot(x,y1)
        plt.show()

        return 0,5 

    def B2(self, s,v):
        x=np.arange(s,v,0.1)
        y1=np.sin(x)
        plt.plot(x,y1)
        plt.show()   
        plt.savefig('aaa.png')


#------------------------------------------------------------------        
if __name__ =='__main__':   
    MyApp=MyGUI()

【问题讨论】:

    标签: tkinter


    【解决方案1】:

    从docs of plt.show()可以看出这个函数的作用是:

    显示所有图形和块

    因为 Tkinter 依赖于 mainloop 来运行,所以这不适用于 plt.show() 等阻塞函数。

    再次来自文档:

    单个实验性关键字参数 block 可以设置为 True 或 False 以覆盖上述阻止行为。

    这意味着您可以调用plt.show(block=False) 使其不会阻塞 Tkinter 主循环。

    但是,有一种更简洁的方法可以将 matplotlib 集成到 Tkinter 中,可以在 here 找到一个示例。在最简单的实现中,这将转化为您的代码,如下所示:

    from tkinter import *
    import numpy as np
    
    from matplotlib.figure import Figure
    from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2TkAgg)
    
    class MyGUI:
        def __init__(self):
            win = Tk()
            win.geometry('750x640')
            win.resizable(False,False)
            win.update()
            w = win.winfo_width()
            h = win.winfo_height()
    
            btn1 = Button(win,text='Enable button 2',command=self.btn1Listener)
            btn1.place(x=20, y=20)
            btn1.update()
    
            self.btn2 = Button(win,text='Plot 1',command=self.btn2Listener)
            self.btn2.place(x=btn1.winfo_x()+btn1.winfo_width()+10, y=20, width=150)
            self.btn2.configure(state='disabled')
            self.btn2.update()
    
            self.btn3 = Button(win,text='Plot 2',command=self.btn3Listener)
            self.btn3.place(x=self.btn2.winfo_x()+self.btn2.winfo_width()+10, y=20, width=150)
            self.btn3.configure(state='disabled')
            self.btn3.update()
    
    
            self.fig = Figure(figsize=(5, 4), dpi=100)
            self.ax = self.fig.add_subplot(111)
    
            self.canvas = FigureCanvasTkAgg(self.fig, master=win)  # A tk.DrawingArea.
            self.canvas.draw()
            self.canvas.get_tk_widget().place(x=20, y=80)
    
            win.mainloop()
    
        #------------------------------------------------------- 
        def btn1Listener(self):
            self.btn2.configure(state='normal')
    
        def btn2Listener(self):
            self.s, self.v = self.B1()
            self.btn3.configure(state='normal')
    
        def btn3Listener(self):
            self.B2(self.s, self.v)
    
        #-------------------------------------------------------------
        def B1(self):                  
            x=np.arange(0, 5, 0.1)
            y1=np.sin(x)
            self.ax.plot(x, y1)
            self.canvas.draw()
            return 0,5 
    
        def B2(self, s, v):
            x=np.arange(s, v, 0.1)
            y1=np.cos(x)
            # Use this if you want to remove the first plot
            # self.ax.clear()
            self.ax.plot(x, y1)
            self.canvas.draw()
            self.fig.savefig('aaa.png')
    
    
    #------------------------------------------------------------------        
    if __name__ =='__main__':   
        MyApp=MyGUI()
    

    附:我不推荐使用place,因为从长远来看它很难管理并且不喜欢调整窗口大小。尝试使用 grid 和/或 pack 来设置您的 GUI。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-16
      • 2018-05-13
      • 2021-10-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多