python - 使用 PySide 搜索 QTableView 中的所有行

标签 python pyside

如何使用搜索字符串来过滤 QTableView 中的行,该搜索字符串检查每行每列的每个显示角色的值?请记住,在这种情况下,可见的列可以根据复选框进行更改。同时保持通过单击列标题对行进行排序的能力。

enter image description here

import os, sys, json, pprint
sys.path.append(os.environ.get('PS_SITEPACKAGES'))
from Qt import QtGui, QtWidgets, QtCore


class QDictTableView(QtWidgets.QWidget):

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

        # controls
        self.ui_search_input = QtWidgets.QLineEdit()
        self.ui_search_input.setPlaceholderText('Search...')

        self.ui_name_filter = QtWidgets.QCheckBox('Name')
        self.ui_age_filter = QtWidgets.QCheckBox('Age')
        self.ui_career_filter = QtWidgets.QCheckBox('Career')

        self.ui_item_table = QtWidgets.QTableView()
        self.ui_item_table.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
        self.ui_item_table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
        self.ui_item_table.verticalHeader().hide()
        self.ui_item_table.setModel(QtGui.QStandardItemModel())

        # lay main
        lay_filters = QtWidgets.QHBoxLayout()
        lay_filters.addWidget(self.ui_name_filter)
        lay_filters.addWidget(self.ui_age_filter)
        lay_filters.addWidget(self.ui_career_filter)

        lay_main = QtWidgets.QVBoxLayout()
        lay_main.setAlignment(QtCore.Qt.AlignTop)
        lay_main.addWidget(self.ui_search_input)
        lay_main.addLayout(lay_filters)
        lay_main.addWidget(self.ui_item_table)
        self.setLayout(lay_main)

        # connections
        self.ui_search_input.textChanged.connect(self.changed_text)
        self.ui_name_filter.stateChanged.connect(self.populate_table)
        self.ui_age_filter.stateChanged.connect(self.populate_table)
        self.ui_career_filter.stateChanged.connect(self.populate_table)

        # being
        self.populate_table()
        self.ui_name_filter.setChecked(True)
        self.ui_age_filter.setChecked(True)
        self.ui_career_filter.setChecked(True)


    # methods
    def changed_text(self, text):
        print 'SEARCHING:', text


    def populate_table(self):
        people = [
            {'name': 'Kevin', 'age': 5, 'career': 'athlete'},
            {'name': 'Maggie', 'age': 13, 'career': 'banker'},
            {'name': 'Leslie', 'age': 32, 'career': 'banker'},
            {'name': 'Emily', 'age': 45, 'career': 'athlete'},
            {'name': 'David', 'age': 27, 'career': 'banker'},
            {'name': 'Marie', 'age': 63, 'career': 'secretary'}
        ]

        model = self.ui_item_table.model()
        model.clear()
        self.ui_item_table.setSortingEnabled(False)

        # column headers
        headers = []
        if self.ui_name_filter.isChecked():
            headers.append('Name')
        if self.ui_age_filter.isChecked():
            headers.append('Age')
        if self.ui_career_filter.isChecked():
            headers.append('Career')
        model.setHorizontalHeaderLabels(headers)
        # model.setHeaderData( i, Qt::Horizontal,thermoNames.at(i));

        # populate rows
        for x in people:

            row = []

            if self.ui_name_filter.isChecked():
                col = QtGui.QStandardItem()
                col.setData(x.get('name', 'NA'), role=QtCore.Qt.DisplayRole)
                col.setData(x, role=QtCore.Qt.UserRole)
                row.append(col)

            if self.ui_age_filter.isChecked():
                col = QtGui.QStandardItem()
                col.setData(x.get('age', 'NA'), role=QtCore.Qt.DisplayRole)
                col.setData(x, role=QtCore.Qt.UserRole)
                row.append(col)
                headers.append('Age')

            if self.ui_career_filter.isChecked():
                col = QtGui.QStandardItem()
                col.setData(x.get('career', 'NA'), role=QtCore.Qt.DisplayRole)
                col.setData(x, role=QtCore.Qt.UserRole)
                row.append(col)
                headers.append('Career')

            model.appendRow(row)

        # update ui after
        self.ui_item_table.setSortingEnabled(True)
        self.ui_item_table.sortByColumn(0, QtCore.Qt.AscendingOrder)



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

最佳答案

如果你想过滤数据,你必须使用QSortFilterProxyModel并覆盖filterAcceptsRow()方法,另一方面,每次都创建模型并不优雅,你只能使用QTableViewsetColumnHidden()方法隐藏列。

