【问题标题】:How to create filter rows for Qtableview with using QSqlTableModel.?如何使用 QSqlTableModel 为 Qtableview 创建过滤器行。?
【发布时间】:2020-11-15 05:51:36
【问题描述】:

是否可以使用 QSqlTableModel 为 Qtableview 创建行过滤器。 我正在唱“QSqlTableModel”来显示来自 SQLite 的 Qtableview 上的数据。但我正在尝试过滤行。当我执行代码时,我遇到的错误是

第 44 行,在 for row in range(self.model.rowCount()) AttributeError: 'QSqlTableModel' object has no attribute 'item'

我试过但没有得到任何解决方案。可以用 QSqlTableModel 做到这一点吗? 当我单击 Qtableview 的任何列时,我想显示来自 tableview 的过滤项目。我正在将 Qtableview 与 QSqlTableModel 一起使用。

我想像图片中显示的那样做

from PyQt5 import QtCore, QtGui, QtWidgets, QtSql
from PyQt5.QtSql import *


class myWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(myWindow, self).__init__(parent)
        self.centralwidget  = QtWidgets.QWidget(self)
        self.view           = QtWidgets.QTableView(self.centralwidget)

        self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)

        self.gridLayout.addWidget(self.view, 1, 0, 1, 3)

        self.setCentralWidget(self.centralwidget)

       # self.model = QtGui.QStandardItemModel(self)

        db = QSqlDatabase.addDatabase("QSQLITE")
        db.setDatabaseName("model.db")
        db.open()

        self.model = QSqlTableModel(self)
        self.model.setTable("sheet")
        self.model.select()
        self.view.setModel(self.model)

        self.proxy = QtCore.QSortFilterProxyModel(self)
        self.proxy.setSourceModel(self.model)

        self.view.setModel(self.proxy)


        self.horizontalHeader = self.view.horizontalHeader()
        self.horizontalHeader.sectionClicked.connect(self.on_view_horizontalHeader_sectionClicked)

    @QtCore.pyqtSlot(int)
    def on_view_horizontalHeader_sectionClicked(self, logicalIndex):
        self.logicalIndex   = logicalIndex
        self.menuValues     = QtWidgets.QMenu(self)
        self.signalMapper   = QtCore.QSignalMapper(self)  

        valuesUnique = [    self.model.item(row, self.logicalIndex).text()
                            for row in range(self.model.rowCount())
                            ]

        actionAll = QtWidgets.QAction("All", self)
        actionAll.triggered.connect(self.on_actionAll_triggered)
        self.menuValues.addAction(actionAll)
        self.menuValues.addSeparator()


        for actionNumber, actionName in enumerate(sorted(list(set(valuesUnique)))):              
            action = QtWidgets.QAction(actionName, self)
            self.signalMapper.setMapping(action, actionNumber)  
            action.triggered.connect(self.signalMapper.map)  
            self.menuValues.addAction(action)

        self.signalMapper.mapped.connect(self.on_signalMapper_mapped)  

        headerPos = self.view.mapToGlobal(self.horizontalHeader.pos())        

        posY = headerPos.y() + self.horizontalHeader.height()
        posX = headerPos.x() + self.horizontalHeader.sectionPosition(self.logicalIndex)

        self.menuValues.exec_(QtCore.QPoint(posX, posY))

    @QtCore.pyqtSlot()
    def on_actionAll_triggered(self):
        filterColumn = self.logicalIndex
        filterString = QtCore.QRegExp(  "",
                                        QtCore.Qt.CaseInsensitive,
                                        QtCore.QRegExp.RegExp
                                        )

        self.proxy.setFilterRegExp(filterString)
        self.proxy.setFilterKeyColumn(filterColumn)

    @QtCore.pyqtSlot(int)
    def on_signalMapper_mapped(self, i):
        stringAction = self.signalMapper.mapping(i).text()
        filterColumn = self.logicalIndex
        filterString = QtCore.QRegExp(  stringAction,
                                        QtCore.Qt.CaseSensitive,
                                        QtCore.QRegExp.FixedString
                                        )

        self.proxy.setFilterRegExp(filterString)
        self.proxy.setFilterKeyColumn(filterColumn)


if __name__ == "__main__":
    import sys

    app  = QtWidgets.QApplication(sys.argv)
    main = myWindow()
    main.show()
    main.resize(400, 600)
    sys.exit(app.exec_())

