【问题标题】:pygtk console output for debugging用于调试的 pygtk 控制台输出
【发布时间】:2011-10-11 13:40:28
【问题描述】:

我有这个问题。我正在创建一个编辑器,我需要将控制台输出(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))

谢谢。

【问题讨论】:

    标签: python windows linux gtk pygtk


    【解决方案1】:

    由于您想要捕获 sys.stdoutsys.stderr,并且根据文档,这些对于解释器来说是全局的,因此无论在哪个线程完成输出,您都应该能够捕获它们。

    另一方面,您的代码离工作不远了。它缺少对事件循环的调用,这就是它冻结的原因。我添加了对c.main() 的呼叫。

    我还添加了一个打印“hello”的按钮,并将默认的sys.stdout 替换为ConsoleOutput 的实例,因此“hello”应该出现在文本视图上。

    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有自己的线程设施,只是在搜索谷歌时首先出现了python的模块。

    重要的一点是在ConsoleOutput 类中。请注意,我将更新控制台缓冲区的代码包装在一个名为self.update_buffer 的方法中,该方法通过gobject.idle_add 间接调用。这个函数的作用是调用self.update_buffer 在 gtk 事件循环中。必须这样做,因为所有更新 GUI 的调用都必须在事件循环内完成,否则 Gtk 无法同步对其数据结构的访问,您可能会遇到奇怪的行为和崩溃。 p>

    可能存在一些缓冲问题,导致输出无法立即出现在文本视图中。

    【讨论】:

    • 我不小心遗漏了一些文字,因为我在别处合并了它。问题是我不知道在这种情况下如何使用线程。我看过一些例子,但我无法理解它。如果您在示例中包含此内容,我将不胜感激:)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-07
    • 1970-01-01
    • 2011-05-19
    • 2017-03-16
    • 2015-01-20
    • 1970-01-01
    • 2013-05-18
    相关资源
    最近更新 更多