GUI プログラムであっても、パイプやソケットからコマンドやデータを受け取りたいことがある。コンソール・アプリケーションでは getline() 等でループを回せばいいのだが、GUI アプリケーションではそうはいかない。GUI のためのメッセージループが無限ループになっており、その内部で getline() というブロッキングIO を利用するわけにはいかないからだ。そのため、ノン・ブロッキングIO を使ったりといろいろ面倒が生じるのだが、GTK の場合は Glib の IOChannel 機能で簡単に実装できる。
以下のコードでは、コンソールから文字列を入力するたびにラベルが書き換わる。
import gtk, glib import sys class TestWindow: def __init__(self): self.window = gtk.Window() self.window.connect("destroy", gtk.main_quit) self.label = gtk.Label() self.label.set_label("received text will be shown here") self.window.add(self.label) self.window.show_all() self.i = 0 glib.io_add_watch(sys.stdin, glib.IO_IN, self.update_label) def update_label(self, fd, condition): if condition == glib.IO_IN: # これ、必要なの? self.i += 1 str = fd.readline().rstrip() print "called %d: %s" % (self.i, str) self.label.set_label(str) return True # False を返すと、この割り込みハンドラは破棄される TestWindow() gtk.main()
glib.io_add_watch に、ファイル・ディスクリプタを指定して監視対象にしておく。ここでは glib.IO_IN を監視して、イベントが発生するとハンドラ update_label を呼び出すようにした。ハンドラの内部では、引数として渡されるファイル・ディスクリプタを使って、好きなことができる。ハンドラの返り値は真偽値と定められており、False を返すと、そのハンドラは破棄される。