5

stdout のリダイレクトと出力の 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」は、実際には、すべて独自のロガーが設定されているさまざまな関数の単なるラッパーです。独自のロガーを持つ各関数からインスタンス化できるように、「グローバル」な新しいロギング ハンドラーを定義する際に助けが必要です。どんな助けでも大歓迎です。

4

2 に答える 2

5

私が正しく理解していることを確認するために:

ログ メッセージを 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

それが役に立てば幸い。

于 2013-08-12T18:58:00.943 に答える
3

これは、あなたが望むことを行う完全に改訂された答えです。あなたの質問のコードのどの行が変更され、どこに新しい行が追加されたかを示しようとしました。

デフォルトでは、組み込みlogger.StreamHandlerハンドラ クラスは にメッセージを出力するため、テキスト ウィジェットsys.stderrもリダイレクトするには、そのようにsys.stdout設定されたカスタム コンソール ハンドラを使用して新しいロガーを作成する必要があります。これをモジュール内のすべてのロガーに適用したいので、この設定は、他のすべての名前付きロガーが設定を継承する名前のない「ルート」ロガーに適用する必要があります。

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()
于 2013-02-14T23:09:39.223 に答える