Gedit for Windows part3 | PaePoi
を少し改造しようと調べている時に g_idle_add という GLib の関数を知った。
筆者は何も知らないな、もっと勉強しなければいけないようだ。
何も処理を行っていないアイドル時にシグナルを送りつける。
ハンドラにて True を戻すとループ継続、False を戻すとループが止る。
g_timeout_add と同様みたい、ちとテスト。
#!/usr/bin/env python3 from gi.repository import Gtk, GLib class IdleTest(Gtk.Window): def __init__(self): Gtk.Window.__init__(self) self.connect("delete-event", Gtk.main_quit) self.label = Gtk.Label("0") button = Gtk.Button.new_with_label("Time consuming process") button.connect("clicked", self.on_clicked) vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0) vbox.pack_start(self.label, False, False, 0) vbox.pack_start(button, False, False, 0) self.add(vbox) self.show_all() # var self.count = 0 # Idle GLib.idle_add(self.on_idle) def on_idle(self): if self.count == 1000000: return False self.count += 1 self.label.set_text("{0}".format(self.count)) return True def on_clicked(self, widget, data=None): s = "" for i in range(10000000): s += "homura" IdleTest() Gtk.main()
ボタンを押して何か処理を行っている最中は見事にシグナルは停止する。
なるほど、同一プロセスで何もしていない時だけシグナルが発生するのか。
#!/usr/bin/env python3 from gi.repository import Gtk, GLib class IdleTest(Gtk.Window): def __init__(self): Gtk.Window.__init__(self) self.connect("delete-event", Gtk.main_quit) self.label1 = Gtk.Label("0") self.label2 = Gtk.Label("0") vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0) vbox.pack_start(self.label1, False, False, 0) vbox.pack_start(self.label2, False, False, 0) self.add(vbox) self.show_all() # var self.count1 = 0 self.count2 = 0 # Idle GLib.idle_add(self.on_idle) def on_idle(self): if self.count1 == 100000: return False if self.count1 == 50000: GLib.idle_add(self.on_idle2) self.count1 += 1 self.label1.set_text("{0}".format(self.count1)) return True def on_idle2(self): if self.count2 == 100000: return False self.count2 += 1 self.label2.set_text("{0}".format(self.count2)) return True IdleTest() Gtk.main()
2 つ作成しても別スレッドとして動作するみたいですね。
上記のような使い方は CPU 負荷が凄いのでヤメたほうがいいと一応。
これがどういう時に便利かというと簡易スレッド分離。
ランチャを作成し、起動したことを書き出す。
そして終了コードを調べて表示したい等とする。
#!/usr/bin/env python3 from gi.repository import Gtk import subprocess class IdleTest(Gtk.Window): def __init__(self): Gtk.Window.__init__(self) self.connect("delete-event", Gtk.main_quit) view = Gtk.TextView() view.set_size_request(200, 100) self.buf = view.get_buffer() button = Gtk.Button.new_with_label("gnome-calculator") button.connect("clicked", self.on_clicked) vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0) vbox.pack_start(view, True, True, 0) vbox.pack_end(button, False, False, 0) self.add(vbox) self.show_all() def on_clicked(self, widget, data=None): self.buf.set_text("Do gnome-calculator\n\n") # it = self.buf.get_end_iter() retcode = subprocess.call(["gnome-calculator"]) if retcode == 0: self.buf.insert(it, "Sucsess") else: self.buf.insert(it, "Error: {0}".format(retcode)) IdleTest() Gtk.main()
動きそうな気がするけど実際は on_clicked を抜けるまで何も書き出されない。
なので on_clicked にて g_idle_add を入れてスレッドを別にする。
#!/usr/bin/env python3 from gi.repository import Gtk, GLib import subprocess class IdleTest(Gtk.Window): def __init__(self): Gtk.Window.__init__(self) self.connect("delete-event", Gtk.main_quit) view = Gtk.TextView() view.set_size_request(200, 100) self.buf = view.get_buffer() button = Gtk.Button.new_with_label("gnome-calculator") button.connect("clicked", self.on_clicked) vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0) vbox.pack_start(view, True, True, 0) vbox.pack_end(button, False, False, 0) self.add(vbox) self.show_all() def on_clicked(self, widget, data=None): self.buf.set_text("Do gnome-calculator\n\n") GLib.idle_add(self.on_idle) def on_idle(self): it = self.buf.get_end_iter() retcode = subprocess.call(["gnome-calculator"]) if retcode == 0: self.buf.insert(it, "Sucsess") else: self.buf.insert(it, "Error: {0}".format(retcode)) return False IdleTest() Gtk.main()
これなら on_clicked は抜けランチャの終了待機も問題なく行われる。
つまりいつ終るか解らない処理を待つ必要がある場合に利用できる。
こんな感じで簡易なスレッドが必要な場合はもうコレで充分ですよね。