Pyr*_*rox 5 python gtk signals pygtk gtk3
我正在使用GTK为GUI编写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()
Run Code Online (Sandbox Code Playgroud)
相反,如果我设置了默认行为,则正确捕获信号:
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()
Run Code Online (Sandbox Code Playgroud)
我错过了什么吗?
编辑:
我尝试了更多,我注意到信号实际上已被捕获,但窗口不是立即关闭,而是仅在重新获得焦点时.相反,如果我跑了
kill -9 pid
Run Code Online (Sandbox Code Playgroud)
从另一个终端窗口,应用程序立即关闭.
小智 5
我还记得在使用 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()
Run Code Online (Sandbox Code Playgroud)
请注意,在接收信号时,如果您不退出 gtk 循环(Gtk.main_quit()),那么当它第二次接收到信号时,它会自行关闭,可能是因为您提到的错误。尽管如此,在退出之前清理变量(包括使用 CTRL + C)仍然很完美。
如果我没记错的话,我从 pygtk irc 频道中的一个人那里得到了解决方案,所以我无法正确地赞扬为我提供解决方案的人。
小智 5
我尝试了几种不同的方法,包括有一个单独的线程来运行 glib mainloop 并从另一个线程捕获信号,但最后它就像使用“try”一样简单:
from gi.repository import GLib
main_loop = GLib.MainLoop()
try:
main_loop.run()
except KeyboardInterrupt:
print("How rude!")
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2654 次 |
| 最近记录: |