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]

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.

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.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")

    # 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")
        # Always show directories
        if source_model.isDir(index0):
            return True
        # filter files
#       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
            return False

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...?

  • I did something similar to this but I used filter="csv (project.csv)") instead of filter="csv (*.csv)")[0]. It's not as nice as having just *.csv in the file type widget but it was good enough for my use-case as it only listed that one file. – Joseph Apr 13 '17 at 14:26
  • I should have specified that the project name is arbitrary, i.e. <project>.csv and <project>_fleetsync.csv and <project>_clueLog.csv. Can the standard filter syntax handle that? – Tom Grundy Apr 13 '17 at 15:37

Found the solution at another stackoverflow question here.

From that solution:

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

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.

Thanks to users Frank and ariwez.

| improve this answer | |
  • Glad you found an answer :) – Joseph Apr 18 '17 at 9:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.