我有这个问题。我正在创建一个编辑器,我需要输出到textview的控制台输出(sys.stderr和sys.stdout)。问题是,当我启动控制台时,它等待它退出,但是我希望它能抓住任何东西并将其输出到textview,所以我认为你可能需要不同的线程,但它不会让它变得不可能从另一个线程中捕获任何东西?如果编辑器没有从终端启动,我想要这个。如果您想知道它将用作模块。这是到目前为止的代码:
import sys
import gtk
import pygtk
pygtk.require('2.0')
class Console:
def __init__(self):
tv = gtk.TextView()
tv.set_editable(False)
tv.set_wrap_mode(gtk.WRAP_WORD)
self.buffer = tv.get_buffer()
table = gtk.Table(3, 6, gtk.FALSE)
table.attach(tv, 0, 6, 0, 1)
#### Main window
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.connect('destroy_event', lambda w, e: gtk.mainquit())
self.window.connect('delete_event', lambda w, e: gtk.mainquit())
self.window.set_border_width(10)
self.window.add(table)
self.window.set_title('Search')
self.window.set_default_size(300, 300)
self.window.show_all()
def main(self):
gtk.main()
c = Console()
class ConsoleOutput:
def __init__(self, source):
self.source=source
self.buf = []
def write(self, data):
self.buf.append(data)
if data.endswith('\n'):
c.buffer.insert(c.buffer.get_end_iter(), ''.join(self.buf))
self.buf = []
def __del__(self):
if self.buf != []:
c.buffer.insert(c.buffer.get_end_iter(), ''.join(self.buf))
谢谢。
答案 0 :(得分:2)
由于您希望捕获sys.stdout
和sys.stderr
并且这些对于解释器来说是全局的,因此无论输出完成的线程如何,您都应该能够捕获它们。
另一方面,你的代码离工作还不远。它缺少对事件循环的调用,这就是它冻结的原因。我添加了对c.main()
的调用。
我还添加了一个打印“hello”的按钮,我用sys.stdout
的实例替换了默认的ConsoleOutput
,因此“hello”应该出现在textview上。
import sys
import gtk
import pygtk
pygtk.require('2.0')
import gobject
import threading
class MyThread(threading.Thread):
def __init__(self, name):
threading.Thread.__init__(self)
self.name = name
def run(self):
for i in range(10):
print "Hello %d from thread %s" % (i, self.name)
class Console:
def __init__(self):
tv = gtk.TextView()
tv.set_editable(False)
tv.set_wrap_mode(gtk.WRAP_WORD)
self.buffer = tv.get_buffer()
button = gtk.Button("Update")
button.connect("clicked", self.update, None)
table = gtk.Table(3, 6, gtk.FALSE)
table.attach(tv, 0, 6, 0, 1)
table.attach(button, 0, 6, 1, 2)
#### Main window
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.connect('destroy_event', lambda w, e: gtk.mainquit())
self.window.connect('delete_event', lambda w, e: gtk.mainquit())
self.window.set_border_width(10)
self.window.add(table)
self.window.set_title('Search')
self.window.set_default_size(300, 300)
self.window.show_all()
def update(self, widget, data=None):
print "hello"
MyThread("A").start()
MyThread("B").start()
def main(self):
gtk.main()
c = Console()
class ConsoleOutput:
def __init__(self, source):
self.source=source
self.buf = []
def update_buffer(self):
c.buffer.insert(c.buffer.get_end_iter(), ''.join(self.buf))
self.buf = []
def write(self, data):
self.buf.append(data)
if data.endswith('\n'):
gobject.idle_add(self.update_buffer)
def __del__(self):
if self.buf != []:
gobject.idle_add(self.update_buffer)
sys.stdout = ConsoleOutput(None)
c.main()
编辑:我已经更新了我的答案以包含一个线程示例。按下按钮时会创建两个线程。我使用了python的线程模块。我认为pygtk有自己的线程设施,只是在搜索Google时首先出现了python的模块。
重要的一点是ConsoleOutput
课程。请注意,我已经在名为self.update_buffer
的方法中包装了更新控制台缓冲区的代码,该方法通过gobject.idle_add
间接调用。此函数的作用是在gtk事件循环中调用self.update_buffer
。必须以这种方式完成,因为所有更新GUI的调用必须在事件循环中完成,否则Gtk无法同步对其数据结构的访问,您可能会遇到奇怪的行为和崩溃。
可能存在一些阻止输出在文本视图中一次出现的缓冲问题。