Home > Enterprise >  How to properly close tkinter Toplevel with matplotlib embeded?
How to properly close tkinter Toplevel with matplotlib embeded?

Time:10-13

I'm making a GUI application and I want to use matplotlib to display some plots. I have structured my code like that:

import tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
import matplotlib.pyplot as plt


class PopUP_Graph(tk.Toplevel):
    def __init__(self, *args, **kargs):
        super().__init__(*args, **kargs)
        self.fig, self.ax = plt.subplots()
        self.drawing_area = FigureCanvasTkAgg(self.fig, master=self)
        self.drawing_area.draw()
        self.toolbar = NavigationToolbar2Tk(self.drawing_area, self)
        self.toolbar.update()
        self.drawing_area.get_tk_widget().pack(side="top", fill="both", expand=1)


class App:
    def __init__(self, root):
        self.master = root
        self.button = tk.Button(root, text="Open graph", command=self.open_graph)
        self.button.grid(column=0, row=0)

    def open_graph(self):
        popupgraph1 = PopUP_Graph(self.master)
        popupgraph1.mainloop()


w, h = 900, 600
root = tk.Tk()
root.geometry(f'{w}x{h} 0 0')
app = App(root)
root.mainloop()

The problem I have is that when the toplevel window is displayed and then closed, the program won't close correctly even after closing the root window.

Is there a way to fix this??

CodePudding user response:

For some reason the tkinter mainloop is not stopping, even when the window is closed. To fix this, add root.wm_protocol("WM_DELETE_WINDOW", exit) right after creating root.

This tells tkinter to call exit whenever the root window is closed. exit() simply exits the Python interpreter. I know that this is not the most professional way to do this, but I tried using root.quit in place of exit, and I consistently had to click root's close button twice before it actually closed.

Here is the full code, with the added line marked ### ADDED LINE:

import tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
import matplotlib.pyplot as plt


class PopUP_Graph(tk.Toplevel):
    def __init__(self, *args, **kargs):
        super().__init__(*args, **kargs)
        self.fig, self.ax = plt.subplots()
        self.drawing_area = FigureCanvasTkAgg(self.fig, master=self)
        self.drawing_area.draw()
        self.toolbar = NavigationToolbar2Tk(self.drawing_area, self)
        self.toolbar.update()
        self.drawing_area.get_tk_widget().pack(side="top", fill="both", expand=1)


class App:
    def __init__(self, root):
        self.master = root
        self.button = tk.Button(root, text="Open graph", command=self.open_graph)
        self.button.grid(column=0, row=0)

    def open_graph(self):
        popupgraph1 = PopUP_Graph(self.master)
        popupgraph1.mainloop()


w, h = 900, 600
root = tk.Tk()
root.wm_protocol("WM_DELETE_WINDOW", exit) ### ADDED LINE
root.geometry(f'{w}x{h} 0 0')
app = App(root)
root.mainloop()

CodePudding user response:

As Henry Yik pointed out matplotlib.figure.Figure should be used instead of pyplot. Now it works:

import tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
from matplotlib.figure import Figure


class PopUP_Graph(tk.Toplevel):
    def __init__(self, *args, **kargs):
        super().__init__(*args, **kargs)
        # self.fig, self.ax = plt.subplots()
        self.fig = Figure()
        self.ax = self.fig.add_subplot()
        self.drawing_area = FigureCanvasTkAgg(self.fig, master=self)
        self.drawing_area.draw()
        self.toolbar = NavigationToolbar2Tk(self.drawing_area, self)
        self.toolbar.update()
        self.drawing_area.get_tk_widget().pack(side="top", fill="both", expand=1)


class App:
    def __init__(self, root):
        self.master = root
        self.button = tk.Button(root, text="Open graph", command=self.open_graph)
        self.button.grid(column=0, row=0)

    def open_graph(self):
        popupgraph1 = PopUP_Graph(self.master)
        popupgraph1.mainloop()


w, h = 900, 600
root = tk.Tk()
root.geometry(f'{w}x{h} 0 0')
app = App(root)
root.mainloop()
  • Related