Python开发带类Excel筛选的双窗口数据选录应用求助
解决方案
Python完全能搞定你的需求,不管是30万条数据的处理、类Excel列筛选,还是双窗口交互导出,都有成熟的工具链支撑。下面是具体的拆解实现方案:
核心模块实现
1. 高效加载Excel数据
用pandas处理大数据是最优选择,30列30万条记录的内存占用完全在Python的处理范围内:
import pandas as pd # 加载数据,指定openpyxl引擎支持xlsx格式大文件 df = pd.read_excel("your_data.xlsx", engine="openpyxl") # 可选:提前转换为字符串类型避免数值格式问题 df = df.astype(str)
2. UI框架选择:优先PyQt5/PyQt6
PyQt的模型视图架构天生适合大数据场景,虚拟滚动只渲染可见行,不会出现卡顿,且自带的QSortFilterProxyModel可以快速实现类Excel的列筛选功能。
3. 类Excel列筛选实现
通过自定义QTableView+QSortFilterProxyModel组合,给表头添加筛选下拉菜单,实现点击表头选择值过滤的效果:
from PyQt6.QtWidgets import QTableView, QSortFilterProxyModel, QMenu, QAction from PyQt6.QtCore import Qt, QRegularExpression class FilterableTableView(QTableView): def __init__(self, source_model, parent=None): super().__init__(parent) self.source_model = source_model # 创建代理模型用于筛选 self.proxy_model = QSortFilterProxyModel() self.proxy_model.setSourceModel(source_model) self.setModel(self.proxy_model) self.current_filter_col = -1 def mousePressEvent(self, event): # 判断是否点击表头 header_pos = self.horizontalHeader().mapFromGlobal(event.globalPos()) col_index = self.horizontalHeader().logicalIndexAt(header_pos) if col_index >= 0: self.current_filter_col = col_index self.show_filter_menu(event.globalPos()) super().mousePressEvent(event) def show_filter_menu(self, pos): menu = QMenu(self) # 获取当前列的唯一值并排序 col_data = self.source_model.get_column_data(self.current_filter_col) unique_vals = sorted(list(set(col_data))) # 添加筛选选项 for val in unique_vals: action = QAction(val, self) action.triggered.connect(lambda _, v=val: self.apply_filter(v)) menu.addAction(action) # 添加清除筛选选项 clear_action = QAction("清除筛选", self) clear_action.triggered.connect(self.clear_filter) menu.addAction(clear_action) menu.exec(pos) def apply_filter(self, value): # 精确匹配筛选值(忽略大小写) regex = QRegularExpression(f"^{value}$", QRegularExpression.PatternOption.CaseInsensitiveOption) self.proxy_model.setFilterRegularExpression(regex) self.proxy_model.setFilterKeyColumn(self.current_filter_col) def clear_filter(self): self.proxy_model.setFilterRegularExpression("")
4. 双窗口与行选择实现
创建两个独立的筛选表格窗口,共享同一个数据源模型,支持多选行后导出对应数据:
from PyQt6.QtWidgets import QMainWindow, QWidget, QHBoxLayout, QPushButton, QVBoxLayout from PyQt6.QtCore import QAbstractTableModel # 自定义模型,连接pandas数据和PyQt视图 class PandasTableModel(QAbstractTableModel): def __init__(self, df): super().__init__() self.df = df def rowCount(self, parent=None): return self.df.shape[0] def columnCount(self, parent=None): return self.df.shape[1] def data(self, index, role=Qt.ItemDataRole.DisplayRole): if role == Qt.ItemDataRole.DisplayRole: return self.df.iloc[index.row(), index.column()] return None def headerData(self, section, orientation, role=Qt.ItemDataRole.DisplayRole): if role == Qt.ItemDataRole.DisplayRole: if orientation == Qt.Orientation.Horizontal: return self.df.columns[section] return str(section + 1) return None def get_column_data(self, col_idx): return self.df.iloc[:, col_idx].tolist() # 主窗口,包含两个筛选表格和导出按钮 class DualWindowApp(QMainWindow): def __init__(self, df): super().__init__() self.df = df self.setWindowTitle("双窗口Excel筛选工具") self.resize(1200, 800) # 创建数据模型 self.data_model = PandasTableModel(df) # 创建左右两个筛选表格 self.left_table = FilterableTableView(self.data_model) self.right_table = FilterableTableView(self.data_model) # 设置多选模式 self.left_table.setSelectionMode(QTableView.SelectionMode.MultiSelection) self.right_table.setSelectionMode(QTableView.SelectionMode.MultiSelection) # 导出按钮 export_btn = QPushButton("导出选中行") export_btn.clicked.connect(self.export_selected) # 布局 central_widget = QWidget() main_layout = QVBoxLayout(central_widget) table_layout = QHBoxLayout() table_layout.addWidget(self.left_table) table_layout.addWidget(self.right_table) main_layout.addLayout(table_layout) main_layout.addWidget(export_btn) self.setCentralWidget(central_widget) def export_selected(self): # 获取左窗口选中行的源模型索引 left_proxy_indices = self.left_table.selectedIndexes() left_source_rows = list(set([self.left_table.proxy_model.mapToSource(idx).row() for idx in left_proxy_indices])) # 获取右窗口选中行的源模型索引 right_proxy_indices = self.right_table.selectedIndexes() right_source_rows = list(set([self.right_table.proxy_model.mapToSource(idx).row() for idx in right_proxy_indices])) # 导出选中数据 self.df.iloc[left_source_rows].to_excel("left_selected.xlsx", index=False) self.df.iloc[right_source_rows].to_excel("right_selected.xlsx", index=False) # 启动应用 if __name__ == "__main__": from PyQt6.QtWidgets import QApplication import sys app = QApplication(sys.argv) window = DualWindowApp(df) window.show() sys.exit(app.exec())
5. 性能优化建议
- 开启虚拟滚动:PyQt的
QTableView默认支持,确保只渲染可见行,避免加载30万条数据卡顿 - 数据预处理:加载时将数值列转为字符串,避免筛选时的格式匹配问题
- 筛选逻辑优化:用
QSortFilterProxyModel的内置正则筛选,比手动遍历数据效率高
替代方案(轻量场景)
如果不想用PyQt,也可以用Tkinter的ttk.Treeview配合自定义筛选逻辑,但处理30万条数据时,滚动和筛选的性能会比PyQt差一些,适合对性能要求不高的场景。
内容的提问来源于stack exchange,提问作者Kazeyoshi
相关产品推荐
相关产品推荐

