0

How to show hidden row after applying filter in QTableView. I attached the code below and I applied filter for second column for filter value '2'. it is working as required. if want to show hidden row which contain value '3' in second column. it is not showing the row. I used match command to find row. everything working fine. but row not showing. please help me to resolve this.

from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *

class TableModel(QAbstractTableModel):
    def __init__(self, data):super().__init__();self._data = data
    def data(self, index, role):
            if role == Qt.ItemDataRole.DisplayRole or role == Qt.EditRole :return self._data[index.row()][index.column()]
    def rowCount(self, index):return len(self._data)
    def columnCount(self, index):return len(self._data[0])

class tableview(QTableView):
    def __init__(self):
        super().__init__()
        self.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection)
        self.setFocusPolicy(Qt.FocusPolicy.NoFocus)
        self.horizontalHeader().setStyleSheet("::section{Background-color:lightgray;border-radius:10px;}")
        self.smodel = QSortFilterProxyModel()
        self.smodel.setFilterKeyColumn(1)
        self.setModel(self.smodel)
        self.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.ResizeToContents)
        self.smodel.setSourceModel(TableModel([[1,2],[1,2],[1,3],[1,4]]))
        self.smodel.setFilterFixedString('2')
    def find(self,key):
        start = self.smodel.index(0, 1)
        matches = self.smodel.sourceModel().match(start,Qt.DisplayRole,key,hits=-1,flags=Qt.MatchExactly)
        for match in matches:self.showRow(match.row())

app = QApplication([])
table=tableview()
table.show()
b=QPushButton();b.clicked.connect(lambda:table.find('3'))
b.show()
app.exec_()

Current result

Current result

Required result on button press

enter image description here

Viswa
  • 134
  • 1
  • 13
  • 1
    please, don't put code in one line after `:` - it is unreadable. And the same with `;`. Put code in next line. See more [PEP 8 -- Style Guide for Python Code](https://www.python.org/dev/peps/pep-0008/) – furas Nov 13 '21 at 13:16
  • if you want to show only last row then use only `smodel.setFilterFixedString(key)` and if you want to show all rows then clear filter - `smodel.setFilterFixedString("")` And if you want rows with `2` or `3` then `self.smodel.setFilterRegExp("2|3")` – furas Nov 13 '21 at 13:21
  • 1
    `filter` and `showRow()`/`hideRow()` can work in different way - so they may have problem to work together. Filter removes data before sending to `TableView`, `showRow()`/`hideRow()` removes row in `TableView`. If you want to use `showRow` then you may need to clear filter, hide all rows and show rows with `2` and `3` – furas Nov 13 '21 at 13:44
  • @furas thankyou. is it possible to get current filter expression and append new as combined filter as like you told?. example: `x=getcurrentfilterexp(); self.smodel.setFilterRegExp(x+"|3")` – Viswa Nov 13 '21 at 13:51
  • 1
    better keep values on list `self.filtered` and use `"|".join(self.filtered)` - and this way you can simply add or remove from list. See example in my answer. – furas Nov 13 '21 at 14:00

1 Answers1

1

I think filter and showRow()/hideRow() can work in different way - so they may have problem to work together.

Filter removes data before sending to TableView, showRow()/hideRow() removes row directly in TableView. If you want to use showRow then you may need to clear filter, hide all rows and show rows with 2 and 3


But it may be simpler to use filter

To show only rows with selected value (key = "3")

smodel.setFilterFixedString(key)

To clear filter and show all rows

smodel.setFilterFixedString("")

To filter few values you can use regex

self.smodel.setFilterRegExp("2|3")

or you could keep values on list

filtered = ["2", "3"]

self.smodel.setFilterRegExp( "|".join(filtered) )

Minimal working code.

My button toggles row "3" - first click shows row, second click hides row, etc.

from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *

class TableModel(QAbstractTableModel):
    def __init__(self, data):
        super().__init__()
        self._data = data
        
    def data(self, index, role):
        if role == Qt.ItemDataRole.DisplayRole or role == Qt.EditRole :
           return self._data[index.row()][index.column()]
        
    def rowCount(self, index):
        return len(self._data)
    
    def columnCount(self, index):
        return len(self._data[0])

class tableview(QTableView):
    def __init__(self):
        super().__init__()
        self.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection)
        self.setFocusPolicy(Qt.FocusPolicy.NoFocus)

        self.horizontalHeader().setStyleSheet("::section{Background-color:lightgray;border-radius:10px;}")
        self.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.ResizeToContents)

        self.smodel = QSortFilterProxyModel()
        self.setModel(self.smodel)
        self.smodel.setSourceModel(TableModel([[1,2],[1,2],[1,3],[1,4]]))
        self.smodel.setFilterKeyColumn(1)

        self.filtered = ["2"]
        
        #self.smodel.setFilterFixedString("2")
        self.smodel.setFilterRegExp( "|".join(self.filtered) )
        
    def find(self, key):
        print('find:', key)
        
        if key in self.filtered:
            self.filtered.remove(key)
        else:
            self.filtered.append(key)

        #self.smodel.setFilterFixedString("")   # clear filter - show all rows
        #self.smodel.setFilterFixedString(key)  
        #self.smodel.setFilterRegExp("2|3")
        
        self.smodel.setFilterRegExp( "|".join(self.filtered) )
        
# --- main ---

app = QApplication([])

table = tableview()
table.show()

button = QPushButton(text="Toggle: 3")
button.clicked.connect(lambda:table.find('3'))
button.show()

app.exec()

BTW:

I see only one problem: some chars have special meaning in regex so adding ie. dot . to filtered may hide all rows, so it may need use \..

The same problem can be with | ( ) [ ] ^ $, etc.

furas
  • 134,197
  • 12
  • 106
  • 148
  • ok. I think now it is not an issue for me. I hope this method will be useful. and one more clarification. which one is better and faster in QTableWidget and QTableView. – Viswa Nov 13 '21 at 14:26
  • 2
    both use code in C/C++ in library Qt so both should have similar speed. As I remeber `QTableWidget` can be built on top of `QTableView`. `QTableWidget` can be simpler to create something in short time but you have to write all functions to filter data,etc., `QTableView` can be more useful when you use database - you hide all functions in `Model`. - [c++ - QTableWidget vs QTableView - Stack Overflow](https://stackoverflow.com/questions/15290932/qtablewidget-vs-qtableview) – furas Nov 13 '21 at 21:48