I found a similar question on this. Keep the selection after filtering a QTableView with a QSortFilterProxyModel But it is about C++ QT, I tried myself many times, but I still did not pull it off in PyQt5 or PySide6?
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLineEdit, QTableView, QHeaderView, QVBoxLayout
from PyQt5.QtCore import Qt, QSortFilterProxyModel
from PyQt5.QtGui import QStandardItemModel, QStandardItem
class AppDemo(QWidget):
def __init__(self):
super().__init__()
self.resize(1200, 1000)
mainLayout = QVBoxLayout()
# companies = ('Apple', 'Facebook', 'Google', 'Amazon', 'Walmart', 'Dropbox', 'Starbucks', 'eBay', 'Canon')
companies = [f'company_{i}' for i in range(200)]
model = QStandardItemModel(len(companies), 1)
model.setHorizontalHeaderLabels(['Company'])
for row, company in enumerate(companies):
item = QStandardItem(company)
model.setItem(row, 0, item)
filter_proxy_model = QSortFilterProxyModel()
filter_proxy_model.setSourceModel(model)
filter_proxy_model.setFilterCaseSensitivity(Qt.CaseInsensitive)
filter_proxy_model.setFilterKeyColumn(0)
search_field = QLineEdit()
search_field.textChanged.connect(filter_proxy_model.setFilterRegExp)
mainLayout.addWidget(search_field)
table = QTableView()
table.setStyleSheet('font-size: 35px;')
table.verticalHeader().setSectionResizeMode(QHeaderView.Stretch)
table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
table.setModel(filter_proxy_model)
mainLayout.addWidget(table)
self.setLayout(mainLayout)
app = QApplication(sys.argv)
demo = AppDemo()
demo.show()
sys.exit(app.exec_())
I found a solution myself. I switched to use a QListWidget instead. But the same logic also can be applied to QListView. Below is the code.
Below is the core part, it is a slot that is connected to a line edit. Doing this way, the efficiency is good especially when you have many items as it doesn' use QListWidget.clear() when lineedit input changes, it just hide the items behind the curtain.
# deal with search file
def onFileTextChanged(self, text):
search_items = self.listWidget.findItems(text, Qt.MatchContains)
for index in range(self.listWidget.count()):
item = self.listWidget.item(index)
if item in search_items:
item.setHidden(False)
else:
item.setHidden(True)