如何在PyQt5的QTableWidget列过滤器中添加搜索栏与滚动条
给QTableWidget过滤器添加搜索栏与滚动条优化
直接上修改后的完整代码,实现类似Excel的筛选搜索效果,同时解决选项过多导致菜单过大的问题:
import sys from PyQt5.QtWidgets import (QApplication, QMainWindow, QTableWidget, QTableWidgetItem, QMenu, QAction, QLineEdit, QWidget, QVBoxLayout, QScrollArea) from PyQt5.QtCore import Qt, QRegExp from PyQt5.QtGui import QRegExpValidator class FilterableTableWidget(QTableWidget): def __init__(self, rows, columns, parent=None): super().__init__(rows, columns, parent) self.filter_menus = {} # 存储各列过滤器菜单 self.filter_values = {} # 存储各列过滤值 def setHorizontalHeaderLabels(self, labels): super().setHorizontalHeaderLabels(labels) # 为每个表头绑定过滤器菜单触发事件 for col in range(self.columnCount()): header_item = self.horizontalHeaderItem(col) header_item.setToolTip("点击筛选") self.horizontalHeader().setContextMenuPolicy(Qt.CustomContextMenu) self.horizontalHeader().customContextMenuRequested.connect(self.show_filter_menu) def show_filter_menu(self, pos): # 获取点击的列索引 col = self.horizontalHeader().logicalIndexAt(pos) if col < 0: return # 提取当前列的所有唯一值并排序 unique_values = [] for row in range(self.rowCount()): item = self.item(row, col) if item and item.text() not in unique_values: unique_values.append(item.text()) unique_values.sort() # 创建主菜单 menu = QMenu(self) # 构建搜索栏组件 search_widget = QWidget() search_layout = QVBoxLayout(search_widget) search_layout.setContentsMargins(5, 5, 5, 5) search_edit = QLineEdit() search_edit.setPlaceholderText("搜索选项...") search_layout.addWidget(search_edit) # 构建带滚动条的选项区域 scroll_area = QScrollArea() scroll_area.setWidgetResizable(True) scroll_area.setMaximumHeight(300) # 限制菜单最大高度,超出显示滚动条 content_widget = QWidget() content_layout = QVBoxLayout(content_widget) content_layout.setAlignment(Qt.AlignTop) scroll_area.setWidget(content_widget) search_layout.addWidget(scroll_area) # 将搜索组件加入菜单 search_action = QAction(menu) search_action.setDefaultWidget(search_widget) menu.addAction(search_action) menu.addSeparator() # 添加全选选项 select_all_action = QAction("全选", menu) select_all_action.setCheckable(True) select_all_action.setChecked(True) menu.addAction(select_all_action) menu.addSeparator() # 生成选项动作列表 action_list = [] for value in unique_values: action = QAction(value, menu) action.setCheckable(True) action.setChecked(True) action.triggered.connect(lambda checked, val=value: self.update_filter(col, val, checked)) content_layout.addWidget(action) action_list.append(action) # 绑定搜索栏文本变化事件,过滤选项 def filter_options(text): regex = QRegExp(text, Qt.CaseInsensitive, QRegExp.FixedString) for action in action_list: action.setVisible(regex.exactMatch(action.text())) search_edit.textChanged.connect(filter_options) # 绑定全选事件 def toggle_all(checked): for action in action_list: action.setChecked(checked) self.update_filter(col, action.text(), checked) select_all_action.triggered.connect(toggle_all) # 显示菜单 menu.exec_(self.horizontalHeader().mapToGlobal(pos)) def update_filter(self, col, value, checked): # 更新过滤值集合 if col not in self.filter_values: self.filter_values[col] = set() if checked: self.filter_values[col].add(value) else: self.filter_values[col].discard(value) # 应用过滤规则 self.apply_filters() def apply_filters(self): # 根据过滤值控制行的显示/隐藏 for row in range(self.rowCount()): show_row = True for col, allowed_values in self.filter_values.items(): item = self.item(row, col) if item and item.text() not in allowed_values: show_row = False break self.setRowHidden(row, not show_row) class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("带搜索过滤器的表格") self.setGeometry(100, 100, 800, 600) # 创建表格并设置表头 self.table = FilterableTableWidget(100, 3) headers = ["姓名", "部门", "职级"] self.table.setHorizontalHeaderLabels(headers) # 填充测试数据(模拟50+唯一值场景) departments = ["研发部", "市场部", "人事部", "财务部", "运营部", "产品部", "客服部", "行政部"] * 7 positions = ["实习生", "专员", "主管", "经理", "总监", "副总裁", "总裁"] * 8 for row in range(100): self.table.setItem(row, 0, QTableWidgetItem(f"员工{row+1}")) self.table.setItem(row, 1, QTableWidgetItem(departments[row])) self.table.setItem(row, 2, QTableWidgetItem(positions[row])) self.setCentralWidget(self.table) if __name__ == "__main__": app = QApplication(sys.argv) window = MainWindow() window.show() sys.exit(app.exec_())
关键修改说明
- 搜索栏功能:在过滤器菜单顶部添加
QLineEdit,通过正则匹配实时过滤选项,支持大小写不敏感搜索 - 滚动条优化:将选项列表放入
QScrollArea并限制最大高度,避免选项过多导致菜单超出屏幕 - 全选同步:点击全选按钮时自动同步所有选项的选中状态,同时更新过滤规则
- 过滤逻辑:通过集合存储允许显示的值,遍历所有行并控制显示状态,保证过滤效率
内容的提问来源于stack exchange,提问作者Jenit Patel
相关产品推荐
相关产品推荐