import sys
import os
sys.path.append(os.environ.get('PS_SITEPACKAGES'))
from Qt import QtGui, QtWidgets, QtCore

from functools import partial


class FilterProxy(QtCore.QSortFilterProxyModel):
    def __init__(self, *args, **kwargs):
        super(FilterProxy, self).__init__(*args, **kwargs)
        self.filters_colums = set()
        self.mText = ""

    def setText(self, text):
        self.mText = text
        self.invalidateFilter()

    def appendColumn(self, name):
        self.filters_colums.add(name.lower())
        self.invalidateFilter()

    def removeColumn(self, name):
        self.filters_colums.discard(name.lower())
        self.invalidateFilter()

    def filterAcceptsRow(self, source_row, source_parent):
        if self.mText:
            for i in range(self.sourceModel().columnCount()):
                header = self.sourceModel().headerData(i, QtCore.Qt.Horizontal) 
                text = self.sourceModel().index(source_row, i).data()
                if header in self.filters_colums and self.mText in text.lower():
                    return True
            return False
        return True


class QDictTableView(QtWidgets.QWidget):
    def __init__(self, *args, **kwargs):
        super(QDictTableView, self).__init__(*args, **kwargs)
        self.resize(400,300)

        # controls
        self.ui_search_input = QtWidgets.QLineEdit()
        self.ui_search_input.setPlaceholderText('Search...')

        self.ui_item_table = QtWidgets.QTableView()
        self.ui_item_table.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
        self.ui_item_table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
        self.ui_item_table.verticalHeader().hide()

        lay_filters = QtWidgets.QHBoxLayout()
        lay_main = QtWidgets.QVBoxLayout(self)
        lay_main.setAlignment(QtCore.Qt.AlignTop)
        lay_main.addWidget(self.ui_search_input)
        lay_main.addLayout(lay_filters)
        lay_main.addWidget(self.ui_item_table)

        model = self.populate_table()
        self.proxy = FilterProxy()
        self.proxy.setSourceModel(model)
        self.ui_item_table.setModel(self.proxy)

        for text in ("Name", "Age", "Career"):
            checkbox = QtWidgets.QCheckBox(text)            
            checkbox.stateChanged.connect(partial(self.update_columns, text))
            checkbox.setChecked(True)
            lay_filters.addWidget(checkbox)

        self.ui_search_input.textChanged.connect(self.proxy.setText)

    def update_columns(self, text, state):
        cols = self.ui_item_table.model().columnCount()
        i = [self.ui_item_table.model().headerData(i, QtCore.Qt.Horizontal) for i in range(cols)].index(text.lower())
        self.ui_item_table.setColumnHidden(i, state == QtCore.Qt.Unchecked)
        if state == QtCore.Qt.Unchecked:
            self.proxy.removeColumn(text)
        else:
            self.proxy.appendColumn(text)

    def populate_table(self):
        peoples = [
            {'name': 'Kevin', 'age': 5, 'career': 'athlete'},
            {'name': 'Maggie', 'age': 13, 'career': 'banker'},
            {'name': 'Leslie', 'age': 32, 'career': 'banker'},
            {'name': 'Emily', 'age': 45, 'career': 'athlete'},
            {'name': 'David', 'age': 27, 'career': 'banker'},
            {'name': 'Marie', 'age': 63, 'career': 'secretary'}
        ]

        model = QtGui.QStandardItemModel()

        headers = ["name", "age", "career"]
        model.setHorizontalHeaderLabels(headers)

        for row, people in enumerate(peoples):
            items = []
            for key, value in people.items():
                col = headers.index(key)
                item = QtGui.QStandardItem(str(value))
                items.append(item)
            model.insertRow(row, items)
        return model

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

关于python - 使用 PySide 搜索 QTableView 中的所有行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51212916/

相关文章:

python - 使用带有可选参数的 docopt 双破折号选项?

python - 列表 python [(160,177),(198,123)] 的逆

python - 为什么部分在 View 之外的矩形被绘制为三角形?

qt - 如何在 QTextEdit 实例 (PySide/PyQt) 中垂直居中单行?

python - 导入错误 : No module named PySide

python - 在 PlotWidget GUI 中运行实时 pyqtgraph

python - 用期末存款计算复利 future 值(value)的正确公式是什么

python - 如何获取我的元素的父元素?

jquery - 如何抓取通过按钮锁定的数据?

python - 为什么 QToolTips 不会出现在 QMenu 中的 QActions 上