PyQt QFileDialog 自定义代理过滤器不起作用 [英] PyQt QFileDialog custom proxy filter not working

查看:73
本文介绍了PyQt QFileDialog 自定义代理过滤器不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个工作代码会弹出一个 QFileDialog 提示用户选择一个 .csv 文件:

This working code brings up a QFileDialog prompting the user to select a .csv file:

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() 函数只能处理其中的三分之一.

Now, I'd like to change that filter to be more selective. The program saves each project as a set of three .csv files (project.csv, project_fleetsync.csv, project_clueLog.csv) but I only want the file dialog to display the first one (project.csv) in order to avoid presenting the user with too many choices when only a third of them can be handled by the rest of the load() function.

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

According to this post, it looks like the solution is to use a proxy model. So, I changed the code to the following (all of the commented lines in load() are things I've tried in various combinations):

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文件仍列在对话框中.显然我做错了什么......?

When I call the load() function, I do get the "initializing CSVFileSortFilterProxyModel" output, but apparently filterAcceptsRow is not getting called: there is no "CSV filterAcceptsRow called" output, and, the _fleetsync.csv and _clueLog.csv files are still listed in the dialog. Clearly I'm doing something wrong...?

推荐答案

在另一个 stackoverflow 问题此处中找到了解决方案.

Found the solution at another stackoverflow question here.

来自该解决方案:

要注意的主要事情是打电话dialog.setOption(QFileDialog::DontUseNativeDialog) 之前dialog.setProxyModel.

The main thing to watch out for is to call dialog.setOption(QFileDialog::DontUseNativeDialog) before dialog.setProxyModel.

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

Also it looks like you then have to use fileDialog.exec_() rather than fileDialog.getOpenFileName. The value you set to setNameFilter does show up in the filter cyclic field of the non-native dialog, but is effectively just for decoration since the proxymodel filter overrides it. In my opinion that is a good thing since you can put wording in the filter cyclic that would indicate something useful to the user as to what type of filtering is going on.

感谢用户 Frank 和 ariwez.

Thanks to users Frank and ariwez.

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

UPDATE: to clarify, here's the full final code I'm using:

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

这篇关于PyQt QFileDialog 自定义代理过滤器不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