偷看GTK赛事; gtk.gdk.event_peek始终返回None

时间:2012-10-28 10:45:05

标签: python gtk pygtk

我需要检查在执行某些非GUI代码时是否按下了Escape键。 (代码在Python中,但如果需要,可以很容易地调用C语言。)代码从GUI接收一个函数,它偶尔会调用它来检查它是否被中断。问题是如何实施这项检查。

通过查看文档,gdk_event_peek似乎是一个很好的选择:

def _check_esc(self):
    event = gtk.gdk.event_peek()
    if event is None or event.type not in (gtk.gdk.KEY_PRESS, gtk.gdk.KEY_RELEASE):
        return False
    return gtk.gdk.keyval_name(event.keyval) == 'Escape'

但这不起作用:当主循环未运行时,从gtk.gdk.event_peek()返回的事件始终为None。将其更改为gtk.gdk.display_get_default().peek_event()也无济于事。我假设事件在X事件队列中并且尚未移动到GDK事件队列。 The documentation说:

  

请注意,此功能不会从窗口获取更多事件   系统。它只检查已经移动到的事件   GDK事件队列。

那么,如何将事件转移到GDK事件队列或?换句话说,gtk.gdk.peek_event()何时返回事件?调用gtk.events_pending()没有任何效果。

这是一个测试它的最小程序:

import gtk, gobject
import time

def code(check):
    while 1:
        time.sleep(.1)
        if check():
            print 'interrupted'
            return

def _check_esc():
    event = gtk.gdk.event_peek()
    print 'event:', event
    if event is None or event.type not in (gtk.gdk.KEY_PRESS, gtk.gdk.KEY_RELEASE):
        return False
    return gtk.gdk.keyval_name(event.keyval) == 'Escape'

def runner():
    code(_check_esc)
    gtk.main_quit()

w = gtk.Window()
w.show()
gobject.idle_add(runner)
gtk.main()

运行代码时,即使按Escape键或移动鼠标,打印的事件也始终为None。

我还考虑过为Escape安装一个处理程序,并使用while gtk.events_pending(): gtk.main_iteration()成语来检查进程事件。这会导致所有挂起事件(包括键盘和鼠标事件)的取消和发送。结果是,在代码运行时GUI启用了响应,这看起来不太好并且可能严重干扰代码的执行。执行期间处理的 only 事件应该是用于中断它的转义键。

1 个答案:

答案 0 :(得分:1)

我想出了一个runner实现,它满足了问题中提出的标准:

def runner():
    # _check_esc searches for Escape in our queue
    def _check_esc():
        oldpos = len(queue)
        while gtk.events_pending():
            gtk.main_iteration()
        new = itertools.islice(queue, oldpos, None)
        return any(event.type == gtk.gdk.KEY_PRESS \
                       and gtk.gdk.keyval_name(event.keyval) == 'Escape'
                   for event in new)

    queue = []
    # temporarily set the global event handler to queue
    # the events
    gtk.gdk.event_handler_set(queue.append)
    try:
        code(_check_esc)
    finally:
        # restore the handler and replay the events
        handler = gtk.main_do_event
        gtk.gdk.event_handler_set(gtk.main_do_event)
        for event in queue:
            handler(event)
    gtk.main_quit()

与基于peek的解决方案相比,它的优势在于它可以处理按键后另一个事件到达时的情况。缺点是它需要摆弄全局事件处理程序。