0

I have root=Tk.Tk() which consist from labels (Tk.Label), entry forms (Tk.Entry), button (Tk.Button) and embedded matplotlib FigureCanvasTkAgg. This is simple script, which plots quadtratic functions with coefficients (a, b, c) specified by user. But I have some problems and misunderstanding with destroying the mainloop. I was expecting, that simple closing of the main window (by clicking "x" at the right corner), should also lead to the exit from mainloop. This is the case for my script, if I would comment all the code, related to the embeded canvas. But with embedded FigureCanvasTkAgg, it doesn't happen (so there is a need for interrupting kernel for running script again). As was discussed in other questions, there are 2 methods for exiting mainloop: root.quit() and root.destroy(). So I also tried to use these methods for exiting mainloop:

def close_all():
    root.quit()
    root.destroy()

by new button :

button_quit=Tk.Button(root, text="Quit", command=close_all)
button_quit.grid(row=5, column=1)

by overwriting "x" button :

root.protocol('WM_DELETE_WINDOW', close_all)

My questions:

  1. Using both methods worked. But why if I use only root.destroy(), root.mainloop() would still execute? Why mainloop is not being destroyed just after closing window? And why this problem causes FigureCanvasTkAgg? Embedding matplotlib figure was done by the following (if it helps to explain):

    fig, ax = plt.subplots()
    canvas = FigureCanvasTkAgg(fig, master=root)
    plot_widget = canvas.get_tk_widget()
    #(plotting with plt.plot(..))
    canvas.show()
    plot_widget.grid(row=6, column = 0, columnspan=3)
    
  2. close_all() function worked in that sense, that there was performed exit from mainloop, and script execution stopped. But there is still some strange behavior. There variables such as var_a = Tk.StringVar(), used for receiving data from entry fields in a way:

    L_a = Tk.Label(master=root, width=10, height=2, bd =2, text="a")
    E_a = Tk.Entry(master=root, width=10, bd =2, textvariable=var_a) 
    

    with

    def get_value():
        if not check_if_float(var_a.get()) or not check_if_float(var_b.get()) or not check_if_float(var_c.get()):
            showerror(title = "Error", message = "Invalid entry. Enter integer or decimal numbers, please")
            return None
        a=float(var_a.get())
        b=float(var_b.get())
        c=float(var_c.get())
    

    So the problem and strange behavior is that after executing code once, and closing main window (either by clicking "x" at the right top corner, or by clicking "Quit" button), in the next execution code receives empty var_a, var_b, var_c. If kernel interrupted, and code runs again, it works correctly (running it in jupyter notebook). I have no idea why is it like that.

Community
  • 1
  • 1
Antonio
  • 325
  • 1
  • 3
  • 9

1 Answers1

2

This is because you did not provide the variables with a master, so they default to the first Tk() instance created, even if it's been destroyed. The fix is simply to provide the correct root:

var_a = Tk.StringVar(root)

This usually isn't an issue since there are very few situations where you would want to call Tk() more than once.

Novel
  • 13,406
  • 2
  • 25
  • 41
  • Thanks! It helps, works now. Do you have any idea, why for the embedded canvas just `root.destroy()` is not enough (and just closing window not enough) to exit main loop? In other words, why both `root.quit()` and `root.destroy()` are needed to correctly exit the main loop? – Antonio May 07 '17 at 07:47
  • Those do different things. `destroy` removes the widget from the screen. `quit` stops the main loop. In normal situations, calling one would cause the other to be called automatically, but sometimes that's prevented, especially on Windows. – Novel May 07 '17 at 19:45