PyQt QFileDialog自定义代理筛选器无法正常工作

时间:2017-04-15 03:56:52

标签: proxy pyqt

此工作代码会显示一个QFileDialog,提示用户选择.csv文件:

def load(self,fileName=None):
        if not fileName:
            fileName=fileDialog.getOpenFileName(caption="Load Existing Radio Log",filter="csv (*.csv)")[0]
  ...
  ...

现在,我想将该过滤器更改为更具选择性。程序将每个项目保存为一组三个.csv文件(project.csv,project_fleetsync.csv,project_clueLog.csv)但我只希望文件对话框显示第一个(project.csv)以避免呈现用户如果只有其中三分之一可以由load()函数的其余部分处理,那么选择太多了。

根据this帖子,解决方案似乎是使用代理模型。所以,我将代码更改为以下内容(load()中的所有注释行都是我尝试过各种组合的内容):

def load(self,fileName=None):
    if not fileName:
        fileDialog=QFileDialog()
        fileDialog.setProxyModel(CSVFileSortFilterProxyModel(self))
#           fileDialog.setNameFilter("CSV (*.csv)")
#           fileDialog.setOption(QFileDialog.DontUseNativeDialog)
#           fileName=fileDialog.getOpenFileName(caption="Load Existing Radio Log",filter="csv (*.csv)")[0]
#           fileName=fileDialog.getOpenFileName(caption="Load Existing Radio Log")[0]
#           fileDialog.exec_()

...
...

# code for CSVFileSortFilterProxyModel partially taken from
#  https://github.com/ZhuangLab/storm-control/blob/master/steve/qtRegexFileDialog.py
class CSVFileSortFilterProxyModel(QSortFilterProxyModel):
    def __init__(self,parent=None):
        print("initializing CSVFileSortFilterProxyModel")
        super(CSVFileSortFilterProxyModel,self).__init__(parent)

    # filterAcceptsRow - return True if row should be included in the model, False otherwise
    #
    # do not list files named *_fleetsync.csv or *_clueLog.csv
    #  do a case-insensitive comparison just in case
    def filterAcceptsRow(self,source_row,source_parent):
        print("CSV filterAcceptsRow called")
        source_model=self.sourceModel()
        index0=source_model.index(source_row,0,source_parent)
        # Always show directories
        if source_model.isDir(index0):
            return True
        # filter files
        filename=source_model.fileName(index0)
#       filename=self.sourceModel().index(row,0,parent).data().lower()
        print("testing lowercased filename:"+filename)
        if filename.count("_fleetsync.csv")+filename.count("_clueLog.csv")==0:
            return True
        else:
            return False

当我调用load()函数时,我确实得到了“初始化CSVFileSortFilterProxyModel”输出,但显然没有调用filterAcceptsRow:没有“CSV filterAcceptsRow调用”输出,_fleetsync.csv和_clueLog.csv文件仍然在对话框中列出。显然我做错了什么......?

1 个答案:

答案 0 :(得分:1)

在另一个stackoverflow问题here找到解决方案。

从那个解决方案:

  

最值得注意的是打电话   dialog.setOption(QFileDialog :: DontUseNativeDialog)之前   dialog.setProxyModel。

此外,您似乎必须使用fileDialog.exec_()而不是fileDialog.getOpenFileName。您设置为setNameFilter的值确实显示在非本机对话框的过滤器循环字段中,但实际上仅用于装饰,因为proxymodel过滤器会覆盖它。在我看来,这是一件好事,因为你可以在过滤器循环中加入措辞,这表明用户对过滤的类型有用。

感谢用户Frank和ariwez。

更新:澄清一下,这是我正在使用的完整最终代码:

def load(self,fileName=None):
    if not fileName:
        fileDialog=QFileDialog()
        fileDialog.setOption(QFileDialog.DontUseNativeDialog)
        fileDialog.setProxyModel(CSVFileSortFilterProxyModel(self))
        fileDialog.setNameFilter("CSV Radio Log Data Files (*.csv)")
        fileDialog.setDirectory(self.firstWorkingDir)
        if fileDialog.exec_():
            fileName=fileDialog.selectedFiles()[0]
        else: # user pressed cancel on the file browser dialog
            return
... (the rest of the load function processes the selected file)
...


# code for CSVFileSortFilterProxyModel partially taken from
#  https://github.com/ZhuangLab/storm-control/blob/master/steve/qtRegexFileDialog.py
class CSVFileSortFilterProxyModel(QSortFilterProxyModel):
    def __init__(self,parent=None):
#       print("initializing CSVFileSortFilterProxyModel")
        super(CSVFileSortFilterProxyModel,self).__init__(parent)

    # filterAcceptsRow - return True if row should be included in the model, False otherwise
    #
    # do not list files named *_fleetsync.csv or *_clueLog.csv
    #  do a case-insensitive comparison just in case
    def filterAcceptsRow(self,source_row,source_parent):
#       print("CSV filterAcceptsRow called")
        source_model=self.sourceModel()
        index0=source_model.index(source_row,0,source_parent)
        # Always show directories
        if source_model.isDir(index0):
            return True
        # filter files
        filename=source_model.fileName(index0).lower()
#       print("testing lowercased filename:"+filename)
        # never show non- .csv files
        if filename.count(".csv")<1:
            return False
        if filename.count("_fleetsync.csv")+filename.count("_cluelog.csv")==0:
            return True
        else:
            return False