Skip to main content
 首页 » 编程设计

python之将看门狗与 Tkinter 一起使用

2025年05月04日14myhome

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

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 应用程序)。现在,当用户按下某个按钮时,我想像以前一样调用 watchdog 来监视文件更改,并调用 dispatch() 对它做一些事情并更新一些 tkinter ui 小部件,如进度条相同的脚本。

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

请您参考如下方法:

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

以下示例将看门狗事件放在队列中,并使用 event_generate 在检测到看门狗事件时从观察器向 GUI 发送信号。我不确定以下是否适用于所有情况,因为目前我只能访问 linux box 来测试它。然而,它似乎在 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()