You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 10:14:58