Skip to content

Instantly share code, notes, and snippets.

@dbridges
Last active December 1, 2022 22:11
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save dbridges/4732790 to your computer and use it in GitHub Desktop.
Save dbridges/4732790 to your computer and use it in GitHub Desktop.
A subclass of QSortFilterProxyModel that implements custom filtering, especially useful for multicolumn filtering.
from PySide import QtGui
class CustomSortFilterProxyModel(QtGui.QSortFilterProxyModel):
"""
Implements a QSortFilterProxyModel that allows for custom
filtering. Add new filter functions using addFilterFunction().
New functions should accept two arguments, the column to be
filtered and the currently set filter string, and should
return True to accept the row, False otherwise.
Filter functions are stored in a dictionary for easy
removal by key. Use the addFilterFunction() and
removeFilterFunction() methods for access.
The filterString is used as the main pattern matching
string for filter functions. This could easily be expanded
to handle regular expressions if needed.
"""
def __init__(self, parent=None):
super(CustomSortFilterProxyModel, self).__init__(parent)
self.filterString = ''
self.filterFunctions = {}
def setFilterString(self, text):
"""
text : string
The string to be used for pattern matching.
"""
self.filterString = text.lower()
self.invalidateFilter()
def addFilterFunction(self, name, new_func):
"""
name : hashable object
The object to be used as the key for
this filter function. Use this object
to remove the filter function in the future.
Typically this is a self descriptive string.
new_func : function
A new function which must take two arguments,
the row to be tested and the ProxyModel's current
filterString. The function should return True if
the filter accepts the row, False otherwise.
ex:
model.addFilterFunction(
'test_columns_1_and_2',
lambda r,s: (s in r[1] and s in r[2]))
"""
self.filterFunctions[name] = new_func
self.invalidateFilter()
def removeFilterFunction(self, name):
"""
name : hashable object
Removes the filter function associated with name,
if it exists.
"""
if name in self.filterFunctions.keys():
del self.filterFunctions[name]
self.invalidateFilter()
def filterAcceptsRow(self, row_num, parent):
"""
Reimplemented from base class to allow the use
of custom filtering.
"""
model = self.sourceModel()
# The source model should have a method called row()
# which returns the table row as a python list.
tests = [func(model.row(row_num), self.filterString)
for func in self.filterFunctions.values()]
return not False in tests
@nikitagashkov
Copy link

nikitagashkov commented Sep 12, 2016

Hi, dbridges!

Could you provide interface example of multicolumn filtering? Will it be something like this: model.setFilterKeyColumn([0, 1, 2])

@LoicGRENON
Copy link

LoicGRENON commented Nov 19, 2017

@nickgashkov: As wrote on docstrings, you need to use addFilterFunction() and removeFilterFunction() methods for access.
See the exemple in the addFilterFunction method docstring.

@dbridges: To complies with PEP8, the line 75 should be "return False not in tests" but "return all(tests)" may be better ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment