0

非 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 イベント キューに移動されていないと仮定します。ドキュメントには次のように記載されています。

この関数は、ウィンドウ システムからそれ以上のイベントを取得しないことに注意してください。すでに 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()

コードを実行すると、Esc キーを押したりマウスを動かしたりしても、出力されるイベントは常に None です。

また、Escape のハンドラーをインストールし、while gtk.events_pending(): gtk.main_iteration()イディオムを使用してチェッカーにイベントを処理させることも検討しました。これにより、保留中のすべてのイベント (キーボード イベントやマウス イベントを含む) がアンキューされ、ディスパッチされます。その結果、コードの実行中に GUI がレスポンシブ対応になるため、見栄えが悪く、コードの実行に深刻な影響を与える可能性があります。実行中に処理される唯一のイベントは、実行を中断するためのエスケープ キーである必要があります。

4

1 に答える 1

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

ピークベースのソリューションと比較すると、その利点は、キーを押した後に別のイベントが到着したときにケースを処理することです。欠点は、グローバルイベントハンドラーをいじる必要があることです。

于 2012-10-28T14:32:39.863 に答える