我需要检查在执行某些非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 事件应该是用于中断它的转义键。
答案 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的解决方案相比,它的优势在于它可以处理按键后另一个事件到达时的情况。缺点是它需要摆弄全局事件处理程序。