我正在写一个Python的命令行模拟器一个GTK + GUI程序。 我的Python命令行实现为gtk.TextView,它可以用来输出结果prints
(以及从TextView的读取命令和exec
他们,但我不张贴在这里输入部分,因为它没有任何与题)。
我使用以下技术发球的stdout
的实际终端和我的Python命令行之间流:
r_out, w_out = os.pipe() # create a pipe, cause sys.stdout is unreadable, thus we can't poll it for available output
w_out_stream = os.fdopen(w_out, "w", 0) # open write-end of pipe with 0-length buffer
sys.stdout = w_out_stream # now prints and sys.stdout.writes would go to the pipe
watch = gobject.io_add_watch(r_out, gobject.IO_IN, stdout_callback) # poll the read-end of pipe for data and call stdout_callback
def stdout_callback(stream, condition):
data = os.read(stream, 1) # read the pipe byte-by-byte
iter = textbuf.get_end_iter() # textbuf is buffer of TextView, the GUI widget, I use as python command line
textbuf.insert(iter, data) # output stdout to GUI
sys.__stdout__.write(data) # output stdout to "real" terminal stdout
gtk.main()
这个工程相当不错的小输出。 但不幸的是,当输出变得比较大(如几千字节),我的应用程序挂起并且不显示任何输出。
但是,如果我发送一个SIGINT
,我的输出都出现在GUI和真正的终端。 很显然,我希望它有没有SIGINT。 任何想法,是什么原因导致这样的块?
外部进程阻塞UI,同时使用os.read,你应该使用glib.spawn_async产卵过程,并使用IOChannel读取输入类似:
from gi.repository import Gtk, GLib
class MySpawned(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self)
vb = Gtk.VBox(False, 5)
self.tw = Gtk.TextView()
bt = Gtk.Button('Run')
bt.connect('clicked', self.process)
vb.pack_start(self.tw, True, True, 0)
vb.pack_start(bt, False, False, 0)
self.add(vb)
self.set_size_request(200, 300)
self.connect('delete-event', Gtk.main_quit)
self.show_all()
def run(self):
Gtk.main()
def process(self, widget, data=None):
params = ['python', '-h']
def write_to_textview(io, condition):
print condition
if condition is GLib.IO_IN:
line = io.readline()
self.tw.props.buffer.insert_at_cursor(line)
return True
elif condition is GLib.IO_HUP|GLib.IO_IN:
GLib.source_remove(self.source_id)
return False
self.source_id = None
pid, stdin, stdout, stderr = GLib.spawn_async(params,
flags=GLib.SpawnFlags.SEARCH_PATH,
standard_output=True)
io = GLib.IOChannel(stdout)
self.source_id = io.add_watch(GLib.IO_IN|GLib.IO_HUP,
write_to_textview,
priority=GLib.PRIORITY_HIGH)
if __name__ == '__main__':
s = MySpawned()
s.run()
还有像一个极大的线程在那里,告诉你,你可以使用线程或其他的东西,请不要做,上面的例子不会阻止你即使在一个长期的过程UI和输出将在TextView的打印,作品在Windows太(但它会打开一个丑陋的控制台窗口,直到GLib的一个bug会得到固定)。
文章来源: pygtk: asynchronous output implemented with io_add_watch blocks when printing large output dataset