我使用 pyqt5 创建了一个 QTableWidget,并成功地在表格小部件的每一列中添加了过滤选项,并使用堆栈溢出上可用的答案之一。过滤器按预期工作,但我想在顶部的过滤器中添加搜索栏来搜索值。
在我的 python 脚本中,过滤器中可能有大约 50 多个唯一值。因此,如果有一种方法可以在过滤器中搜索值,那就很容易了。
另外,有没有一种方法可以在其中添加滚动条,因为目前如果我向表中添加更多值,我的过滤区域会变得更大,并且更大以累积所有值。
这是我完整的 python 代码:
import csv
import sys
from PyQt5 import QtCore, QtWidgets, QtGui
from PyQt5.QtWidgets import QApplication, QVBoxLayout, QTableWidget, QCheckBox, QWidgetAction, QMenu, QDialogButtonBox, QTableWidgetItem
from PyQt5.QtGui import QFont
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent=parent)
self.verticalLayout = QVBoxLayout(self)
self.filterall = QTableWidget(self)
self.filterall.setColumnCount(0)
self.filterall.setRowCount(0)
self.verticalLayout.addWidget(self.filterall)
self.loadAll()
self.horizontalHeader = self.filterall.horizontalHeader()
self.horizontalHeader.sectionClicked.connect(self.on_view_horizontalHeader_sectionClicked)
self.keywords = dict([(i, []) for i in range(self.filterall.columnCount())])
self.checkBoxs = []
self.col = None
def slotSelect(self, state):
for checkbox in self.checkBoxs:
checkbox.setChecked(QtCore.Qt.Checked == state)
def on_view_horizontalHeader_sectionClicked(self, index):
#self.clearFilter()
self.menu = QMenu(self)
#self.menu.setStyleSheet('QMenu { menu-scrollable: true; }')
self.col = index
data_unique = []
self.checkBoxs = []
checkBox = QCheckBox("Select all", self.menu)
checkableAction = QWidgetAction(self.menu)
checkableAction.setDefaultWidget(checkBox)
self.menu.addAction(checkableAction)
checkBox.setChecked(True)
checkBox.stateChanged.connect(self.slotSelect)
for i in range(self.filterall.rowCount()):
if not self.filterall.isRowHidden(i):
item = self.filterall.item(i, index)
font = QFont()
font.setBold(False)
self.filterall.horizontalHeaderItem(index).setFont(font)
if item.text() not in data_unique:
data_unique.append(item.text())
checkBox = QCheckBox(item.text(), self.menu)
checkBox.setChecked(True)
checkableAction = QWidgetAction(self.menu)
checkableAction.setDefaultWidget(checkBox)
self.menu.addAction(checkableAction)
self.checkBoxs.append(checkBox)
btn = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel,
QtCore.Qt.Horizontal, self.menu)
btn.accepted.connect(self.menuClose)
btn.rejected.connect(self.menu.close)
checkableAction = QWidgetAction(self.menu)
checkableAction.setDefaultWidget(btn)
self.menu.addAction(checkableAction)
headerPos = self.filterall.mapToGlobal(self.horizontalHeader.pos())
posY = headerPos.y() + self.horizontalHeader.height()
posX = headerPos.x() + self.horizontalHeader.sectionPosition(index)
self.menu.exec_(QtCore.QPoint(posX, posY))
def menuClose(self):
self.keywords[self.col] = []
for element in self.checkBoxs:
if element.isChecked():
self.keywords[self.col].append(element.text())
self.filterdata()
self.menu.close()
def loadAll(self):
with open("sample.csv", "r") as inpfil:
reader = csv.reader(inpfil, delimiter=',')
csheader = next(reader)
ncol = len(csheader)
data = list(reader)
row_count = len(data)
self.filterall.setRowCount(row_count)
self.filterall.setColumnCount(ncol)
self.filterall.setHorizontalHeaderLabels(str('%s' % ', '.join(map(str, csheader))).split(","))
for ii in range(0, row_count):
mainins = data[ii]
for var in range(0, ncol):
self.filterall.setItem(ii, var, QTableWidgetItem(mainins[var]))
def clearFilter(self):
for i in range(self.filterall.rowCount()):
self.filterall.setRowHidden(i, False)
def filterdata(self):
columnsShow = dict([(i, True) for i in range(self.filterall.rowCount())])
for i in range(self.filterall.rowCount()):
for j in range(self.filterall.columnCount()):
item = self.filterall.item(i, j)
if self.keywords[j]:
if item.text() not in self.keywords[j]:
columnsShow[i] = False
font = QFont()
font.setBold(True)
self.filterall.horizontalHeaderItem(j).setFont(font)
for key, value in columnsShow.items():
self.filterall.setRowHidden(key, not value)
app = QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
我希望看到我的代码工作,以便当用户在搜索栏中输入时,它会从给定的唯一值中过滤选项。这就像 Excel 过滤器中的搜索栏,您可以在其中键入关键字并过滤可用的唯一值。
预期示例输出:
我的代码过滤如下所示:
python 代码过滤| ||我的sample.csv 文件有数据(19 条记录),如下面的屏幕截图所示:
sample.csv 文件
好的,我可以帮助你在 Pyqt5 QTableWidget 列过滤器中实现搜索栏。以下是实现此目标的方法,以及添加滚动条以更好地处理大量唯一值的说明:
import csv
import sys
from PyQt5 import QtCore, QtWidgets, QtGui
from PyQt5.QtWidgets import QApplication, QVBoxLayout, QTableWidget, QCheckBox, QWidgetAction, QMenu, QDialogButtonBox, QTableWidgetItem, QLineEdit
from PyQt5.QtGui import QFont
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent=parent)
self.verticalLayout = QVBoxLayout(self)
self.filterall = QTableWidget(self)
self.filterall.setColumnCount(0)
self.filterall.setRowCount(0)
self.verticalLayout.addWidget(self.filterall)
self.loadAll()
self.horizontalHeader = self.filterall.horizontalHeader()
self.horizontalHeader.sectionClicked.connect(self.on_view_horizontalHeader_sectionClicked)
self.keywords = dict([(i, []) for i in range(self.filterall.columnCount())])
self.checkBoxs = []
self.col = None
def slotSelect(self, state):
for checkbox in self.checkBoxs:
checkbox.setChecked(QtCore.Qt.Checked == state)
def on_view_horizontalHeader_sectionClicked(self, index):
self.col = index
data_unique = []
self.checkBoxs = []
menu = QMenu(self)
menu.setStyleSheet('QMenu { menu-scrollable: true; }') # 启用滚动
# 添加搜索栏
searchEdit = QLineEdit(menu)
searchEdit.setPlaceholderText("搜索...")
searchEdit.textChanged.connect(lambda text: self.searchFilter(text, menu))
checkableAction = QWidgetAction(menu)
checkableAction.setDefaultWidget(searchEdit)
menu.addAction(checkableAction)
# 添加“全选”复选框
checkBox = QCheckBox("全选", menu)
checkableAction = QWidgetAction(menu)
checkableAction.setDefaultWidget(checkBox)
menu.addAction(checkableAction)
checkBox.setChecked(True)
checkBox.stateChanged.connect(self.slotSelect)
for i in range(self.filterall.rowCount()):
if not self.filterall.isRowHidden(i):
item = self.filterall.item(i, index)
if item.text() not in data_unique:
data_unique.append(item.text())
checkBox = QCheckBox(item.text(), menu)
checkBox.setChecked(True)
checkableAction = QWidgetAction(menu)
checkableAction.setDefaultWidget(checkBox)
menu.addAction(checkableAction)
self.checkBoxs.append(checkBox)
btn = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel,
QtCore.Qt.Horizontal, menu)
btn.accepted.connect(lambda: self.menuClose(menu)) # 传递菜单
btn.rejected.connect(menu.close)
checkableAction = QWidgetAction(menu)
checkableAction.setDefaultWidget(btn)
menu.addAction(checkableAction)
headerPos = self.filterall.mapToGlobal(self.horizontalHeader.pos())
posY = headerPos.y() + self.horizontalHeader.height()
posX = headerPos.x() + self.horizontalHeader.sectionPosition(index)
menu.exec_(QtCore.QPoint(posX, posY))
def searchFilter(self, text, menu):
# 在菜单中过滤操作
for action in menu.actions():
if isinstance(action.defaultWidget(), QCheckBox):
checkbox = action.defaultWidget()
checkbox.setVisible(text.lower() in checkbox.text().lower())
def menuClose(self, menu): # 接收菜单作为参数
self.keywords[self.col] = []
for action in menu.actions():
if isinstance(action.defaultWidget(), QCheckBox):
checkbox = action.defaultWidget()
if checkbox.isChecked():
self.keywords[self.col].append(checkbox.text())
self.filterdata()
menu.close() # 关闭传递的菜单
def loadAll(self):
with open("sample.csv", "r") as inpfil:
reader = csv.reader(inpfil, delimiter=',')
csheader = next(reader)
ncol = len(csheader)
data = list(reader)
row_count = len(data)
self.filterall.setRowCount(row_count)
self.filterall.setColumnCount(ncol)
self.filterall.setHorizontalHeaderLabels(str('%s' % ', '.join(map(str, csheader))).split(","))
for ii in range(0, row_count):
mainins = data[ii]
for var in range(0, ncol):
self.filterall.setItem(ii, var, QTableWidgetItem(mainins[var]))
def clearFilter(self):
for i in range(self.filterall.rowCount()):
self.filterall.setRowHidden(i, False)
def filterdata(self):
columnsShow = dict([(i, True) for i in range(self.filterall.rowCount())])
for i in range(self.filterall.rowCount()):
for j in range(self.filterall.columnCount()):
item = self.filterall.item(i, j)
if self.keywords[j]:
if item.text() not in self.keywords[j]:
columnsShow[i] = False
font = QFont()
font.setBold(True)
self.filterall.horizontalHeaderItem(j).setFont(font)
for key, value in columnsShow.items():
self.filterall.setRowHidden(key, not value)
app = QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
以下是所做更改的说明:
- 添加搜索栏:
-
在
on_view_horizontalHeader_sectionClicked
函数内部,我们创建了一个QLineEdit
小部件 (searchEdit
) 并将其添加到菜单中。 -
searchEdit
的textChanged
信号连接到一个新函数searchFilter
。 -
实现
searchFilter
函数: - 此函数接收搜索文本并迭代菜单中的操作。
-
它检查操作是否具有
QCheckBox
作为其默认小部件。 -
如果是,它会根据搜索文本显示或隐藏复选框。
-
启用菜单滚动:
-
在
on_view_horizontalHeader_sectionClicked
函数中,我们使用样式表QMenu { menu-scrollable: true; }
启用菜单滚动。这为包含大量唯一值的长过滤器列表添加了一个滚动条。
现在,当单击列标题时,将出现一个带有搜索栏的菜单。在搜索栏中键入内容将过滤过滤器选项列表,从而更容易找到要查找的内容,尤其是在有大量唯一值的情况下。
标签:python,search,pyqt5,filtering,qtablewidget From: 78814144