1

I have a problem similar to this post: Exit program within a tkinter class

My variation on the problem involves the wait_variable being used on a button to control "stepping forward" in an app, but also allowing the app to close cleanly.

See my code below:

# To see output unbuffered:
#   python -u delete_win_test.py

import tkinter as tk
from tkinter import *


class GUI(Tk):
    def __init__(self):
        super().__init__()

        # Close the app when the window's X is pressed
        self.protocol("WM_DELETE_WINDOW", self.closing)

        # When this var is set to 1, the move function can continue
        self.var = tk.IntVar()

        # Close the app if the button is pressed
        button = tk.Button(self, text="Exit",
                           command=self.destroy)
        button.place(relx=.5, rely=.5, anchor="c")

        # Step forward
        self.step_button = tk.Button(self, text="Step",
                                     command=lambda: self.var.set(1))
        self.step_button.place(relx=.5, rely=.75, anchor="c")

    def move(self):
        print("doing stuff")  # simulates stuff being done
        self.step_button.wait_variable(self.var)
        self.after(0, self.move)

    def closing(self):
        self.destroy()


app = GUI()
app.move()
app.mainloop()
  • The window shows correctly
  • "Stepping forward" works because "doing stuff" prints to terminal on button click
  • Exiting the window by both pressing X or using the "exit" button both work

The problem: the Python app never exits from the terminal and requires a closing of the terminal.

How can I make the Python program exit cleanly so the user does not need to close and re-open a new terminal window?

Related references for animation, etc:

UPDATE (the solution):

(Credit to both response answers below)

         # Close the app if the button is pressed
         button = tk.Button(self, text="Exit",
-                           command=self.destroy)
+                           command=self.closing)
         button.place(relx=.5, rely=.5, anchor="c")
 
         # Step forward
...
     def closing(self):
         self.destroy()
+        self.var.set("")
+        exit(0)

This allows the native window's "X" to close the window and the Tk button to close the window while still closing the Python app cleanly in the terminal.

kecklabs
  • 13
  • 3
  • Why dont you set `self.var` to a special int in your `closing` method and dont continue with `move` if this special int is set? Working with a `if statement` solves this anyhow and shouldnt be too hard to solve for you. – Thingamabobs Nov 10 '21 at 17:09
  • Hi @Atlas435, I see what you mean with `self.var`, however can you explain what you mean by the `if statement`? Is that a separate solution or related to `self.var`? – kecklabs Nov 10 '21 at 17:41

2 Answers2

0

Your closing function needs to set the variable to cause the app to stop waiting.

def closing(self):
    self.destroy()
    self.var.set("")
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • Hi Bryan, thank you for the response, but this did not work for me. The Python app still does not exit cleanly in the terminal even though the window closes (using X or the close button). Tested on both Windows Git Bash and Mac OSX. – kecklabs Nov 10 '21 at 17:47
  • @masao: that's odd. It works for me on OSX. – Bryan Oakley Nov 10 '21 at 18:04
  • Hi again Bryan, here's my environment: `tk==0.1.0` `toml==0.10.2` Python version: `Python 3.9.4` Does this match your environment? – kecklabs Nov 10 '21 at 18:28
  • Solution posted in original post! Thank you so much! – kecklabs Nov 10 '21 at 18:38
0

in the closing function, you need to call exit to exit the program.

def closing(self):
    self.destroy() #closes tkinkter window
    exit(0) #exits program
2pichar
  • 1,348
  • 4
  • 17