0

I am using QSqlTableModel, (FilterProxyModel) as custom proxy modelwith QtCore.QSortFilterProxyModel, QTableView,Qcombobox.

self.lineEdit       = QtWidgets.QLineEdit(self.centralwidget)
self.view           = QtWidgets.QTableView(self.centralwidget)
self.comboBox       = QtWidgets.QComboBox(self.centralwidget)

Below code is the custom filter class to get menu of Columns from tableview :

class FilterProxyModel(QtCore.QSortFilterProxyModel):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._filter_value = None

    @property
    def filter_value(self):
        return self._filter_value

    @filter_value.setter
    def filter_value(self, value):
        self._filter_value = value
        self.invalidateFilter()

    def filterAcceptsRow(self, sourceRow, sourceParent):
        if self.filter_value is None:
            return True
        value = (
            self.sourceModel()
            .index(sourceRow, self.filterKeyColumn(), sourceParent)
            .data(self.filterRole())
        )
        return value == self.filter_value

Below is the database model:

    db = QSqlDatabase.addDatabase("QSQLITE")
    db.setDatabaseName("model.db")
    db.open()

    self.model = QSqlTableModel(self)
    self.model.setTable("sheet")
    self.model.select()
    self.view.setModel(self.model)

    self.proxy = FilterProxyModel(self)###
    self.proxy.setSourceModel(self.model)

    self.view.setModel(self.proxy)

Below is the details of my question

    column_names = (["All","Name", "Age", "Adress"])
    self.comboBox.addItems([x for x in column_names])


@QtCore.pyqtSlot(str)
def msa_lineEdit_textChanged(self, text):
    self.proxy = QtCore.QSortFilterProxyModel(self)
    self.proxy.setSourceModel(self.model)
    self.view.setModel(self.proxy)
    search = QtCore.QRegExp(    text,
                                QtCore.Qt.CaseInsensitive,
                                QtCore.QRegExp.RegExp
                                )

    self.proxy.setFilterRegExp(search)

for example : I tryied with above function with QtCore.QRegExp.RegExp its showing the data in first column, selected "all" in Qcombobox.

I added items "All","Name", "Age", and "Adress" in the combobox, and I am trying to search or filter data from QlineEdit with using of QcomboBox as if I select "All" in cobobox and when I am typing words in QlineEdit that should be filter data from all columns.

If I select "Name" or "Age", or "Adress" on QcomboBox that should be filter data as per the column name selection in the Qcombobox. My database have String and as well as Int Values. Are there any examples available for this?

enter image description here

halfer
  • 19,824
  • 17
  • 99
  • 186
user3030327
  • 411
  • 1
  • 7
  • 19

1 Answers1

1

You have to use the filterKeyColumn properly:

This property holds the column where the key used to filter the contents of the source model is read from.

The default value is 0. If the value is -1, the keys will be read from all columns.

So you can connect both the textChanged signal of the line edit and currentIndexChanged of the combo to the function, then set the filter accordingly:

def msa_lineEdit_textChanged(self):
    search = QtCore.QRegExp(self.lineEdit.text(), 
        QtCore.Qt.CaseInsensitive, QtCore.QRegExp.RegExp)
    self.proxy.setFilterKeyColumn(self.combo.currentIndex() - 1)
    self.proxy.setFilterRegExp(search)

Note that your custom proxy won't work as expected if you're using setFilterRegExp and that's because you have overridden the filterAcceptsRow method.

You should change the implementation like this:

    def filterAcceptsRow(self, sourceRow, sourceParent):
        if self.filter_value is None:
            return super().filterAcceptsRow(sourceRow, sourceParent)
        if self.filterKeyColumn() >= 0:
            value = (
                self.sourceModel()
                .index(sourceRow, self.filterKeyColumn(), sourceParent)
                .data(self.filterRole())
            )
            return value == self.filter_value
        for column in range(self.columnCount()):
            value = (
                self.sourceModel()
                .index(sourceRow, column, sourceParent)
                .data(self.filterRole())
            )
            if value == self.filter_value:
                return True
        return False

You should also clear the property whenever the regex filter is applied:

    def setFilterRegExp(self, filter):
        self.filter_value = None
        super().setFilterRegExp(filter)
musicamante
  • 41,230
  • 6
  • 33
  • 58
  • I added your answer and used "self.lineEdit.textChanged.connect(self.msa_lineEdit_textChanged)". It is not responding when i am typing on Qlineedit. – user3030327 Aug 07 '20 at 13:54
  • Is custom filter "class FilterProxyModel(QtCore.QSortFilterProxyModel):" effects "self.proxy.setFilterRegExp(search)" ? I do not know. – user3030327 Aug 07 '20 at 13:59
  • @musicamante.As per your Note new instance of the proxy should not to be made every time. so how to call original "QSortFilterProxyModel" into "def msa_lineEdit_textChanged(self):" function. Along with custom FilterProxyModel which is used above. – user3030327 Aug 08 '20 at 04:07
  • I don't understand what you're asking. And I don't know why it doesn't work for you, but if you're still using the pyqtSlot decorator, remove it: as you can see, I didn't use it, and slot decorators are rarely a requirement for signal/slot connections. – musicamante Aug 08 '20 at 06:30
  • @musicamante.I removed pyqtSlot decorator still not working. And What i want to say: I am using customized filter as "self.proxy = FilterProxyModel" that you can find in the top of my question, that was used to create QMenu. – user3030327 Aug 08 '20 at 06:43
  • @musicamante.Actually if i make a new instance of the proxy to "msa_lineEdit_textChanged" function as "self.proxy = QtCore.QSortFilterProxyModel(self)" that your code is working. But you said that don't make new instance of the proxy each time. – user3030327 Aug 08 '20 at 06:48
  • *What* is not working? Be more specific! Is the `msa_lineEdit_textChanged` function called? If not, check the connection and the output of the program in the shell/prompt to look for more debugging info. Is it called? Then, first of all ensure that it works for a specific column, if that's so, you have to implement the filterAcceptsRow correctly, so that it checks for *all* columns if the setFilterKeyColumn is -1, otherwise you'll obviously get invalid indexes. – musicamante Aug 08 '20 at 06:52
  • From the shell there is no error and at the same time the function is idle. If you want my full code i can share with you. – user3030327 Aug 08 '20 at 06:57
  • @musicamante.I have a doubt that is : Is custom filter prevent parent instance or properties? Why i am asking this because "self.proxy = FilterProxyModel" was customized. And " self.proxy.setFilterKeyColumn(self.combo.currentIndex() - 1)", " self.proxy.setFilterRegExp(search) " are not responding. – user3030327 Aug 08 '20 at 10:17
  • 1
    If you call `setFilterRegExp` on your custom model and `filter_value` is not set, the result is that there will be no filtering at all (as the implementation of `filterAcceptsRow` returns `True` in that case). See the update. – musicamante Aug 09 '20 at 12:41
  • (you should probably remove the new question you just posted, as the update should solve the issue) – musicamante Aug 09 '20 at 12:42
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/219493/discussion-between-user3030327-and-musicamante). – user3030327 Aug 09 '20 at 13:31