【问题标题】:Use watchdog along with Tkinter与 Tkinter 一起使用看门狗
【发布时间】:2017-01-16 18:34:57
【问题描述】:

所以我有一个小脚本来监视文件的更改/修改,如果文件被更改,它会做很多事情,比如:

class Event(LoggingEventHandler):
def dispatch(self, event):
    #Do something here

if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO,
                        format='%(asctime)s - %(message)s',
                        datefmt='%Y-%m-%d %H:%M:%S')
    event_handler = Event()
    observer = Observer()
    observer.schedule(event_handler, my_path, recursive=True)
    observer.start()
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        observer.stop()
    observer.join()

而且效果很好。但是我有另一个带有一堆 Tkinter 小部件的脚本(带有mainloop() 的典型 tk 应用程序)。现在,当用户按下某个按钮时,我想像以前一样调用看门狗来监视文件更改并调用dispatch(),它会对其进行大量处理并在同一脚本中更新一些 tkinter ui 小部件(如进度条)。

对这个 GUI 东西很陌生,不知道如何使看门狗循环和 root.mainloop 一起工作。怎么办?

【问题讨论】:

    标签: python python-3.x user-interface tkinter


    【解决方案1】:

    Watchdog 在自己的线程中运行,因此您无需做太多事情。如果要根据事件修改 GUI,则应设置线程安全队列。 Tkinter 小部件不应被多个线程修改,因此常见的模式是使用线程安全队列在线程之间进行通信。

    以下示例将看门狗事件置于队列中,并在检测到看门狗事件时使用event_generate 将信号从观察者发送到 GUI。我不确定以下内容是否适用于所有情况,因为我目前只能访问 linux 机器来测试它。但是,它在 linux 上似乎可以正常工作。

    import Tkinter as tk
    from watchdog.observers import Observer
    from watchdog.events import FileSystemEventHandler
    
    from Queue import Queue
    import sys
    
    class CustomHandler(FileSystemEventHandler):
        def __init__(self, app):
            FileSystemEventHandler.__init__(self)
            self.app = app
        def on_created(self, event): app.notify(event)
        def on_deleted(self, event): app.notify(event)
        def on_modified(self, event): app.notify(event)
        def on_moved(self, event): app.notify(event)
    
    class App(object):
        def __init__(self):
            path = sys.argv[1] if len(sys.argv) > 1 else "/tmp"
            handler = CustomHandler(self)
            self.observer = Observer()
            self.observer.schedule(handler, path, recursive=True)
    
            self.queue = Queue()
            self.root = tk.Tk()
    
            self.text = tk.Text(self.root)
            self.text.pack(fill="both", expand=True)
    
            self.text.insert("end", "Watching %s...\n" % path)
    
            self.root.bind("<Destroy>", self.shutdown)
            self.root.bind("<<WatchdogEvent>>", self.handle_watchdog_event)
    
            self.observer.start()
    
        def handle_watchdog_event(self, event):
            """Called when watchdog posts an event"""
            watchdog_event = self.queue.get()
            print("event type:", type(watchdog_event))
            self.text.insert("end", str(watchdog_event) + "\n")
    
        def shutdown(self, event):
            """Perform safe shutdown when GUI has been destroyed"""
            self.observer.stop()
            self.observer.join()
    
        def mainloop(self):
            """Start the GUI loop"""
            self.root.mainloop()
    
        def notify(self, event):
            """Forward events from watchdog to GUI"""
            self.queue.put(event)
            self.root.event_generate("<<WatchdogEvent>>", when="tail")
    
    app = App()
    app.mainloop()
    

    【讨论】:

    • 很好的答案。谢谢。 event_generate 很棒
    猜你喜欢
    • 1970-01-01
    • 2021-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-25
    • 1970-01-01
    • 1970-01-01
    • 2012-02-22
    相关资源
    最近更新 更多