【问题标题】:How to only emit one directoryChanged signal with QFileSystemWatcher如何使用 QFileSystemWatcher 仅发出一个 directoryChanged 信号
【发布时间】:2015-02-17 21:57:54
【问题描述】:

这是我的应用程序的基本前提:

我已经建立了一个 QFileSystemWatcher 来监视一个目录。

Path = [r'C:\Users\user\Documents\Images']
DirectoryWatcher = QtCore.QFileSystemWatcher(Path)
DirectoryWatcher.directoryChanged.connect(showImages.UpdateImages)

我过去使用过 QFileSystemWatcher,它总是能完美运行(对于目录和文件更改)。

应用程序将显示 \Images 文件夹中图像的幻灯片。将新图像放置在 \Images 文件夹中时,幻灯片将重置为包含新图像。如果图像从 \Images 文件夹中删除,幻灯片将再次重置。

我遇到的问题是:如果我将多个图像拖到 \Images 文件夹中,则会多次触发 directoryChanged 信号。信号被触发,并且为添加到文件夹中的每个图像运行相应的 UpdateImages() 例程,即使它们是同时添加的(即选择多个图像,将它们拖放到 \Images 中)。

这严重破坏了我的日常生活。有没有办法为一批目录更改触发一次 directoryChanged 信号? IE。在将最终图像添加到目录之前,我可以禁用信号吗?

非常感谢!

【问题讨论】:

  • 我不认为图像是真正的同时复制。除非您实施一些时间延迟,否则这是预期的行为。
  • 看起来没有适合您需要的信号,但您可以将directoryChanged 连接到设置标志或具有计时器的更智能的功能,而不是立即更新图像。这样您就可以自己过滤事件。
  • 你也可以研究eventFilter,它可以让你拦截和操纵某种类型的事件。
  • 感谢您的意见,非常感谢。我没有过多地使用“eventFilter”,但我可以看到它可能很有用。 Windows(7,如果有区别的话)是否“宣布”有多少文件将被添加到目录中?如果我知道要移动的文件数量,在它们移动之前,我可以设置一个过滤事件,该事件在发出 directoryChanged 信号时运行。

标签: python pyqt pyside qfilesystemwatcher


【解决方案1】:

解决方案是简单地避免将directoryChanged 信号连接到更新图像的插槽。相反,只要在发生任何更改时设置一个标志,然后定期检查该标志以查看是否需要任何更新(这可以通过简单的计时器机制来完成)。

这是一个演示这个想法的基本脚本:

import sys, os
from PyQt4 import QtCore, QtGui

class Window(QtGui.QWidget):
    def __init__(self):
        super(Window, self).__init__()
        self.list = QtGui.QListWidget(self)
        self.button = QtGui.QPushButton('Choose Directory', self)
        self.button.clicked.connect(self.handleSetDirectory)
        layout = QtGui.QVBoxLayout(self)
        layout.addWidget(self.list)
        layout.addWidget(self.button)
        self.watcher = QtCore.QFileSystemWatcher(self)
        self.watcher.directoryChanged.connect(self.handleDirectoryChanged)
        self.timer = QtCore.QTimer(self)
        self.timer.setInterval(500)
        self.timer.timeout.connect(self.handleTimer)
        self.handleSetDirectory(QtCore.QDir.tempPath())

    def handleDirectoryChanged(self):
        self.timer.stop()
        print('Directory Changed')
        self._changed = True
        self.timer.start()

    def handleSetDirectory(self, directory=None):
        if not directory:
            directory = QtGui.QFileDialog.getExistingDirectory(self)
        if directory:
            self.timer.stop()
            self.watcher.removePaths(self.watcher.directories())
            self._changed = False
            self.watcher.addPath(directory)
            self.updateList()
            self.timer.start()

    def handleTimer(self):
        if self._changed:
            self._changed = False
            self.updateList()

    def updateList(self):
        print('Update List')
        self.list.clear()
        for directory in self.watcher.directories():
            self.list.addItems(os.listdir(directory))

if __name__ == '__main__':

    import sys
    app = QtGui.QApplication(sys.argv)
    window = Window()
    window.resize(250, 600)
    window.show()
    sys.exit(app.exec_())

【讨论】:

  • 感谢您的评论,非常感谢(一如既往!)。我将逐行浏览您的代码,但与此同时,轮询真的是解决此问题的唯一实用方法吗?我不反对在这种特殊情况下进行轮询,我只是假设对已建立的信号过程会有更高水平的控制。再次感谢!
  • @jars121。这个问题与信号无关,甚至与一般的 Qt 无关:它纯粹与文件系统的工作方式有关。 Qt 在文件系统通知方面完全依赖于操作系统。一些操作是严格原子的(例如文件重命名,在某些情况下),但大多数不是。 QFileSystemWatcher 是一个相当基本的包装类,它隐藏了各种平台之间的大部分细节。这使得它可以方便地用于简单的任务,但它显然缺乏操作系统本身可能提供的许多细粒度控制。
  • 公平点。从那以后我做了更多的阅读,似乎单个“简单”事件,例如将文件复制到目录,实际上可能涉及操作系统本身发出的几个低级信号。鉴于 Python 只是读取发出的 OS 信号(如您所说),在这种情况下没有什么可以做的。我目前正在重写应用程序以涉及标志和轮询,看起来这将是一种非常合适的替代方法。再次感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多