Python 如何在PyQt中为QTableView创建过滤器
我正在使用QTableView显示从Python 如何在PyQt中为QTableView创建过滤器,python,qt,pyqt,pyqt4,qtableview,Python,Qt,Pyqt,Pyqt4,Qtableview,我正在使用QTableView显示从QtSql.QSqlQuery 我想知道如何像在excel中一样为它创建过滤器 在上图中,我需要得到所有heder的过滤器(Sh_代码,Sh_顺序,Stage) 过滤器在我们可以过滤的列中具有唯一的值 要求的结果 我需要一个带有下拉框的表视图标题,该下拉框列出该列中的所有唯一值,就像下面的excel一样。无需顶部,标准过滤器。。。如图所示。只需要“全部”和唯一的“列项目” 这是我的.NET应用程序,为了更清晰,上传了它 这里是PyQt中使用QSortFil
QtSql.QSqlQuery
我想知道如何像在excel中一样为它创建过滤器
在上图中,我需要得到所有heder的过滤器(Sh_代码,Sh_顺序,Stage)
过滤器在我们可以过滤的列中具有唯一的值
要求的结果
我需要一个带有下拉框的表视图标题,该下拉框列出该列中的所有唯一值,就像下面的excel一样。无需顶部,标准过滤器。。。如图所示。只需要“全部”和唯一的“列项目”
这是我的.NET应用程序,为了更清晰,上传了它
这里是PyQt中使用
QSortFilterProxyModel
、QStandardItemModel
和QTableView
进行过滤的一个示例,它可以很容易地适应其他视图和模型:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
from PyQt4 import QtCore, QtGui
class myWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(myWindow, self).__init__(parent)
self.centralwidget = QtGui.QWidget(self)
self.lineEdit = QtGui.QLineEdit(self.centralwidget)
self.view = QtGui.QTableView(self.centralwidget)
self.comboBox = QtGui.QComboBox(self.centralwidget)
self.label = QtGui.QLabel(self.centralwidget)
self.gridLayout = QtGui.QGridLayout(self.centralwidget)
self.gridLayout.addWidget(self.lineEdit, 0, 1, 1, 1)
self.gridLayout.addWidget(self.view, 1, 0, 1, 3)
self.gridLayout.addWidget(self.comboBox, 0, 2, 1, 1)
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
self.setCentralWidget(self.centralwidget)
self.label.setText("Regex Filter")
self.model = QtGui.QStandardItemModel(self)
for rowName in range(3) * 5:
self.model.invisibleRootItem().appendRow(
[ QtGui.QStandardItem("row {0} col {1}".format(rowName, column))
for column in range(3)
]
)
self.proxy = QtGui.QSortFilterProxyModel(self)
self.proxy.setSourceModel(self.model)
self.view.setModel(self.proxy)
self.comboBox.addItems(["Column {0}".format(x) for x in range(self.model.columnCount())])
self.lineEdit.textChanged.connect(self.on_lineEdit_textChanged)
self.comboBox.currentIndexChanged.connect(self.on_comboBox_currentIndexChanged)
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 = QtGui.QMenu(self)
self.signalMapper = QtCore.QSignalMapper(self)
self.comboBox.blockSignals(True)
self.comboBox.setCurrentIndex(self.logicalIndex)
self.comboBox.blockSignals(True)
valuesUnique = [ self.model.item(row, self.logicalIndex).text()
for row in range(self.model.rowCount())
]
actionAll = QtGui.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 = QtGui.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)
@QtCore.pyqtSlot(str)
def on_lineEdit_textChanged(self, text):
search = QtCore.QRegExp( text,
QtCore.Qt.CaseInsensitive,
QtCore.QRegExp.RegExp
)
self.proxy.setFilterRegExp(search)
@QtCore.pyqtSlot(int)
def on_comboBox_currentIndexChanged(self, index):
self.proxy.setFilterKeyColumn(index)
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
main = myWindow()
main.show()
main.resize(400, 600)
sys.exit(app.exec_())
要获得所需的结果,通过单击标题启动弹出菜单,并填充该列的唯一值。一旦选择了弹出菜单中的一个项目,该值将传递给self.proxy.setFilterRegExp(filterString)
,并传递给self.proxy.setFilterKeyColumn(filterValue)
我试图更新上面提供的关于
PyQt5
from PyQt5 import QtCore, QtGui, QtWidgets
class myWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(myWindow, self).__init__(parent)
self.centralwidget = QtWidgets.QWidget(self)
self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
self.view = QtWidgets.QTableView(self.centralwidget)
self.comboBox = QtWidgets.QComboBox(self.centralwidget)
self.label = QtWidgets.QLabel(self.centralwidget)
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout.addWidget(self.lineEdit, 0, 1, 1, 1)
self.gridLayout.addWidget(self.view, 1, 0, 1, 3)
self.gridLayout.addWidget(self.comboBox, 0, 2, 1, 1)
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
self.setCentralWidget(self.centralwidget)
self.label.setText("Regex Filter")
self.model = QtGui.QStandardItemModel(self)
for rowName in range(3*5):
self.model.invisibleRootItem().appendRow(
[ QtGui.QStandardItem("row {0} col {1}".format(rowName, column))
for column in range(3)
]
)
self.proxy = QtCore.QSortFilterProxyModel(self)
self.proxy.setSourceModel(self.model)
self.view.setModel(self.proxy)
self.comboBox.addItems(["Column {0}".format(x) for x in range(self.model.columnCount())])
self.lineEdit.textChanged.connect(self.on_lineEdit_textChanged)
self.comboBox.currentIndexChanged.connect(self.on_comboBox_currentIndexChanged)
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)
self.comboBox.blockSignals(True)
self.comboBox.setCurrentIndex(self.logicalIndex)
self.comboBox.blockSignals(True)
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)
@QtCore.pyqtSlot(str)
def on_lineEdit_textChanged(self, text):
search = QtCore.QRegExp( text,
QtCore.Qt.CaseInsensitive,
QtCore.QRegExp.RegExp
)
self.proxy.setFilterRegExp(search)
@QtCore.pyqtSlot(int)
def on_comboBox_currentIndexChanged(self, index):
self.proxy.setFilterKeyColumn(index)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
main = myWindow()
main.show()
main.resize(400, 600)
sys.exit(app.exec_())
根据@user1006989和@Behzad Jamali的回答: 如果表的列数超过当前的视图端口数,则用于在标题上筛选的菜单位置不会在确切位置弹出 要正确定位弹出菜单,请使用此行
posX = headerPos.x() + self.horizontalHeader.sectionViewportPosition(index)
当我在过滤框中输入“行0列0”时,它不会过滤任何内容。我在组合框上的
中添加了打印语句,但它们从未被执行。我正在研究Python2.6。4@PBLNarasimhaRao忘记连接插槽了!我更新了,它现在应该可以工作了。它通过连接信号self.comboBox.currentIndexChanged.connect(self.on\u comboBox\u currentIndexChanged)
和self.lineEdit.textChanged.connect(self.on\u lineEdit\u textChanged)
工作,但我需要在列标题上显示一个过滤器,从那里我可以选择它(例如在excel中)。我已使用所需的excel快照更新了该问题。@PBLNarasimhaRao Checkout my,我添加了一些关于如何在单击标题时显示筛选弹出菜单的信息。您可以编辑您建议的代码。我找不到标题单击事件。