2016-10-03 46 views
0

Ctrl-C/SIGTERM/SIGINTはtkinterによって無視されるようです。通常はcaptured again with a callbackとなります。これは動作していないようですので、mainloop() is an infinite loop and blocks以降、tkinter in another threadを実行すると思いました。私は実際に別のスレッドでstdinから読み込むためにこれをしたいと思っています。この後もCtrl + Cはウィンドウを閉じるまで処理されません。ここに私のMWEだ:Ctrl-Cでtkinterアプリケーションを終了し、SIGINTをキャッチする

#! /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) 

結果:

  • を実行し、端末でアプリ
  • はCtrl-C(何も起こらない)
  • は "...終了"
  • ウィンドウを閉じます既に出ているループについてはエラーが出ます。

ここでは何が起こっているのですか?端末からCtrl-Cを押してアプリケーションを閉じるにはどうしたらいいですか?


更新:Adding a pollas suggested、メインスレッドで動作しますが、別のスレッドで開始したときには役立ちません...

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() 
+0

ちょうど明白である:あなたはGUIからではなく、端末から制御-Cをしたいのですが、正しいですか? –

+0

@BryanOakleyはい、開発中の頻繁なテストには非常に便利です。 – jozxyqk

+0

次のリンクはあなたの質問に答えていますか? http://stackoverflow.com/a/13784297/7432 –

答えて

1

あなたのTkinterのアプリが別のスレッドで実行されているので、そうでありませんメインスレッドにシグナルハンドラを設定し、ちょうどapp.start()文の後に、次のコードブロックを使用する必要があります。

import time 

while app.is_alive(): 
    try: 
     time.sleep(0.5) 
    except KeyboardInterrupt: 
     app.root.destroy() 
     break 

あなたはすることができますその後、 Ctrl-Cを使用してKeyboardInterrupt例外を発生させ、tkinterアプリケーションを閉じてwhileループを解除します。 whileループは、tkinterアプリケーションを終了すると終了します。

上記のコードはPython 2でのみ動作します(コードでTkinterを使用しているため)。

+0

ありがとう!これは確かにウィンドウを閉じますが、何かがまだ実行されており、プロセスが終了を拒否しています。シグナルハンドラが動作しない理由を言うこともできますか?なぜそれが難しいのか理解したいと思います。 – jozxyqk

+0

シグナルハンドラは、メインスレッドでのみ機能するため、機能しません。しかし、あなたのコード中のメインスレッドは 'signal.signal(...)'ステートメントの後で終了します。メインスレッドを生かした 'signal.signal(...)'ステートメントの後に 'true:pass'を追加すると、シグナルハンドラが動作します。 – acw1668

関連する問題