繁体   English   中英

如何在 PyQt5/PySide2 中实现可过滤列表?

[英]How to implement a filterable List in PyQt5/PySide2?

如何在 PyQt5/PySide2 中实现一个简单的可过滤列表?

测试代码:

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_()


Filter 本身可以工作,但 ListView 没有正确刷新。 当我更改过滤器时,列表不会更新,直到我用鼠标移动到一个条目。

您更改内部列表的信息并不会立即通知某些更改,对于每种类型的更改,必须在更改之前或之后调用某些方法。

在这种情况下, beginResetModel 和 endResetModel 就足够了

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()

相反,另一个更优雅的解决方案是使用 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_()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM