PyQt QFileDialog custom proxy filter not working

2024/10/16 1:22:49

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=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 casedef 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 directoriesif source_model.isDir(index0):return True# filter filesfilename=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 Trueelse: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...?

Answer

Found the solution at another stackoverflow question here.

From that solution:

The main thing to watch out for is to calldialog.setOption(QFileDialog::DontUseNativeDialog) beforedialog.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.

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 dialogreturn
... (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 casedef 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 directoriesif source_model.isDir(index0):return True# filter filesfilename=source_model.fileName(index0).lower()
#       print("testing lowercased filename:"+filename)# never show non- .csv filesif filename.count(".csv")<1:return Falseif filename.count("_fleetsync.csv")+filename.count("_cluelog.csv")==0:return Trueelse:return False
https://en.xdnf.cn/q/117771.html

Related Q&A

If I have Pandas installed correctly, why wont my import statement recognize it?

Im working on a project to play around with a csv file, however, I cant get pandas to work. Everything I have researched so far has just told me to make sure that pandas is installed. Using pip I have …

Python Issues with a Class

I am having issues with my below class. I keep getting the below traceback, butI am not sure were I am going wrong. I am expecting to see a dictionary with photo tags. Any help would be great. Tracebac…

Dynamically populate drop down menu with selection from previous drop down menu

I have a cgi script written in Python. There are two drop down menus and then a submit button. Id like to be able to make a selection from the first menu, and based off that choice, have the second dro…

Web Scrape page with multiple sections

Pretty new to python... and Im trying to my hands at my first project.Been able to replicate few simple demo... but i think there are few extra complexities with what Im trying to do.Im trying to scrap…

Python recv Loop

I am try to display data that is sent over a socket via an iteration from a loop. The way I have it at the moment isnt working on the Admin client. What should I do to fix my loop? Thank youAdmin t…

gtk+ python entry color [closed]

Its difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying thi…

converting a text corpus to a text document with vocabulary_id and respective tfidf score

I have a text corpus with say 5 documents, every document is separated with each other by /n. I want to provide an id to every word in the document and calculate its respective tfidf score. for example…

Numpy append array isnt working

Why isnt it appending all the lists? test = {file1:{subfile1:[1,2,3],subfile2:[10,11,12]},file5:{subfile1:[4,678,6]},file2:{subfile1:[4,78,6]},file3:{subfile1:[7,8,9]}} testarray = np.array([50,60,70]…

Select a valid choice ModelChoiceField

Whenever im running form.is_valid() i get the error: Select a valid choice. That choice is not one of the availablechoices.Here is what I do in my view:timeframes = HostTimeFrame.objects.all() if reque…

Let a module file use a global variable?

Forgive me if this is just a super easy solution as I am pretty new to Python. Right now Im trying to make a basic video game, and to save space I decided to make a module for a combat encounter -- so …