TkinterでLog出力用windowを作ってみました


TkinterでWindowsでGUIを作ると、リアルタイムのprintデバッグが難しいため
メインウィンドウのほかにLog Windowを立ち上げた方が便利だと思い、作ってみました。
あくまでもサブウィンドウなのでToplevelでのWindowを立ち上げます。
(TkinterのToplevel windowsの使いかをちゃんと理解できていません)
ただのLog Windowでは面白くないので、Log種類によって表示/非表示ができるようなチェックボックスを入れてみました。

追記: 出力したが、出力に追随してスクロールされなかったので view('end')を追加。
pythonの標準出力に対応するため write(str), flush()を追加

sys.stdout = Logwindow として使えます。

IOLogWindow.py
import sys
import serial
import binascii
import time
import tkinter as tk
from tkinter import scrolledtext

TEXT_COLORS = {
    'MESSAGE' : 'black',
    'INPUT' : 'blue',
    'OUTPUT' : 'green',
    'ERROR' : 'red',
    'DEBUG' : 'yellow'    
    }

# Initial value = flag=True or False
class SimpleCheck(tk.Checkbutton):
    def __init__(self, parent, *args, **kw):
        self.flag = kw.pop('flag')
        self.var =  tk.BooleanVar()
        if self.flag:
            self.var.set(True)
        self.txt = kw["text"]
        tk.Checkbutton.__init__(self, parent, *args, **kw, variable=self.var)

    def get(self):
        return self.var.get()

class IOLogFrame(tk.Frame):
    def __init__(self, master):    
        tk.Frame.__init__(self, master)
        master.title("Log Window")

        #view/hide choice
        select_frame = tk.LabelFrame(master, text= "Log text disable",relief = 'groove')

        self.ckboxs = []
        for key in TEXT_COLORS:
            cb = SimpleCheck(select_frame, text=key, command=self.callback, flag=False)
            self.ckboxs.append(cb)
            cb.pack(side='left')
        select_frame.pack(side = 'top', fill = 'x')

        self.txt = scrolledtext.ScrolledText(master)
        self.txt.pack(fill=tk.BOTH, expand=1)
        for key in TEXT_COLORS:
            self.txt.tag_config(key, foreground=TEXT_COLORS[key])

    def callback(self):
        count = 0
        for key in TEXT_COLORS:
            if(self.ckboxs[count].get()):
                self.hide(key)
            else:
                self.view(key)
            count += 1

    def print(self, str, state='MESSAGE'):
        self.txt.insert(tk.END, str+'\n', state)
        self.txt.see(tk.END)

    def hide(self, tag):
        self.txt.tag_config(tag, elide=True)

    def view(self, tag):
        self.txt.tag_config(tag, elide=False)

    def write(self, str, state='MESSAGE'):
        self.txt.insert(tk.END, str+'\n', state)
        self.txt.see(tk.END)

    def flush(self):
        pass

#sample main window
class IOLogWindow(tk.Toplevel):
    def __init__(self, master):
        master.title("Main WIndow")
        tk.Toplevel.__init__(self, master)
        io = IOLogFrame(self)
        io.print("Message")
        io.print("--ERROR--", 'ERROR')
        io.print("--INPUT--", 'INPUT')
        io.print("--OUTPUT--", 'OUTPUT')
        io.print("--DEBUG--", 'DEBUG')    

if __name__ == '__main__':
    win = tk.Tk()
    io=IOLogWindow(win)
    win.mainloop()