Viswa
Viswa

Reputation: 174

How to show specific row after apply filter in QTableView

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

Upvotes: 1

Views: 1022

Answers (1)

furas
furas

Reputation: 142641

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.

Upvotes: 2

Related Questions