1
votes

I am having issues trying to get my filter working for my QTableView; currently it only works for the first column, however I am trying to filter the first two columns using a QLineEdit. It should match either the first or second column.

I am working on making a minimal example, but was just seeing if anyone can see if i'm just making simple mistakes in my code.

Changing 'i' in the for loop to a single column (0 or 1) works, but doesn't work as expected because it just filters that specific column.

class SortFilterProxyModel(QtCore.QSortFilterProxyModel):
    def __init__(self, *args, **kwargs):
        QtCore.QSortFilterProxyModel.__init__(self, *args, **kwargs)
        self.filters = {}

    def setFilterByColumn(self, regex, column):
        self.filters[column] = regex
        self.invalidateFilter()

    def filterAcceptsRow(self, source_row, source_parent):
        for key, regex in self.filters.items():
            ix = self.sourceModel().index(source_row, key, source_parent)
            if ix.isValid():
                text = self.sourceModel().data(ix)
                if regex.indexIn(text) == -1:
                    return False
        return True

class Database(QtWidgets.QMainWindow, Ui_databaseWindow):
    def __init__(self,parent=None):
        super().__init__()
        self.setupUi(self)
        self.mainTableView.clicked.connect(self.tableInfo)
        self.radioGroup = QtWidgets.QButtonGroup()
        self.radioGroup.addButton(self.frameView) # below are radio buttons
        self.radioGroup.addButton(self.cylView)
        self.radioGroup.addButton(self.driversView)
        self.radioGroup.addButton(self.valView)
        self.radioGroup.addButton(self.fixedView)
        self.radioGroup.addButton(self.vvcpView)
        self.frameView.setChecked(True)
        self.db = QtSql.QSqlDatabase.addDatabase("QSQLITE")
        self.db.setDatabaseName("C:\\Workspace\\Database\\data.db")
        self.db.open()

        self.projectModel = QtSql.QSqlQueryModel()
        self.proxyModel = SortFilterProxyModel(self)
        self.proxyModel.setSourceModel(self.projectModel)
        self.radioGroup.buttonClicked.connect(self.checkState)
        self.projectModel.setQuery("select * from tblBasic_Frame",self.db)
        self.mainTableView.setModel(self.proxyModel)
        self.mainTableView.setSortingEnabled(True)
        self.sortBox.textChanged.connect(self.onTextChanged) #QLineEdit

    @QtCore.pyqtSlot(str)
    def onTextChanged(self, text):
        if self.valveView.isChecked():
            for i in range(0,2):
                self.proxyModel.setFilterByColumn(QtCore.QRegExp(text, QtCore.Qt.CaseInsensitive),i)
        else:
            self.proxyModel.setFilterByColumn(QtCore.QRegExp(text, QtCore.Qt.CaseInsensitive),0)
1
Your filter should show the row if there is a match in both columns or just just match at least one of the columnseyllanesc
@eyllanesc It should show match for at least one of the columnsdree

1 Answers

0
votes

Your code has the following errors:

  • If the text in the first column does not match the text then you return False indicating that the row is not displayed without considering that there may be a match with the second column.

  • Let's say you have filtered the 2 columns and change the state of valveView, this will only update the regex of the first column so it will still filter the second column with the previous regex.

  • If there is no text in the QLineEdit then you must clean the filters.

  • You must also update the filter status when the valveView status is changed.

class SortFilterProxyModel(QtCore.QSortFilterProxyModel):
    def __init__(self, *args, **kwargs):
        QtCore.QSortFilterProxyModel.__init__(self, *args, **kwargs)
        self.filters = {}

    def setFilterByColumn(self, regex, column):
        self.filters[column] = regex
        self.invalidateFilter()

    def clear_filter(self):
        self.filters = {}
        self.invalidateFilter()

    def filterAcceptsRow(self, source_row, source_parent):
        values = []
        if self.filters:
            for key, regex in self.filters.items():
                text = self.sourceModel().index(source_row, key, source_parent).data()
                values.append(regex.indexIn(text) != -1)
            return any(values)
        return True

class Database(QtWidgets.QMainWindow, Ui_databaseWindow):
    def __init__(self,parent=None):
        super().__init__()
        self.setupUi(self)
        self.mainTableView.clicked.connect(self.tableInfo)
        self.radioGroup = QtWidgets.QButtonGroup()
        self.radioGroup.addButton(self.frameView) # below are radio buttons
        self.radioGroup.addButton(self.cylView)
        self.radioGroup.addButton(self.driversView)
        self.radioGroup.addButton(self.valView)
        self.radioGroup.addButton(self.fixedView)
        self.radioGroup.addButton(self.vvcpView)
        self.frameView.setChecked(True)
        self.db = QtSql.QSqlDatabase.addDatabase("QSQLITE")
        self.db.setDatabaseName("C:\\Workspace\\Database\\data.db")
        self.db.open()

        self.projectModel = QtSql.QSqlQueryModel()
        self.proxyModel = SortFilterProxyModel(self)
        self.proxyModel.setSourceModel(self.projectModel)
        self.radioGroup.buttonClicked.connect(self.checkState)
        self.projectModel.setQuery("select * from tblBasic_Frame",self.db)
        self.mainTableView.setModel(self.proxyModel)
        self.mainTableView.setSortingEnabled(True)
        self.sortBox.textChanged.connect(self.update_filter) #QLineEdit
        self.valveView.toggled.connect(self.update_filter)

    @QtCore.pyqtSlot()
    def update_filter(self):
        text = self.sortBox.text()
        self.proxyModel.clear_filter()
        if text:
            if self.valveView.isChecked():
                for i in range(2):
                    self.proxyModel.setFilterByColumn(
                        QtCore.QRegExp(text, QtCore.Qt.CaseInsensitive), i
                    )
            else:
                self.proxyModel.setFilterByColumn(
                    QtCore.QRegExp(text, QtCore.Qt.CaseInsensitive), 0
                )