2012-11-10 60 views
18

Có bất kỳ ví dụ nào về cách thiết lập đăng nhập bằng Python vào một tiện ích văn bản Tkinter không? Tôi đã thấy điều này được sử dụng trong một số ứng dụng nhưng không thể tìm ra cách để chỉ đạo việc ghi nhật ký vào bất kỳ thứ gì khác ngoài tệp nhật ký.Đăng nhập bằng Python vào tiện ích văn bản Tkinter

Trả lời

9

Bạn nên phân lớp logging.Handler, ví dụ:

import logging 
from Tkinter import INSERT 

class WidgetLogger(logging.Handler): 
    def __init__(self, widget): 
     logging.Handler.__init__(self) 
     self.widget = widget 

    def emit(self, record): 
     # Append message (record) to the widget 
     self.widget.insert(INSERT, record + '\n') 
6

tôi được xây dựng trên ý tưởng của Yuri, nhưng cần thiết để thực hiện một vài thay đổi để có được những điều làm việc:

import logging 
import Tkinter as tk 

class WidgetLogger(logging.Handler): 
    def __init__(self, widget): 
     logging.Handler.__init__(self) 
     self.setLevel(logging.INFO) 
     self.widget = widget 
     self.widget.config(state='disabled') 

    def emit(self, record): 
     self.widget.config(state='normal') 
     # Append message (record) to the widget 
     self.widget.insert(tk.END, self.format(record) + '\n') 
     self.widget.see(tk.END) # Scroll to the bottom 
     self.widget.config(state='disabled') 

Lưu ý rằng chuyển đổi qua lại trạng thái lưng và từ 'bình thường' sang 'bị vô hiệu hóa' là cần thiết để làm cho tiện ích chỉ đọc ở chế độ chỉ đọc Text.

1

Xây dựng thêm về câu trả lời của ford, đây là tiện ích con văn bản cuộn có đuôi nhật ký. Thành viên logging_handler là những gì bạn thêm vào nhật ký của mình.

import logging 
from Tkinter import END, N, S, E, W, Scrollbar, Text 
import ttk 

class LoggingHandlerFrame(ttk.Frame): 

    class Handler(logging.Handler): 
     def __init__(self, widget): 
      logging.Handler.__init__(self) 
      self.setFormatter(logging.Formatter("%(asctime)s: %(message)s")) 
      self.widget = widget 
      self.widget.config(state='disabled') 

     def emit(self, record): 
      self.widget.config(state='normal') 
      self.widget.insert(END, self.format(record) + "\n") 
      self.widget.see(END) 
      self.widget.config(state='disabled') 

    def __init__(self, *args, **kwargs): 
     ttk.Frame.__init__(self, *args, **kwargs) 

     self.columnconfigure(0, weight=1) 
     self.columnconfigure(1, weight=0) 
     self.rowconfigure(0, weight=1) 

     self.scrollbar = Scrollbar(self) 
     self.scrollbar.grid(row=0, column=1, sticky=(N,S,E)) 

     self.text = Text(self, yscrollcommand=self.scrollbar.set) 
     self.text.grid(row=0, column=0, sticky=(N,S,E,W)) 

     self.scrollbar.config(command=self.text.yview) 

     self.logging_handler = LoggingHandlerFrame.Handler(self.text) 
0

Xây dựng trên ford quá nhưng thêm văn bản màu!

class WidgetLogger(logging.Handler): 
    def __init__(self, widget): 
     logging.Handler.__init__(self) 
     self.setLevel(logging.DEBUG) 
     self.widget = widget 
     self.widget.config(state='disabled') 
     self.widget.tag_config("INFO", foreground="black") 
     self.widget.tag_config("DEBUG", foreground="grey") 
     self.widget.tag_config("WARNING", foreground="orange") 
     self.widget.tag_config("ERROR", foreground="red") 
     self.widget.tag_config("CRITICAL", foreground="red", underline=1) 

     self.red = self.widget.tag_configure("red", foreground="red") 
    def emit(self, record): 
     self.widget.config(state='normal') 
     # Append message (record) to the widget 
     self.widget.insert(tk.END, self.format(record) + '\n', record.levelname) 
     self.widget.see(tk.END) # Scroll to the bottom 
     self.widget.config(state='disabled') 
     self.widget.update() # Refresh the widget 
5

Ngoài các câu trả lời ở trên: mặc dù có rất nhiều các giải pháp đề xuất cho việc này (ở đây và cũng trong this other thread), tôi đã phải vật lộn khá một chút để làm công việc này bản thân mình. Cuối cùng, tôi chạy vào this text handler class by Moshe Kaplan, sử dụng tiện ích ScrolledText (có lẽ dễ dàng hơn phương thức ScrollBar).

Tôi mất một thời gian để tìm hiểu cách sử dụng lớp Moshe trong ứng dụng luồng. Cuối cùng tôi tạo ra một kịch bản demo tối thiểu cho thấy làm thế nào để làm cho nó tất cả các công việc. Vì nó có thể hữu ích cho những người khác tôi đang chia sẻ nó bên dưới. Trong trường hợp cụ thể của tôi, tôi muốn đăng nhập vào cả GUI và tệp văn bản; nếu bạn không cần điều đó, chỉ cần xóa thuộc tính tên tệp trong ghi nhật ký.basicConfig.

import time 
import threading 
import logging 
try: 
    import tkinter as tk # Python 3.x 
    import tkinter.scrolledtext as ScrolledText 
except ImportError: 
    import Tkinter as tk # Python 2.x 
    import ScrolledText 

class TextHandler(logging.Handler): 
    # This class allows you to log to a Tkinter Text or ScrolledText widget 
    # Adapted from Moshe Kaplan: https://gist.github.com/moshekaplan/c425f861de7bbf28ef06 

    def __init__(self, text): 
     # run the regular Handler __init__ 
     logging.Handler.__init__(self) 
     # Store a reference to the Text it will log to 
     self.text = text 

    def emit(self, record): 
     msg = self.format(record) 
     def append(): 
      self.text.configure(state='normal') 
      self.text.insert(tk.END, msg + '\n') 
      self.text.configure(state='disabled') 
      # Autoscroll to the bottom 
      self.text.yview(tk.END) 
     # This is necessary because we can't modify the Text from other threads 
     self.text.after(0, append) 

class myGUI(tk.Frame): 

    # This class defines the graphical user interface 

    def __init__(self, parent, *args, **kwargs): 
     tk.Frame.__init__(self, parent, *args, **kwargs) 
     self.root = parent 
     self.build_gui() 

    def build_gui(self):      
     # Build GUI 
     self.root.title('TEST') 
     self.root.option_add('*tearOff', 'FALSE') 
     self.grid(column=0, row=0, sticky='ew') 
     self.grid_columnconfigure(0, weight=1, uniform='a') 
     self.grid_columnconfigure(1, weight=1, uniform='a') 
     self.grid_columnconfigure(2, weight=1, uniform='a') 
     self.grid_columnconfigure(3, weight=1, uniform='a') 

     # Add text widget to display logging info 
     st = ScrolledText.ScrolledText(self, state='disabled') 
     st.configure(font='TkFixedFont') 
     st.grid(column=0, row=1, sticky='w', columnspan=4) 

     # Create textLogger 
     text_handler = TextHandler(st) 

     # Logging configuration 
     logging.basicConfig(filename='test.log', 
      level=logging.INFO, 
      format='%(asctime)s - %(levelname)s - %(message)s')   

     # Add the handler to logger 
     logger = logging.getLogger()   
     logger.addHandler(text_handler) 

def worker(): 
    # Skeleton worker function, runs in separate thread (see below) 
    while True: 
     # Report time/date at 2-second intervals 
     time.sleep(2) 
     timeStr = time.asctime() 
     msg = 'Current time: ' + timeStr 
     logging.info(msg) 

def main(): 

    root = tk.Tk() 
    myGUI(root) 

    t1 = threading.Thread(target=worker, args=[]) 
    t1.start() 

    root.mainloop() 
    t1.join() 

main() 

Github Gist liên kết đến mã trên đây:

https://gist.github.com/bitsgalore/901d0abe4b874b483df3ddc4168754aa

+0

Đối với những bạn nhận được ** 'TclStackFree: freePtr' sai ** lỗi, câu trả lời ở trên giải quyết này. Sử dụng 'self.widget.after (0, function_to_execute)' đảm bảo rằng widget được sửa đổi bởi chuỗi nó thuộc về. – Felix

Các vấn đề liên quan