Python GTK信号处理程序不工作

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):

我正在为GUI使用GTK编写一个Python应用程序。我注意到用Ctrl-C从终端关闭它不起作用,我发现这是因为一个错误,所以我尝试手动处理信号。问题是,如果我将默认行为设置为默认行为,信号将被捕获,应用程序将正确关闭,但如果我使用自定义处理程序,它将不起作用。以下是我的(简化)代码:

相反,如果我设置了默认行为,则信号被正确捕获:

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!")