我正在为 GUI 使用 GTK 编写 Python 应用程序。我注意到从终端用 Ctrl-C 关闭它不起作用,我发现这是因为一个错误,所以我尝试手动处理信号。问题是,如果我将默认行为设置为默认行为,则会捕获信号并正确关闭应用程序,但如果我使用自定义处理程序,它就不起作用。这是我的(简化的)代码:
from gi.repository import Gtk
import signal
class MainWindow(Gtk.Window):
def __init__(self):
...
signal.signal(signal.SIGINT, self.__signal_handler)
def __signal_handler(self, signal, frame):
print "Caught!"
...
if __name__ == "__main__":
win = MainWindow()
win.show_all()
Gtk.main()
相反,如果我设置了默认行为,则可以正确捕获信号:
from gi.repository import Gtk
import signal
class MainWindow(Gtk.Window):
def __init__(self):
...
signal.signal(signal.SIGINT, signal.SIG_DFL)
...
if __name__ == "__main__":
win = MainWindow()
win.show_all()
Gtk.main()
我错过了什么吗?
编辑:
我又尝试了一些,我注意到信号实际上被捕获了,但是窗口并没有立即关闭,而是只有在再次获得焦点时才关闭。相反,如果我运行一个
kill -9 pid
从另一个终端窗口,应用程序立即关闭。
最佳答案
我还记得在使用 pygtk3 学习应用程序时遇到过很多关于信号处理的麻烦。这里有一个工作示例,演示如何为 SIGHUP、SIGINT 和 SIGTERM 完成此操作:
#!/usr/bin/python
from gi.repository import Gtk, GLib, GObject
from gi.repository import AppIndicator3 as appindicator
import os
import signal
class Gui():
def __init__(self):
self.window = Gtk.Window(title="Signal example")
self.window.set_size_request(250,150)
self.window.connect("delete-event", Gtk.main_quit)
self.window.show_all()
def cleanup(self):
print("... Cleaning up variables, etc.")
def quit(self, widget):
print("... Exiting main gtk loop")
Gtk.main_quit()
def InitSignal(gui):
def signal_action(signal):
if signal is 1:
print("Caught signal SIGHUP(1)")
elif signal is 2:
print("Caught signal SIGINT(2)")
elif signal is 15:
print("Caught signal SIGTERM(15)")
gui.cleanup()
gui.quit(None)
def idle_handler(*args):
print("Python signal handler activated.")
GLib.idle_add(signal_action, priority=GLib.PRIORITY_HIGH)
def handler(*args):
print("GLib signal handler activated.")
signal_action(args[0])
def install_glib_handler(sig):
unix_signal_add = None
if hasattr(GLib, "unix_signal_add"):
unix_signal_add = GLib.unix_signal_add
elif hasattr(GLib, "unix_signal_add_full"):
unix_signal_add = GLib.unix_signal_add_full
if unix_signal_add:
print("Register GLib signal handler: %r" % sig)
unix_signal_add(GLib.PRIORITY_HIGH, sig, handler, sig)
else:
print("Can't install GLib signal handler, too old gi.")
SIGS = [getattr(signal, s, None) for s in "SIGINT SIGTERM SIGHUP".split()]
for sig in filter(None, SIGS):
print("Register Python signal handler: %r" % sig)
signal.signal(sig, idle_handler)
GLib.idle_add(install_glib_handler, sig, priority=GLib.PRIORITY_HIGH)
if __name__ == "__main__":
gui = Gui()
InitSignal(gui)
Gtk.main()
请注意,在收到信号时,如果您不退出 gtk 循环 (Gtk.main_quit()),那么当它第二次收到信号时,它会自行关闭,这可能是因为您提到的错误。尽管如此,在退出前清理变量(包括使用 CTRL + C)仍然很完美。
如果我没记错的话,我是从 pygtk irc channel 的一个人那里得到解决方案的,所以我不能正确地归功于为我提供解决方案的人。
关于Python GTK 信号处理程序不工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26388088/