How can I implement a simple filterable List in PyQt5/PySide2?
Test code:
import sys
from PySide2.QtCore import QAbstractListModel
from PySide2.QtGui import Qt
from PySide2.QtWidgets import QApplication, QWidget, QVBoxLayout, QLineEdit, QListView
class MyModel(QAbstractListModel):
def __init__(self):
QAbstractListModel.__init__(self)
self.test_data = ['Test','abc', 'Test2', 'aaa', 'bbb']
self.filtered_data = self.test_data
self.filter = ''
self.refresh()
def refresh(self):
if self.filter:
self.filtered_data = [x for x in self.test_data if self.filter in x]
else:
self.filtered_data = self.test_data
def data(self, index, role):
if role == Qt.DisplayRole:
return self.filtered_data[index.row()]
def rowCount(self, index):
return len(self.filtered_data)
def text_changed():
model.filter = le.text()
model.refresh()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = QWidget()
le = QLineEdit()
le.textChanged.connect(text_changed)
model = MyModel()
lv = QListView(model=model)
layout = QVBoxLayout()
layout.addWidget(le)
layout.addWidget(lv)
window.setLayout(layout)
window.show()
app.exec_()
The Filter itself works, but the ListView is not refreshed properly. When I change the filter, the list is not updated, until I move with the mouse to a entry.
That you change the information of an internal list does not notify in sight that something has changed, for each type of change certain methods must be invoked before or after the change.
In this case, beginResetModel and endResetModel are enough
def refresh(self):
self.beginResetModel()
if self.filter:
self.filtered_data = [x for x in self.test_data if self.filter in x]
else:
self.filtered_data = self.test_data
self.endResetModel()
Instead another more elegant solution is to use a QSortFilterProxyModel:
class MyModel(QAbstractListModel):
def __init__(self):
QAbstractListModel.__init__(self)
self.test_data = ['Test','abc', 'Test2', 'aaa', 'bbb']
self.filtered_data = self.test_data
def data(self, index, role):
if role == Qt.DisplayRole:
return self.filtered_data[index.row()]
def rowCount(self, index):
return len(self.filtered_data)
def text_changed():
proxy.filter = le.text()
class SortFilterProxyModel(QSortFilterProxyModel):
def __init__(self, parent=None):
super().__init__(parent)
self._filter = ""
def filterAcceptsRow(self, sourceRow, sourceParent):
index = self.sourceModel().index(sourceRow, 0, sourceParent)
if self.filter:
return self.filter in index.data()
return True
@property
def filter(self):
return self._filter
@filter.setter
def filter(self, f):
self._filter = f
self.invalidateFilter()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = QWidget()
le = QLineEdit()
le.textChanged.connect(text_changed)
model = MyModel()
proxy = SortFilterProxyModel()
proxy.setSourceModel(model)
lv = QListView(model=proxy)
layout = QVBoxLayout()
layout.addWidget(le)
layout.addWidget(lv)
window.setLayout(layout)
window.show()
app.exec_()
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.