如何使用 QSqlTableModel 为 Qtableview 创建过滤器行?
How to create filter rows for Qtableview with using QSqlTableModel.?
是否可以使用 QSqlTableModel 为 Qtableview 创建行过滤器。
我正在唱“QSqlTableModel”来显示来自正在工作的 SQLite 的 Qtableview 上的数据。但我正在尝试过滤行。当我执行代码时,我遇到的错误是
line 44, in
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_())
实施 QSortFilterProxyModel 是为了比较字符串,但在您的情况下,您有不同类型的值,因此必须实施自定义过滤器。
为了处理与每个选项关联的不同类型的数据,然后在 QAction 中分别使用 setData() 和 data() 存储和访问值。
另一方面,我认为没有必要使用 QSignalMapper 或信号,因为 exec_() 方法 returns 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_())
是否可以使用 QSqlTableModel 为 Qtableview 创建行过滤器。 我正在唱“QSqlTableModel”来显示来自正在工作的 SQLite 的 Qtableview 上的数据。但我正在尝试过滤行。当我执行代码时,我遇到的错误是
line 44, in 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_())
实施 QSortFilterProxyModel 是为了比较字符串,但在您的情况下,您有不同类型的值,因此必须实施自定义过滤器。
为了处理与每个选项关联的不同类型的数据,然后在 QAction 中分别使用 setData() 和 data() 存储和访问值。
另一方面,我认为没有必要使用 QSignalMapper 或信号,因为 exec_() 方法 returns 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_())