Search code examples
pythoncanvastkinterscrollbarfigure

Error when closing tkinter app with figure and canvas


I get the following error when I resize the right expand the window and then close it: _tkinter.TclError: invalid command name ".!scrollbar" Maybe it's related to the canvas widget. I tried a lot, but without results.

can anyone help me?

The code is below

import tkinter as tk
from matplotlib.figure import Figure
import numpy as np
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

root=tk.Tk()

vscrollbar = tk.Scrollbar(root)

canvasF2= tk.Canvas(root,yscrollcommand=vscrollbar.set)

vscrollbar.config(command=canvasF2.yview)
vscrollbar.pack(side=tk.RIGHT, fill=tk.Y) 

frame2=tk.Frame(canvasF2) #Create the frame which will hold the widgets

canvasF2.pack(side="left", fill="both", expand=True)

##Updated the window creation
canvasF2.create_window(0,0,window=frame2, anchor='nw')
#
fig = Figure(figsize=(10, 4), dpi=100)
t = np.arange(0, 3, .01)
a = fig.add_subplot(111)
a.plot(t, 2 * np.sin(2 * np.pi * t))

canvas = FigureCanvasTkAgg(fig, frame2)  # A tk.DrawingArea.
canvas.draw()
canvas.get_tk_widget().grid(row=4, column=0, columnspan=2, sticky="nswe")

def on_configure(event):    
    canvasF2.configure(scrollregion=canvasF2.bbox('all'))

root.bind('<Configure>', on_configure) 

root.mainloop()

Solution

  • I'm not sure why this error triggers when the window is closed, my guess is somehow after closing the window the widget canvasF2 is not getting destroyed properly. So if we destroy canvasF2 properly before closing the window the error won't trigger. I think there'll be a better way of doing this but here's what I did.

    I handled the deletion of the window by using protocol method. I added this to the end of your code and I got no error by destroying canvasF2 before the main window is destroyed.

    def close_window():
        canvasF2.destroy()
        root.destroy()
    
    root.protocol("WM_DELETE_WINDOW", close_window)
    

    Complete Code:

    import tkinter as tk
    from matplotlib.figure import Figure
    import numpy as np
    from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
    
    root=tk.Tk()
    
    vscrollbar = tk.Scrollbar(root)
    
    canvasF2= tk.Canvas(root,yscrollcommand=vscrollbar.set)
    
    vscrollbar.config(command=canvasF2.yview)
    vscrollbar.pack(side=tk.RIGHT, fill=tk.Y) 
    
    frame2=tk.Frame(canvasF2) #Create the frame which will hold the widgets
    
    canvasF2.pack(side="left", fill="both", expand=True)
    
    ##Updated the window creation
    canvasF2.create_window(0,0,window=frame2, anchor='nw')
    #
    fig = Figure(figsize=(10, 4), dpi=100)
    t = np.arange(0, 3, .01)
    a = fig.add_subplot(111)
    a.plot(t, 2 * np.sin(2 * np.pi * t))
    
    canvas = FigureCanvasTkAgg(fig, frame2)  # A tk.DrawingArea.
    canvas.draw()
    canvas.get_tk_widget().grid(row=4, column=0, columnspan=2, sticky="nswe")
    
    def on_configure(event):    
        canvasF2.configure(scrollregion=canvasF2.bbox('all'))
    
    root.bind('<Configure>', on_configure) 
    
    
    def close_window():
        canvasF2.destroy()
        root.destroy()
    
    root.protocol("WM_DELETE_WINDOW", close_window)
    
    root.mainloop()
    

    Hope this helps!