pygtk glib.timeout_add(): 如何判断计时器没有被销毁?

5 投票
2 回答
4575 浏览
提问于 2025-04-17 10:57

在我的应用程序中,我使用一个函数来显示GtkInfoBars,并设置一个超时(具体方法可以参考这个链接),这是通过glib.timeout_add_seconds()实现的。

我明白glib.timeout_add_seconds()的作用是定期调用一个函数,直到这个函数返回False为止。

不过我并没有这样做,但一切都按预期运行,感觉非常简单。以下是我的代码:

def infobar(self, message, msgtype=gtk.MESSAGE_INFO, timeout=5):
    bar = gtk.InfoBar()
    bar.set_message_type(msgtype)
    bar.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
    bar.connect("response", lambda *args: bar.hide())
    self.vb2.pack_end(bar, False, False)
    label = gtk.Label()
    label.set_markup(message)
    content = bar.get_content_area()
    content.add(label)
    label.show()
    bar.show()
    if timeout:
        glib.timeout_add_seconds(timeout, bar.hide)

那么,问题来了。看看我在最后一行做的事情。简单来说,这样做可以吗?当第二次调用bar.hide()失败时,超时会自己消失吗?还是说我在不断增加一些无用的超时,它们每5秒会“醒来”一次,实际上会消耗资源呢?


补充说明:

如果我猜的没错,这样做是不好的,我确实需要返回False来销毁这些超时,那么我需要一些帮助——我搞不清楚该如何调整代码,以满足以下条件:我需要同时允许多个InfoBars存在,每个InfoBar都能保持与自己的计时器和按钮响应信号连接(就像现在的代码那样) 或者 我需要每个新的InfoBar替换掉之前的那个(我不知道该如何做到这一点,而不让新的InfoBar继承之前的计时器——这样会变得很麻烦)。

谢谢你的阅读!

2 个回答

5

关于 bar.hide 被调用多次的问题,我觉得这应该不会发生。因为据我所知,只要返回一个被认为是 False 的值就可以了,而 bar.hide 返回的是 None,这应该就足够了。不过,如果你想完全确认一下,可以用下面的方式来验证:

import gtk, glib

def callback():
    print 'called'

glib.timeout_add_seconds(1, callback)
gtk.main()

在这个例子中,回调函数也返回 None,而且从输出到 stdout 可以看到,它只被调用了一次。

至于你最后的问题,我觉得这种方式已经可以接受了,可以让多个信息条每个都有自己的计时器。如果我漏掉了什么,请补充更多信息。

4

Widget.hide 这个方法总是返回 None,而 glib.timeout_add_seconds 会把它当成 False 来处理。所以,你的计时器每次运行后都会结束。虽然有可能 hide 会被调用两次(比如用户点击确定和在 5 秒超时后),但这没关系。所以,你的代码是没问题的。

编辑:我刚意识到一点。你每次函数运行时都在创建一个新的信息条,然后只是把它隐藏起来。与其用 hide,不如用 destroy,这样可以把它彻底清理掉。

...或者我需要让每个新的信息条替换掉之前的那个(我不知道怎么做,不想让新的计时器继承之前的信息条的计时器,这样会变得很麻烦)。

其实这并不复杂;只需重复使用同一个信息条即可。记录下 glib.timeout_add_seconds 的返回值,然后在替换信息条的内容时,用 glib.source_remove 来结束之前的计时器。

你提到的这两种选择之间有可用性上的权衡(干净的用户界面 vs. 确保用户不会错过重要信息),但这是另一个话题,也许不是那么重要。

撰写回答