QTableview 从过滤模型中选择项目

Posted

技术标签:

【中文标题】QTableview 从过滤模型中选择项目【英文标题】:QTableview Select Item from filtered model 【发布时间】:2018-08-09 14:56:41 【问题描述】:

我有一个使用 QStandardItemModel 的 QTableView。如何在应用/不应用搜索的情况下选择表中的特定行。

例如,我在搜索栏中键入“y”以过滤列表以仅显示包含字母“y”的行。当我单击“选择 Emily”按钮时,考虑到用户可以更改排序顺序,我如何让它在 tableview 中选择正确的行?

import sys
from PySide import QtCore, QtGui


class Example(QtGui.QWidget):

    def __init__(self, *args, **kwargs):
        super(Example, self).__init__(*args, **kwargs)
        self.resize(400,400)

        # controls
        model = QtGui.QStandardItemModel(5, 3)
        model.setHorizontalHeaderLabels(['NAME', 'AGE', 'CAREER'])

        people = [
            'name': 'Kevin', 'age': 5, 'career': 'athlete',
            'name': 'Maggie', 'age': 13, 'career': 'banker',
            'name': 'Leslie', 'age': 32, 'career': 'banker',
            'name': 'Abby', 'age': 32, 'career': 'marketing',
            'name': 'Emily', 'age': 45, 'career': 'athlete',
            'name': 'David', 'age': 27, 'career': 'banker',
            'name': 'Johnny', 'age': 27, 'career': 'soccer',
            'name': 'Marie', 'age': 63, 'career': 'secretary'
        ]
        for row, obj in enumerate(people):
            item = QtGui.QStandardItem(obj['name'])
            model.setItem(row, 0, item)

            item = QtGui.QStandardItem(str(obj['age']))
            model.setItem(row, 1, item)

            item = QtGui.QStandardItem(obj['career'])
            model.setItem(row, 2, item)

        proxy_model = QtGui.QSortFilterProxyModel()
        proxy_model.setSourceModel(model)

        # controls
        self.ui_table = QtGui.QTableView()
        self.ui_table.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
        self.ui_table.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
        self.ui_table.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
        self.ui_table.setModel(proxy_model)
        self.ui_table.setSortingEnabled(False)
        self.ui_table.setSortingEnabled(True)
        self.ui_table.sortByColumn(0, self.ui_table.horizontalHeader().sortIndicatorOrder())

        self.ui_search = QtGui.QLineEdit()
        self.ui_selected = QtGui.QPushButton('Select Emily')

        # lay main
        lay_main = QtGui.QVBoxLayout()
        lay_main.addWidget(self.ui_search)
        lay_main.addWidget(self.ui_table)
        lay_main.addWidget(self.ui_selected)
        self.setLayout(lay_main)

        # connections
        self.ui_selected.clicked.connect(self.clicked_selected_emily)
        self.ui_search.textChanged.connect(self.filter_items)


    def clicked_selected_emily(self):
        print 'select emily'
        self.ui_table.selectRow(2)

    def filter_items(self, text):
        rows = self.ui_table.model().rowCount()
        for row in range(rows):
            self.filter_row(row, text)


    def filter_row(self, row, pattern):
        if not pattern:
            self.ui_table.setRowHidden(row, False)
            return

        model = self.ui_table.model()
        columns = model.columnCount()
        stringlist = []

        # collect text from all columns into single string for searching
        for c in range(columns):
            mdx = model.index(row, c)
            if mdx.isValid():
                val = str(mdx.data(role=QtCore.Qt.DisplayRole)).lower()
                stringlist.append(val)

        # search for string
        patterns = filter(None, [x.lower() for x in pattern.split(' ')])
        results = all(any(x in y for y in stringlist) for x in patterns)
        if results:
            self.ui_table.setRowHidden(row, False)
        else:
            self.ui_table.setRowHidden(row, True)



if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    ex = Example()
    ex.show()
    sys.exit(app.exec_())

【问题讨论】:

第 2 行是什么?? 那是我在胡闹。这不是什么重要的事情。 如何找到名为 Emily 的行并在表格中选择正确的行? 【参考方案1】:

你必须使用模型的match()方法:

def clicked_selected_emily(self):
    print("select emily")
    self.ui_table.clearSelection()
    indexes = self.ui_table.model().match(
        self.ui_table.model().index(0, 0),
        QtCore.Qt.DisplayRole, # role of the search, the text uses the role Qt::DisplayRole
        "Emily", # value that is being searched in the model.
        -1, # maximum number of values ​​are being searched, if it is -1 it will search for all the matches
        QtCore.Qt.MatchExactly # type of search
    )
    for ix in indexes:
        self.ui_table.selectRow(ix.row())

更新:

默认情况下,搜索是在上一个示例中传递给self.ui_table.model().index(0, col)的列,如果你想搜索所有列,你应该只遍历它们,观察效果,​​启用多选:

    self.ui_table.setSelectionMode(QtGui.QAbstractItemView.MultiSelection)

...

def clicked_selected_emily(self):
    print("select banker")
    self.ui_table.clearSelection()
    word = "banker"

    for i in range(self.ui_table.model().columnCount()):
        indexes = self.ui_table.model().match(
            self.ui_table.model().index(0, i),
            QtCore.Qt.DisplayRole, # role of the search, the text uses the role Qt::DisplayRole
            "banker", # value that is being searched in the model.
            -1, # maximum number of values ​​are being searched, if it is -1 it will search for all the matches
            QtCore.Qt.MatchExactly # type of search
        )
        for ix in indexes:
            self.ui_table.selectRow(ix.row())

【讨论】:

这知道只搜索可见项吗? 这会搜索整行还是只搜索第一列? @JokerMartini 1. 该方法搜索所有元素,即使它们被隐藏。我认为这很容易测试:首先过滤直到隐藏所需的行,然后按下按钮,最后删除过滤器,您会看到它被选中。 @JokerMartini 2. 见docs 注意:这个函数的默认实现只搜索列。重新实现此函数以包含不同的搜索行为。:只需查找位于以下位置的列:self.ui_table.model().index(0, col)

以上是关于QTableview 从过滤模型中选择项目的主要内容,如果未能解决你的问题,请参考以下文章

使用 QSortFilterProxyModel 过滤 QTableView 后保留选择

如何从模型内部选择 QTableView 索引或行

选择多行时QTableView变得很慢

如何在 QTableView 单元格角落绘制三角形以显示可以从列表中选择的模型数据?

如何在保持程序化行选择的同时防止用户点击行选择?

过滤 QTableView 中的多列