【问题讨论】:

    标签: python python-3.x pyqt5 filtering qsqltablemodel


    【解决方案1】:

    实现了 QSortFilterProxyModel 来比较字符串,但在您的情况下,您有不同类型的值,因此必须实现自定义过滤器。

    要处理与每个选项相关的不同类型的数据,然后在 QAction 中分别使用 setData() 和 data() 存储和访问值。

    另一方面,我认为没有必要使用 QSignalMapper 或信号,因为如果 exec_() 方法被选中则返回 QAction,否则返回 None。

    要访问每个项目的值,必须使用模型的 data() 方法:

    from PyQt5 import QtCore, QtGui, QtWidgets, QtSql
    
    
    class FilterProxyModel(QtCore.QSortFilterProxyModel):
        def __init__(self, parent=None):
            super().__init__(parent)
            self._filter_value = None
    
        @property
        def filter_value(self):
            return self._filter_value
    
        @filter_value.setter
        def filter_value(self, value):
            self._filter_value = value
            self.invalidateFilter()
    
        def filterAcceptsRow(self, sourceRow, sourceParent):
            if self.filter_value is None:
                return True
            value = (
                self.sourceModel()
                .index(sourceRow, self.filterKeyColumn(), sourceParent)
                .data(self.filterRole())
            )
            return value == self.filter_value
    
    
    class myWindow(QtWidgets.QMainWindow):
        def __init__(self, parent=None):
            super(myWindow, self).__init__(parent)
            self.centralwidget = QtWidgets.QWidget(self)
            self.view = QtWidgets.QTableView(self.centralwidget)
    
            self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
    
            self.gridLayout.addWidget(self.view, 1, 0, 1, 3)
    
            self.setCentralWidget(self.centralwidget)
    
            db = QtSql.QSqlDatabase.addDatabase("QSQLITE")
            db.setDatabaseName("model.db")
            db.open()
    
            self.model = QtSql.QSqlTableModel(self)
            self.model.setTable("sheet")
            self.model.select()
            self.view.setModel(self.model)
    
            self.proxy = FilterProxyModel(self)
            self.proxy.setSourceModel(self.model)
    
            self.view.setModel(self.proxy)
    
            self.horizontalHeader = self.view.horizontalHeader()
            self.horizontalHeader.sectionClicked.connect(
                self.on_view_horizontalHeader_sectionClicked
            )
    
        @QtCore.pyqtSlot(int)
        def on_view_horizontalHeader_sectionClicked(self, logicalIndex):
            menu = QtWidgets.QMenu(self)
    
            values = []
    
            for row in range(self.model.rowCount()):
                value = self.model.index(row, logicalIndex).data(self.proxy.filterRole())
                values.append(value)
    
            action_all = QtWidgets.QAction("All", self)
            action_all.setData(None)
            menu.addAction(action_all)
            menu.addSeparator()
    
            for value in sorted(list(set(values))):
                action = QtWidgets.QAction(str(value), self)
                action.setData(value)
                menu.addAction(action)
    
            headerPos = self.view.mapToGlobal(self.horizontalHeader.pos())
            posY = headerPos.y() + self.horizontalHeader.height()
            posX = headerPos.x() + self.horizontalHeader.sectionPosition(logicalIndex)
    
            action = menu.exec_(QtCore.QPoint(posX, posY))
            if action is not None:
                self.proxy.setFilterKeyColumn(logicalIndex)
                self.proxy.filter_value = action.data()
    
    
    if __name__ == "__main__":
        import sys
    
        app = QtWidgets.QApplication(sys.argv)
        main = myWindow()
        main.show()
        main.resize(400, 600)
        sys.exit(app.exec_())
    

    【讨论】:

    • 第二列只有数字。得到错误。 action = QtWidgets.QAction(actionName, self) TypeError: arguments does not match any overloaded call: QAction(parent: QObject = None): argument 1 has unexpected type 'int' QAction(str, parent: QObject = None): argument 1有意外类型'int' QAction(QIcon, str, parent: QObject = None): 参数1 有意外类型'int'
    • @user3030327 您展示的图片不代表您所指出的,您可以分享model.db文件
    • 是的。我没有共享数据库内容是我的错误。其实我虽然那是一个例子。实际上我的数据库内容有一些列文本,并且一些列也只有数字值。
    • @user3030327 再试一次
    • @user3030327 图像没有帮助,试试我的新解决方案,如果它有效,那么你不需要共享 .db,如果它不起作用,那么我将需要你的 .db 所以如果你可以通过 drive、drobox 等或其他类似方式共享它。
    猜你喜欢
    • 2012-12-13
    • 2020-11-21
    • 1970-01-01
    • 1970-01-01
    • 2011-08-11
    • 2020-08-10
    • 1970-01-01
    • 2013-01-14
    • 1970-01-01
    相关资源
    最近更新 更多