首页 > 解决方案 > 具有代理模型按日期排序的 QFileDialog 实际上使用日期的字母顺序

问题描述

在 PyQt 5.11.2(在 Windows 10 上)中,设置了 DontUseNativeDialog 选项的 QFileDialog 在按“修改日期”列排序时存在错误:它不按实际日期排序 - 它按非零填充 MM 的字母顺序排序-DD-YYYY 字符串,表示 9-12-2018 显示为比 12-12-2018 更新。 在此处输入图像描述 有解决方法或修复方法吗?

本机对话框确实按日期正确排序,但是,使用非本机对话框的动机是本机对话框不尊重 fileDialog.setProxyModel (用于通过更复杂的正则表达式规则过滤掉某些文件),描述herehere,我认为文档中的这一行已详细说明/暗示了这一点:

默认情况下,如果平台有一个平台原生文件对话框,则将使用它。在这种情况下,用于构造对话框的小部件将不会被实例化,因此相关的访问器(例如 layout() 和 itemDelegate() 将返回 null。您可以设置 DontUseNativeDialog 选项以确保将使用基于小部件的实现而不是本机对话框。

代码:通过调用 self.load() 生成对话框(无参数)

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]

...以及只有一个功能的整个 CSVFileSortFilterProxyModel 类:

# 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()
#       filename=self.sourceModel().index(row,0,parent).data().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

标签: pythonpyqtpyqt5qfiledialog

解决方案


问题是由自定义 QSortFilterProxyModel 引起的,因为在 lessThan 方法中,值是字符串,解决方案是转换为适当的类型进行比较:

class CSVFileSortFilterProxyModel(QtCore.QSortFilterProxyModel):
    def filterAcceptsRow(self,source_row,source_parent):
        source_model = self.sourceModel()
        index0=source_model.index(source_row,0,source_parent)
        if source_model.isDir(index0):
            return True
        filename = source_model.fileName(index0).lower()
        if filename.count(".csv")<1:
            return False
        return filename.count("_fleetsync.csv")+filename.count("_cluelog.csv") == 0

    def lessThan(self, left, right):
        source_model = self.sourceModel()

        if left.column() == right.column() == 1: 
            if source_model.isDir(left) and not source_model.isDir(right):
                return True
            return source_model.size(left) < source_model.size(right)

        if left.column() == right.column() == 2:
            return source_model.type(left) < source_model.type(right)

        if left.column() == right.column() == 3:
            return source_model.lastModified(left) < source_model.lastModified(right)
        return super(CSVFileSortFilterProxyModel, self).lessThan(left, right)

正如@ekhumoro所指出的,一个更简单的选择是覆盖代理排序:

class CSVFileSortFilterProxyModel(QtCore.QSortFilterProxyModel):
    def filterAcceptsRow(self,source_row,source_parent):
        source_model = self.sourceModel()
        index0=source_model.index(source_row,0,source_parent)
        if source_model.isDir(index0):
            return True
        filename = source_model.fileName(index0).lower()
        if filename.count(".csv")<1:
            return False
        return filename.count("_fleetsync.csv")+filename.count("_cluelog.csv") == 0

    def sort(self, column, order):
        self.sourceModel().sort(column, order)

推荐阅读