在 QTableView 中使用 QSortFilterProxyModel 对两行进行排序

Posted

技术标签:

【中文标题】在 QTableView 中使用 QSortFilterProxyModel 对两行进行排序【英文标题】:Sorting two rows using QSortFilterProxyModel in QTableView 【发布时间】:2019-08-29 18:55:48 【问题描述】:

我在尝试让我的过滤器为我的 QTableView 工作时遇到问题;目前它只适用于第一列,但是我正在尝试使用 QLineEdit 过滤前两列。它应该匹配第一列或第二列。

我正在制作一个最小的示例,但只是想看看是否有人能看到我是否只是在我的代码中犯了简单的错误。

将 for 循环中的“i”更改为单个列(0 或 1)可以工作,但不能按预期工作,因为它只是过滤该特定列。

class SortFilterProxyModel(QtCore.QSortFilterProxyModel):
    def __init__(self, *args, **kwargs):
        QtCore.QSortFilterProxyModel.__init__(self, *args, **kwargs)
        self.filters = 

    def setFilterByColumn(self, regex, column):
        self.filters[column] = regex
        self.invalidateFilter()

    def filterAcceptsRow(self, source_row, source_parent):
        for key, regex in self.filters.items():
            ix = self.sourceModel().index(source_row, key, source_parent)
            if ix.isValid():
                text = self.sourceModel().data(ix)
                if regex.indexIn(text) == -1:
                    return False
        return True

class Database(QtWidgets.QMainWindow, Ui_databaseWindow):
    def __init__(self,parent=None):
        super().__init__()
        self.setupUi(self)
        self.mainTableView.clicked.connect(self.tableInfo)
        self.radioGroup = QtWidgets.QButtonGroup()
        self.radioGroup.addButton(self.frameView) # below are radio buttons
        self.radioGroup.addButton(self.cylView)
        self.radioGroup.addButton(self.driversView)
        self.radioGroup.addButton(self.valView)
        self.radioGroup.addButton(self.fixedView)
        self.radioGroup.addButton(self.vvcpView)
        self.frameView.setChecked(True)
        self.db = QtSql.QSqlDatabase.addDatabase("QSQLITE")
        self.db.setDatabaseName("C:\\Workspace\\Database\\data.db")
        self.db.open()

        self.projectModel = QtSql.QSqlQueryModel()
        self.proxyModel = SortFilterProxyModel(self)
        self.proxyModel.setSourceModel(self.projectModel)
        self.radioGroup.buttonClicked.connect(self.checkState)
        self.projectModel.setQuery("select * from tblBasic_Frame",self.db)
        self.mainTableView.setModel(self.proxyModel)
        self.mainTableView.setSortingEnabled(True)
        self.sortBox.textChanged.connect(self.onTextChanged) #QLineEdit

    @QtCore.pyqtSlot(str)
    def onTextChanged(self, text):
        if self.valveView.isChecked():
            for i in range(0,2):
                self.proxyModel.setFilterByColumn(QtCore.QRegExp(text, QtCore.Qt.CaseInsensitive),i)
        else:
            self.proxyModel.setFilterByColumn(QtCore.QRegExp(text, QtCore.Qt.CaseInsensitive),0)

【问题讨论】:

如果两列都匹配或只匹配至少一列,您的过滤器应该显示该行 @eyllanesc 它应该显示匹配至少一列 【参考方案1】:

您的代码有以下错误:

如果第一列中的文本与文本不匹配,则返回 False,表示不显示该行,而不考虑可能与第二列匹配。

假设您已经过滤了 2 列并更改了 ValveView 的状态,这只会更新第一列的正则表达式,因此它仍会使用之前的正则表达式过滤第二列。

李>

如果 QLineEdit 中没有文本,则必须清理过滤器。

您还必须在 ValveView 状态更改时更新过滤器状态。

class SortFilterProxyModel(QtCore.QSortFilterProxyModel):
    def __init__(self, *args, **kwargs):
        QtCore.QSortFilterProxyModel.__init__(self, *args, **kwargs)
        self.filters = 

    def setFilterByColumn(self, regex, column):
        self.filters[column] = regex
        self.invalidateFilter()

    def clear_filter(self):
        self.filters = 
        self.invalidateFilter()

    def filterAcceptsRow(self, source_row, source_parent):
        values = []
        if self.filters:
            for key, regex in self.filters.items():
                text = self.sourceModel().index(source_row, key, source_parent).data()
                values.append(regex.indexIn(text) != -1)
            return any(values)
        return True

class Database(QtWidgets.QMainWindow, Ui_databaseWindow):
    def __init__(self,parent=None):
        super().__init__()
        self.setupUi(self)
        self.mainTableView.clicked.connect(self.tableInfo)
        self.radioGroup = QtWidgets.QButtonGroup()
        self.radioGroup.addButton(self.frameView) # below are radio buttons
        self.radioGroup.addButton(self.cylView)
        self.radioGroup.addButton(self.driversView)
        self.radioGroup.addButton(self.valView)
        self.radioGroup.addButton(self.fixedView)
        self.radioGroup.addButton(self.vvcpView)
        self.frameView.setChecked(True)
        self.db = QtSql.QSqlDatabase.addDatabase("QSQLITE")
        self.db.setDatabaseName("C:\\Workspace\\Database\\data.db")
        self.db.open()

        self.projectModel = QtSql.QSqlQueryModel()
        self.proxyModel = SortFilterProxyModel(self)
        self.proxyModel.setSourceModel(self.projectModel)
        self.radioGroup.buttonClicked.connect(self.checkState)
        self.projectModel.setQuery("select * from tblBasic_Frame",self.db)
        self.mainTableView.setModel(self.proxyModel)
        self.mainTableView.setSortingEnabled(True)
        self.sortBox.textChanged.connect(self.update_filter) #QLineEdit
        self.valveView.toggled.connect(self.update_filter)

    @QtCore.pyqtSlot()
    def update_filter(self):
        text = self.sortBox.text()
        self.proxyModel.clear_filter()
        if text:
            if self.valveView.isChecked():
                for i in range(2):
                    self.proxyModel.setFilterByColumn(
                        QtCore.QRegExp(text, QtCore.Qt.CaseInsensitive), i
                    )
            else:
                self.proxyModel.setFilterByColumn(
                    QtCore.QRegExp(text, QtCore.Qt.CaseInsensitive), 0
                )

【讨论】:

谢谢。如果 .db 文件的值是整数而不是文本,那么对数据进行排序的最佳方法是什么?据我了解,QSortFilterProxyModel 默认过滤文本。 @dree 在你的逻辑中,过滤部分是regex.indexIng(text)! = -1,所以你只需要根据你的逻辑调整它

以上是关于在 QTableView 中使用 QSortFilterProxyModel 对两行进行排序的主要内容,如果未能解决你的问题,请参考以下文章

从 QAbstractTableModel 类中访问视图和代理模型?

如何使用 selectionModel 在 QTableView 中选择多行

编辑单元格时如何在 QTableView 中使用 Enter 键导航

如何使用 beginMoveRows 在 QTableView (QAbstractTableModel) 中移动一行?

使用 QSortFilterProxyModel 过滤 QTableView 后保留选择

如何在 Qt 中使用 QFileSystemModel 设置文本颜色 QTableView?