I boiled my code down into this minimal reproducible example:
import matplotlib.pyplot as plt
from tkinter import Tk
from tkinter import Tk, Frame
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
Dates=["a","b","c","d"]
Numbers=[1,4,2,6]
def test():
fig, ax = plt.subplots(figsize=(10,7))
ax.plot(Dates, Numbers, linestyle='-', color='gray', alpha=0.5)
root = Tk()
root.title("Test")
frame = Frame(root)
frame.pack(fill='both', expand=True)
canvas = FigureCanvasTkAgg(fig, master=frame)
canvas.draw()
canvas.get_tk_widget().pack(fill='both', expand=True)
def f_test():
print("HI")
f_test()
root.mainloop()
test()
The problem im having is that whenever I call the function, it starts running but never ends. It keeps running even though I close the Tk window. I have laso tried with 'winfo_exists()'
But it just wont work.
I have 'f_test'
inside 'test()'
because irl I have 2 functions that are only used inside 'test()'
so i've defined them inside it.
As I suspected in the comments this is due to the blocking tkinter mainloop
which is never properly exited in your case.
The mainloop is an eventhandler. That means its basically an endless loop updating your GUI. So once you enter it. Everything following in your code will never be reached. See this post for reference.
Following this tutorial from matplotlib.org I implemented a closing routine _on_closing
to stop the blocking mainloop
and to destroy the Tk
instance properly. This routine is triggert by the WM_DELETE_WINDOW
event when closing the tkinter window.
import matplotlib.pyplot as plt
from tkinter import Tk, Frame
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
Dates = ["a", "b", "c", "d"]
Numbers = [1, 4, 2, 6]
def test():
fig, ax = plt.subplots(figsize=(10, 7))
ax.plot(Dates, Numbers, linestyle='-', color='gray', alpha=0.5)
root = Tk()
root.title("Test")
frame = Frame(root)
frame.pack(fill='both', expand=True)
canvas = FigureCanvasTkAgg(fig, master=frame)
canvas.draw()
canvas.get_tk_widget().pack(fill='both', expand=True)
def f_test():
print("HI")
def _on_closing():
root.quit() # stops mainloop
root.destroy() # this is necessary on Windows to prevent Fatal Python Error: PyEval_RestoreThread: NULL tstate
root.protocol("WM_DELETE_WINDOW", _on_closing) # bind closing routine
f_test()
root.mainloop()
test()
Please note also that while the tkinter window is open mainloop
is running and therefore the rest of your code is blocked until you close the window!