【问题标题】:Tkinter - logging text in Text WidgetTkinter - 在文本小部件中记录文本
【发布时间】:2014-07-08 08:05:14
【问题描述】:

我想做一个能够在文本小部件中“记录”文本的类。其他应用程序可以使用此类向文本小部件发送和显示日志。

class TraceConsole():

    def __init__(self):
        # Init the main GUI window
        self._logFrame = Tk.Frame()
        self._log      = Tk.Text(self._logFrame, wrap=Tk.NONE, setgrid=True)
        self._scrollb  = Tk.Scrollbar(self._logFrame, orient=Tk.VERTICAL)
        self._scrollb.config(command = self._log.yview) 
        self._log.config(yscrollcommand = self._scrollb.set)
        # Grid & Pack
        self._log.grid(column=0, row=0)
        self._scrollb.grid(column=1, row=0, sticky=Tk.S+Tk.N)
        self._logFrame.pack()


    def log(self, msg, level=None):
        # Write on GUI
        self._log.insert('end', msg + '\n')

    def exitWindow(self):
        # Exit the GUI window and close log file
        print('exit..')

使用示例:

t = TraceConsole()
t.log('hello world!')

我现在的问题是我不知道将主循环放在哪里。该记录器必须“在后台”运行,并且在关闭窗口之前可以随时写入日志。

【问题讨论】:

    标签: python tkinter widget tk


    【解决方案1】:

    我为此苦苦挣扎了一阵子,但在这里总结了建议:

    我在下面创建了一个示例,以阐明使用 Tkinter 将日志记录到 GUI 控件的概念。下面的示例按照您的要求记录到文本控件,但您可以通过将 MyHandlerText 类替换/复制为 MyHandlerLabel、MyHandlerListbox 等其他处理程序类来将日志消息发送到其他 GUI 组件(选择您自己的处理程序类的名称)。然后,您将拥有一个处理各种感兴趣的 GUI 控件的处理程序。对我来说,最重要的“a-ha”时刻是 python.org 鼓励的模块级 getLogger 概念。

    import Tkinter
    import logging
    import datetime
    
    # this item "module_logger" is visible only in this module,
    # (but you can also reference this getLogger instance from other modules and other threads by passing the same argument name...allowing you to share and isolate loggers as desired)
    # ...so it is module-level logging and it takes the name of this module (by using __name__)
    # recommended per https://docs.python.org/2/library/logging.html
    module_logger = logging.getLogger(__name__)
    
    class simpleapp_tk(Tkinter.Tk):
        def __init__(self,parent):
            Tkinter.Tk.__init__(self,parent)
            self.parent = parent
    
            self.grid()
    
            self.mybutton = Tkinter.Button(self, text="ClickMe")
            self.mybutton.grid(column=0,row=0,sticky='EW')
            self.mybutton.bind("<ButtonRelease-1>", self.button_callback)
    
            self.mytext = Tkinter.Text(self, state="disabled")
            self.mytext.grid(column=0, row=1)
    
        def button_callback(self, event):
            now = datetime.datetime.now()
            module_logger.info(now)
    
    class MyHandlerText(logging.StreamHandler):
        def __init__(self, textctrl):
            logging.StreamHandler.__init__(self) # initialize parent
            self.textctrl = textctrl
    
        def emit(self, record):
            msg = self.format(record)
            self.textctrl.config(state="normal")
            self.textctrl.insert("end", msg + "\n")
            self.flush()
            self.textctrl.config(state="disabled")
    
    if __name__ == "__main__":
    
        # create Tk object instance
        app = simpleapp_tk(None)
        app.title('my application')
    
        # setup logging handlers using the Tk instance created above
        # the pattern below can be used in other threads...
        # ...to allow other thread to send msgs to the gui
        # in this example, we set up two handlers just for demonstration (you could add a fileHandler, etc)
        stderrHandler = logging.StreamHandler()  # no arguments => stderr
        module_logger.addHandler(stderrHandler)
        guiHandler = MyHandlerText(app.mytext)
        module_logger.addHandler(guiHandler)
        module_logger.setLevel(logging.INFO)
        module_logger.info("from main")    
    
        # start Tk
        app.mainloop()
    

    【讨论】:

      【解决方案2】:

      在这种情况下,您创建了一个将在应用程序中使用的组件。主循环将在该应用程序中被调用,它们将写入您的日志小部件。

      您可以添加一些简单的使用示例(例如您提供的示例)和/或在与 TraceConsole 相同的 python 文件中使用类似的东西进行测试

      if __name__ == '__main__':
          m = tkinter.Tk()
          t = TraceConsole()
          t.log('hello world!')
          m.mainloop()
      

      我通常会这样做,这样我就可以在将 tkinter 组件合并到我的应用程序之前自行测试它。

      【讨论】:

      • 在调用m.mainloop() 之后,将无法调用t.log('something'),这是我的问题。
      • 我的期望是你会在整个程序中调用t.log('something')。喜欢按钮:my_button = tkinter.Button(m, text="My Button", command=lambda: t.log("Pushed My Button"))
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-15
      • 1970-01-01
      • 2019-06-14
      • 2014-03-19
      相关资源
      最近更新 更多