2

I ran into a problem using tkinter and matplotlib.pyplot, that I don't understand.

Minimal example

import tkinter
import tkinter.filedialog as  tk_filedialog

import numpy as np
import matplotlib.pyplot as plt

def main():

    # # -- part 1 --
    # tkinter.Tk().withdraw()
    junk = tk_filedialog.askopenfilename()

    # # -- part 2 --
    x_p = np.linspace(0,10,100)
    fig = plt.figure()
    plt.plot(x_p,x_p,color='b')
    plt.show()

    print("blob")

if __name__ == '__main__':
    main()
print("blab")

My implementation was originally with the line tkinter.Tk().withdraw() uncommented, but then you don't see what happens.

The program above will run but does not terminate. It should do the following steps:

  1. Open Tkinter "Select-File-Dialog" -> Choose any file, as it does nothing.
  2. Plot the curve -> Close the Plot Window
  3. Print "blob", print "blab"

The problem is that the Tkinter window, which would be suppressed by tkinter.Tk().withdraw(), does not close. That leads to two unexpected behaviours - see below.

The most confusing part is: If you comment either -- part 1 -- or -- part 2 -- the program will run as expected.


Winpython3.5 started from Cygwin

After closing this tkinter window "blob" and "blab" will be printed and the program terminates as expected. enter image description here


Spyder 3

"blob" and "blab" are printed before closing the figure window, and before closing the tk window. Additionally it is impossible to close the tk window (the x-button does nothing). It closes with closing spyder, though. enter image description here


IDLE

Same behaviour as Cygwin.


Any ideas? Did I miss some close() command for tkinter?

I found this:

tk_window = tkinter.Tk()
tk_window.destroy()

But that does not solve the problem above.

3
  • I just removed everything connected to the package os to further reduce the example. numpy could also be thrown out of the example using a list x_p = [1,2,3] Commented Aug 30, 2017 at 13:07
  • Looks like a bug or a limitation in spyder to me. I don't know exactly what runfile dose but IPython can have issues with interactive use of GUI toolkits unless you take some care. Using two GUI toolkits in the same session can be even trickier. Commented Aug 30, 2017 at 13:11
  • @Goyo Thx for your comment. I could solve the problem - see my answer. And I think it is a problem in the implementation of tkinter. || If anyone has further ideas, please let me know. Commented Aug 30, 2017 at 15:37

2 Answers 2

2

In your original code, you explicitly create a root window with tkinter.Tk(). Like all tkinter widget class calls, this actually creates both an instance of the Python class and a tk C structure. But instead of binding the Python instance to a name, so you could access it later, you immediately call a method, .withdraw().

In your answer, you properly keep a reference to root (a conventional name, like self), so you can destroy the tk root structure when you want to, rather than when the program exits.

As it happens, if tkinter._support_default_root is true, which it is by default, then the Tk() instance is bound to tkinter._default_root. In your original code, you could have called tkinter._default_root.destroy(). But I strongly recommend keeping your own reference, as you did in your answer.

Why did your original code keep working, and a root get created, after you disabled the explicit call to Tk()? Because if tkinter._support_default_root is true, tkinter will run _default_root = Tk() for you, as a 'convenience' feature. But this is only convenient if you want the hidden default root to stay for the duration of the process.

To repeat: what you did in your answer is the standard, documented, right way to work with tkinter.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you very much for your answer. It helped a lot to understand the behavior behind these few lines. But this is only convenient if you want the hidden default root to stay for the duration of the process. But shouldn't the default root terminate at the end of the program, as it does when used without pyplot?
Yes, if the OS process terminates, then the tk widgets will be gone. But if the existence of widgets blocks termination, they have to be deleted first. In your program above, you don't need root, visible or hidden, after the ask call, so you should not want it to stay, even if it is normally harmless. Since a pyplot call to a different GUI follows, you are better off destroying root first, as in your answer.
1

After a lot of trial and error, I found a solution. The following snippet replaces the first part of code in my question.

    [...]
    # # -- part 1 --

    root = tkinter.Tk()
    # root.withdraw()
    cwd = os.getcwd()
    junk = tk_filedialog.askopenfilename()
    root.destroy()

    # # -- part 2 --
    [...]

It seems like askopenfilename() opens the root window of tkinter, but does not ensure that it is closed / destroyed after that line has been executed.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.