![](/img/trans.png)
[英]Use threading and queues to redirect logger messages to tkinter widget in python
[英]Redirect output from Python logger to tkinter widget
花了一些時間重定向標准輸出並將輸出記錄到tkinter文本小部件后,我決定需要一些幫助。 我的代碼如下:
#!/usr/bin/env python
from Tkinter import *
import logging
from threading import Thread
class IODirector(object):
def __init__(self,text_area):
self.text_area = text_area
class StdoutDirector(IODirector):
def write(self,str):
self.text_area.insert(END,str)
def flush(self):
pass
class App(Frame):
def __init__(self, master):
self.master = master
Frame.__init__(self,master,relief=SUNKEN,bd=2)
self.start()
def start(self):
self.master.title("Test")
self.submit = Button(self.master, text='Run', command=self.do_run, fg="red")
self.submit.grid(row=1, column=2)
self.text_area = Text(self.master,height=2.5,width=30,bg='light cyan')
self.text_area.grid(row=1,column=1)
def do_run(self):
t = Thread(target=print_stuff)
sys.stdout = StdoutDirector(self.text_area)
t.start()
def print_stuff():
logger = logging.getLogger('print_stuff')
logger.info('This will not show')
print 'This will show'
print_some_other_stuff()
def print_some_other_stuff():
logger = logging.getLogger('print_some_other_stuff')
logger.info('This will also not show')
print 'This will also show'
def main():
logger = logging.getLogger('main')
root = Tk()
app = App(root)
root.mainloop()
if __name__=='__main__':
main()
我知道可以基於文本窗口小部件定義一個新的日志記錄處理程序,但是我無法使其正常工作。 函數“ print_stuff”實際上只是許多不同函數的包裝,所有這些函數都有自己的記錄器。 我需要幫助定義一個新的“全局”日志記錄處理程序,以便可以從具有自己記錄器的每個函數中實例化它。 任何幫助深表感謝。
只是為了確保我理解正確:
您想將日志記錄消息都打印到STDout和Tkinter文本小部件中,但是日志記錄不會在標准控制台中打印。
如果確實是您的問題,請按照以下步驟操作。
首先,讓我們在Tkinter中創建一個非常簡單的控制台,它實際上可以是任何文本小部件,但出於完整性考慮,我將其包括在內:
class LogDisplay(tk.LabelFrame):
"""A simple 'console' to place at the bottom of a Tkinter window """
def __init__(self, root, **options):
tk.LabelFrame.__init__(self, root, **options);
"Console Text space"
self.console = tk.Text(self, height=10)
self.console.pack(fill=tk.BOTH)
現在,讓我們重寫日志記錄處理程序,以重定向到參數中的控制台,並且仍然自動打印到STDout:
class LoggingToGUI(logging.Handler):
""" Used to redirect logging output to the widget passed in parameters """
def __init__(self, console):
logging.Handler.__init__(self)
self.console = console #Any text widget, you can use the class above or not
def emit(self, message): # Overwrites the default handler's emit method
formattedMessage = self.format(message) #You can change the format here
# Disabling states so no user can write in it
self.console.configure(state=tk.NORMAL)
self.console.insert(tk.END, formattedMessage) #Inserting the logger message in the widget
self.console.configure(state=tk.DISABLED)
self.console.see(tk.END)
print(message) #You can just print to STDout in your overriden emit no need for black magic
希望能幫助到你。
這是一個完全修訂的答案,可以滿足您的需求。 我試圖指出問題中代碼的哪些行已更改以及在哪里添加了新行。
默認情況下,內置的logger.StreamHandler
處理程序類將消息輸出到sys.stderr
,因此logger.StreamHandler
它們也將sys.stdout
重定向到文本小部件,則需要構造一個新的logger,並為其設置一個自定義控制台處理程序。 由於您希望將其應用於模塊中的所有記錄器,因此需要將此設置應用於所有其他命名記錄器將繼承其設置的無名“根”記錄器。
from Tkinter import *
import logging
from threading import Thread
class IODirector(object):
def __init__(self, text_area):
self.text_area = text_area
class StdoutDirector(IODirector):
def write(self, msg):
self.text_area.insert(END, msg)
def flush(self):
pass
class App(Frame):
def __init__(self, master):
self.master = master
Frame.__init__(self, master, relief=SUNKEN, bd=2)
self.start()
def start(self):
self.master.title("Test")
self.submit = Button(self.master, text='Run', command=self.do_run, fg="red")
self.submit.grid(row=1, column=2)
self.text_area = Text(self.master, height=2.5, width=30, bg='light cyan')
self.text_area.grid(row=1, column=1)
def do_run(self):
t = Thread(target=print_stuff)
sys.stdout = StdoutDirector(self.text_area)
# configure the nameless "root" logger to also write # added
# to the redirected sys.stdout # added
logger = logging.getLogger() # added
console = logging.StreamHandler(stream=sys.stdout) # added
logger.addHandler(console) # added
t.start()
def print_stuff():
logger = logging.getLogger('print_stuff') # will inherit "root" logger settings
logger.info('This will now show') # changed
print 'This will show'
print_some_other_stuff()
def print_some_other_stuff():
logger = logging.getLogger('print_some_other_stuff') # will inherit "root" logger settings
logger.info('This will also now show') # changed
print 'This will also show'
def main():
logging.basicConfig(level=logging.INFO) # enable logging # added
root = Tk()
app = App(root)
root.mainloop()
if __name__=='__main__':
main()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.