Exiting a tkinter app with Ctrl-C and catching SIGINT
<p>Ctrl-C/SIGTERM/SIGINT seem to be ignored by tkinter. Normally it can be <a href="http://stackoverflow.com/questions/1112343/how-do-i-capture-sigint-in-python">captured again with a callback</a>. This doesn't seem to be working, so I thought I'd run tkinter <a href="http://stackoverflow.com/a/1835036/1888983">in another thread</a> since its <a href="http://stackoverflow.com/questions/29158220/tkinter-understanding-mainloop">mainloop() is an infinite loop and blocks</a>. I actually also want to do this to read from stdin in a separate thread. Even after this, Ctrl-C is still not processed until I close the window. Here's my MWE:</p>

<pre><code>#! /usr/bin/env python
import Tkinter as tk
import threading
import signal
import sys

class MyTkApp(threading.Thread):
    def run(self):
        self.root = tk.Tk()
        self.root.mainloop()

app = MyTkApp()
app.start()

def signal_handler(signal, frame):
    sys.stderr.write("Exiting...\n")

    # think only one of these is needed, not sure
    app.root.destroy()
    app.root.quit()

signal.signal(signal.SIGINT, signal_handler)
</code></pre>

<p>Results:</p>

<ul>
<li>Run the app</li>
<li>Ctrl-C in the terminal (nothing happens)</li>
<li>Close the window</li>
<li>"Exiting..." is printed and I get an error about the loop already having exited.</li>
</ul>

<p>What's going on here and how can I make Ctrl-C from the terminal close the app?</p>

<hr>

<p>Update: <a href="http://stackoverflow.com/a/13784297/7432">Adding a poll</a>, <a href="http://stackoverflow.com/questions/39840815/exiting-a-tkinter-app-with-ctrl-c-and-catching-sigint?noredirect=1#comment66972210_39840815">as suggested</a>, works in the main thread but does not help when started in another thread...</p>

<pre><code>class MyTkApp(threading.Thread):
    def poll(self):
        sys.stderr.write("poll\n")
        self.root.after(50, self.poll)

    def run(self):
        self.root = tk.Tk()
        self.root.after(50, self.poll)
        self.root.mainloop()
</code></pre>

<p>Since your tkinter app is running in another thread, you do not need to set up the signal handler in the main thread and just use the following code block after the <code>app.start()</code> statement:</p>

<pre><code>import time

while app.is_alive():
    try:
        time.sleep(0.5)
    except KeyboardInterrupt:
        app.root.destroy()
        break
</code></pre>

<p>You can then use <kbd>Ctrl-C</kbd> to raise the <code>KeyboardInterrupt</code> exception to close the tkinter app and break the while loop.  The while loop will also be terminated if you close your tkinter app.</p>

<p>Note that the above code is working only in Python 2 (as you use <code>Tkinter</code> in your code).</p>

python multithreading tkinter signals