如何在 QTableView 中应用过滤器后显示特定行

Posted

技术标签:

【中文标题】如何在 QTableView 中应用过滤器后显示特定行【英文标题】:How to show specific row after apply filter in QTableView 【发布时间】:2021-11-13 11:22:58 【问题描述】:

如何在 QTableView 中应用过滤器后显示隐藏行。我附上了下面的代码,并为过滤器值“2”的第二列应用了过滤器。它按要求工作。如果想在第二列中显示包含值“3”的隐藏行。它没有显示该行。我使用 match 命令来查找行。一切正常。但行没有显示。请帮我解决这个问题。

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("::sectionBackground-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_()

当前结果

按钮按下所需的结果

【问题讨论】:

请不要将代码放在: 之后的一行中 - 它不可读。与; 相同。将代码放在下一行。查看更多PEP 8 -- Style Guide for Python Code 如果你想只显示最后一行然后只使用smodel.setFilterFixedString(key) 如果你想显示所有行然后清除过滤器-smodel.setFilterFixedString("") 如果你想要带有23 的行然后self.smodel.setFilterRegExp("2|3") filtershowRow()/hideRow() 可以以不同的方式工作 - 所以他们可能无法一起工作。过滤器在发送到 TableView 之前删除数据,showRow()/hideRow() 删除 TableView 中的行。如果您想使用showRow,那么您可能需要清除过滤器、隐藏所有行并显示带有23 的行 @furas 谢谢。是否可以像您所说的那样获取当前的过滤器表达式并将新的过滤器附加为组合过滤器?例如:x=getcurrentfilterexp(); self.smodel.setFilterRegExp(x+"|3") 最好将值保留在列表self.filtered 并使用"|".join(self.filtered) - 这样您就可以简单地从列表中添加或删除。请参阅我的答案中的示例。 【参考方案1】:

我认为 filtershowRow()/hideRow() 可以以不同的方式工作 - 所以他们一起工作可能会有问题。

Filter 在发送到TableView 之前删除数据,showRow()/hideRow() 直接删除TableView 中的行。如果您想使用showRow,那么您可能需要清除filter,隐藏所有行并显示带有23 的行


但使用过滤器可能更简单

仅显示具有选定值的行 (key = "3")

smodel.setFilterFixedString(key)

清除过滤器并显示所有行

smodel.setFilterFixedString("")

要过滤少量值,您可以使用regex

self.smodel.setFilterRegExp("2|3")

或者您可以将值保留在列表中

filtered = ["2", "3"]

self.smodel.setFilterRegExp( "|".join(filtered) )

最少的工作代码。

我的按钮切换行"3" - 第一次单击显示行,第二次单击隐藏行,等等。

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("::sectionBackground-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()

顺便说一句:

我只看到一个问题:regex 中的某些字符具有特殊含义,因此添加 ie。点.filtered 可能会隐藏所有行,因此可能需要使用\.

| ( ) [ ] ^ $等也可能出现同样的问题。

【讨论】:

好的。我认为现在这对我来说不是问题。我希望这个方法会有用。和一个进一步的澄清。 QTableWidget和QTableView哪个更好更快。 两者都在 Qt 库中使用 C/C++ 中的代码,因此两者的速度应该相似。我记得QTableWidget 可以建立在QTableView 之上。 QTableWidget 可以更简单地在短时间内创建一些东西,但你必须编写所有函数来过滤数据等,QTableView 在使用数据库时会更有用 - 你隐藏了 Model 中的所有函数。 - c++ - QTableWidget vs QTableView - Stack Overflow

以上是关于如何在 QTableView 中应用过滤器后显示特定行的主要内容,如果未能解决你的问题,请参考以下文章

如何在 QTableView 的列中显示下拉列表并根据下拉列表进行过滤

使用 QSortFilterProxyModel 过滤 QTableView 后保留选择

在大量插入后向 QTableView 添加行会减慢应用程序的速度

如何在 QStatusBar 中显示 QAbstractTableModel 的状态?

QT使用QSORTFILTERMODEL关联QTableView,排序后序号不是1、2、3***,而是打乱的序号,怎么使得序号还是1、2

如何通过在 PyQt5 中按 Enter 键从 QTableView 获取数据