Python GTK 信号处理程序不工作

标签 python gtk signals pygtk gtk3

我正在为 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/

相关文章:

c - GTK+ 中的六边形按钮

python - 首选项窗口在关闭时销毁 - Glade、Gtk、Python

linux - lldbinit 中的进程句柄

c - 使用 sigaction 处理信号

python - 无法以 SavedModel 格式保存 Tensorflow

python - Django - form_valid() 与 save()

python - 选择某些显示器以使用 gtk 全屏显示

C++、信号和线程

python - 使用Python和if语句解析JSON

python - Pytest fixture : setup, 拆解和每个测试之间运行的代码