Python GTK信号处理程序不工作
我正在为GUI使用GTK编写一个Python应用程序。我注意到用Ctrl-C从终端关闭它不起作用,我发现这是因为一个错误,所以我尝试手动处理信号。问题是,如果我将默认行为设置为默认行为,信号将被捕获,应用程序将正确关闭,但如果我使用自定义处理程序,它将不起作用。以下是我的(简化)代码: 相反,如果我设置了默认行为,则信号被正确捕获:Python GTK信号处理程序不工作,python,gtk,signals,pygtk,gtk3,Python,Gtk,Signals,Pygtk,Gtk3,我正在为GUI使用GTK编写一个Python应用程序。我注意到用Ctrl-C从终端关闭它不起作用,我发现这是因为一个错误,所以我尝试手动处理信号。问题是,如果我将默认行为设置为默认行为,信号将被捕获,应用程序将正确关闭,但如果我使用自定义处理程序,它将不起作用。以下是我的(简化)代码: 相反,如果我设置了默认行为,则信号被正确捕获: from gi.repository import Gtk import signal class MainWindow(Gtk.Window):
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
从另一个终端窗口,应用程序立即关闭。我无法准确再现您的问题,因为我正在运行GTK2(确切地说,在Linux上,gtk版本:2.21.3,pygtk版本:2.17.0)。我的GTK程序在按下^C时会出现键盘中断异常,我可以使用
try:。。。键盘中断除外:
块
但是,当我在GTK GUI的\uuu init\uuuuu
方法中设置信号处理程序时,我确实得到了与您相同的结果:即,使用默认的信号.SIG\u DFL
处理程序按预期工作,但自定义处理程序没有
但是,如果我将信号处理程序设置在GUI类之外,它确实对我有效。这是一个演示程序,在GUI中有一个输入框,这样GUI就可以在清理时报告一些状态信息
#! /usr/bin/env python
''' Testing signal trapping in GTK '''
import signal
import pygtk
pygtk.require('2.0')
import gtk
class Demo:
def cleanup(self):
print "entry text: '%s'" % self.entry.get_text()
print 'Quitting...'
def quit(self, widget=None):
self.cleanup()
gtk.main_quit()
def entry_activated_cb(self, widget):
print "entry activated: '%s'" % widget.get_text()
return True
def __init__(self):
win = gtk.Window(gtk.WINDOW_TOPLEVEL)
win.connect("destroy", self.quit)
win.set_border_width(5)
self.entry = entry = gtk.Entry()
entry.connect("activate", self.entry_activated_cb)
win.add(entry)
entry.show()
win.show()
def main():
def my_sigint_trap(signum, frame):
print '\nSignal handler called with signal %d, %s' % (signum, frame)
ui.quit()
ui = Demo()
signal.signal(signal.SIGINT, my_sigint_trap)
gtk.main()
if __name__ == "__main__":
main()
希望这项技术也能在GTK3中使用。我还记得在使用pygtk3学习appindicators时,在信号处理方面遇到了很多麻烦。下面是一个工作示例,演示如何为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频道的一个人那里得到解决方案的,因此我不能给提供解决方案的人正确的评价。我用了几种不同的方法,包括有一个单独的线程来运行glib mainloop,并从另一个线程捕获信号,但最终它就像使用“try”一样简单:
from gi.repository import GLib
main_loop = GLib.MainLoop()
try:
main_loop.run()
except KeyboardInterrupt:
print("How rude!")
你需要手动处理信号吗?请参阅“是”,我想设置一个处理程序来管理正确写入文件的数据,即使程序通过发送SIGINT而被终止。实际上,在尝试更多操作后,我注意到问题在于信号被正确捕获,但窗口不会立即关闭,而只是在再次获取焦点之后。只有在启动程序的窗口中按ctrl-C键时才会发生这种情况,但如果运行
kill-9PID
应用程序会立即关闭。不幸的是,这种行为也会发生在你的技术上!哦,我想这值得一试。您可以使用window.present()
或其他方法获取焦点吗?在退出GUI之前尝试了window.present(),但没有任何变化。我通过使其适应我的代码来快速尝试,它似乎可以工作。遗憾的是,你需要做这些事情只是为了“基本”的信号处理。希望以后能修好。
from gi.repository import GLib
main_loop = GLib.MainLoop()
try:
main_loop.run()
except KeyboardInterrupt:
print("How rude!")