基于Python+PyQt5+Pandas编写的带图形界面的Excel合并工具

 更新时间:2026年01月12日 08:42:43   作者:weixin_46244623  
在日常办公或数据处理中,经常会遇到多个 Excel 文件需要合并的场景,手工复制不仅效率低,而且容易出错,本文将手把手教你使用 Python + PyQt5 + Pandas 编写一个带图形界面的 Excel 合并工具,需要的朋友可以参考下

引言

在日常办公或数据处理中,经常会遇到多个 Excel 文件需要合并的场景。手工复制不仅效率低,而且容易出错。

本文将手把手教你使用 Python + PyQt5 + Pandas 编写一个带图形界面的 Excel 合并工具,支持:

  • 选择文件夹
  • 自动读取多个 .xlsx 文件
  • 不同列自动对齐合并
  • 一键生成合并后的 Excel 文件
  • 自带程序图标(Base64 内嵌)

一、效果预览

功能说明:

  • 选择包含多个 .xlsx 文件的文件夹
  • 自动显示文件列表
  • 点击「合并 Excel 文件」
  • 在当前目录生成 合并.xlsx

二、环境准备

1、Python 版本

推荐:

Python 3.8+

2、安装依赖

pip install pyqt5 pandas openpyxl

说明:

库名用途
PyQt5GUI 图形界面
pandasExcel 数据处理
openpyxl读取 / 写入 xlsx

三、功能设计说明

1、合并逻辑说明

  • 逐个读取 Excel 文件
  • 自动收集 所有出现过的列
  • 不同文件中缺失的列自动补 NaN
  • 最终按列名对齐合并

示意:

文件
A.xlsx姓名、年龄
B.xlsx姓名、性别
合并结果姓名、年龄、性别

2、GUI 组件说明

组件功能
QLabel提示文本
QPushButton选择文件夹 / 合并
QFileDialog目录选择
QTableWidget文件列表
QMessageBox完成 / 错误提示

四、完整源码(可直接运行)

代码内嵌 Base64 图标,首次运行会自动生成 icon.png

import sys
import os
import pandas as pd
import base64
from PyQt5.QtWidgets import (
    QApplication, QWidget, QMessageBox, QPushButton,
    QFileDialog, QVBoxLayout, QLabel, QTableWidget, QTableWidgetItem
)
from PyQt5.QtGui import QIcon, QPixmap

Base64 图标处理

base64_icon = "data:image/png;base64,......(略)"
icon_data = base64_icon.split(',')[1]
icon_bytes = base64.b64decode(icon_data)

主窗口类

class ExcelMergerApp(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

初始化 UI

def initUI(self):
    self.setWindowTitle('xlsx多个文件合并')
    self.setGeometry(100, 100, 800, 500)

    if os.path.exists('icon.png'):
        self.setWindowIcon(QIcon('icon.png'))
    else:
        pixmap = QPixmap()
        pixmap.loadFromData(icon_bytes)
        self.setWindowIcon(QIcon(pixmap))
        pixmap.save('icon.png', 'PNG')

    self.info_label = QLabel('选择包含要合并的Excel文件的文件夹:')
    self.select_folder_button = QPushButton('选择文件夹')
    self.merge_button = QPushButton('合并Excel文件')
    self.folder_label = QLabel('')

    self.file_table = QTableWidget()
    self.file_table.setColumnCount(1)
    self.file_table.setHorizontalHeaderLabels(['文件列表'])

    layout = QVBoxLayout()
    layout.addWidget(self.info_label)
    layout.addWidget(self.select_folder_button)
    layout.addWidget(self.folder_label)
    layout.addWidget(self.file_table)
    layout.addWidget(self.merge_button)

    self.setLayout(layout)

    self.select_folder_button.clicked.connect(self.get_folder)
    self.merge_button.clicked.connect(self.merge_excel_files)

选择文件夹 & 显示文件列表

def get_folder(self):
    folder = QFileDialog.getExistingDirectory(self, "选择包含Excel文件的文件夹")
    if folder:
        self.folder_path = folder
        self.folder_label.setText(f'选择的文件夹: {folder}')
        self.populate_file_table()
def populate_file_table(self):
    files = [f for f in os.listdir(self.folder_path) if f.endswith('.xlsx')]
    files.sort()
    self.file_table.setRowCount(len(files))
    for i, f in enumerate(files):
        self.file_table.setItem(i, 0, QTableWidgetItem(f))

Excel 合并核心逻辑

def merge_excel_files(self):
    if not hasattr(self, 'folder_path'):
        QMessageBox.critical(self, '错误', '请先选择文件夹')
        return

    merged_df = pd.DataFrame()

    for row in range(self.file_table.rowCount()):
        file_name = self.file_table.item(row, 0).text()
        file_path = os.path.join(self.folder_path, file_name)
        df = pd.read_excel(file_path)

        for col in df.columns:
            if col not in merged_df.columns:
                merged_df[col] = None

        merged_df = pd.concat([merged_df, df], ignore_index=True)

    output_path = os.path.join(self.folder_path, '合并.xlsx')
    merged_df.to_excel(output_path, index=False)

    QMessageBox.information(self, '完成', f'合并完成,文件保存到:\n{output_path}')

程序入口

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = ExcelMergerApp()
    window.show()
    sys.exit(app.exec_())

完整代码

import sys
import os
import pandas as pd
from PyQt5.QtWidgets import QApplication, QWidget,QMessageBox, QPushButton, QFileDialog, QVBoxLayout, QLabel, QTableWidget, QTableWidgetItem
from PyQt5.QtCore import Qt,QByteArray
from PyQt5.QtGui import QIcon, QPixmap
import base64
base64_icon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAAAXNSR0IArs4c6QAAGhpJREFUeF7tXQuYXEWVPuf29ASi0aARITOJk751e4bwUAFBAdkQFgUURfGBIrKLorgioshDUWHBF0QEUUQWdVkFwVWUBXdVBIkKygLRFUjCTJ/qGWEIICJB2CFmuu/Z7wzd2UkymenHfdTtOfV984VMqs75z1/351bVrTqFoCVyBgYGBl44Pj6+MyIulB9m3pmZd0DE5wKA/Mxj5uci4rza3yd+BwAvqIFZDwBP1X+Y+SlEfHrS359GxEcRcaharQ6Vy+WhyINQgxMMoPLQHgNBEBSYeW9m3gsR9waAPQFgfntWm249zsxlRBwU0YRhOOR53uD4+PjQyMjII01b0wabGFCBNPkwFAqFIJfLLWfmgwBgGQC8uEkTSVd/HADuZuY7EfEuALiDiB5LGkRW/alAZui5QqGwOJfLHVwThIiiN6udPQn3amb+EQBcb61d1QHxxBaCCmQKaovF4oJqtfoPiPguAHhpbOy7YfghZr6uJpZb3YDkDgoVSK0v+vr6tsvn829i5mMB4DUAkHOnmxJDIkOv65n5h4sWLbp55cqVlcQ8O+potgsEfd9fhogiirfUVpIc7arEYf0JAC4DgEtn85xlVgrE932DiMcDwDEAsDjxRy9bDv/GzNcw85fK5fK92YLePtpZJZBCoXC453mnAsDy9qmbfRYQ8ZYwDL9orf3pbIm+4wWydOnS7o0bN8oQ6qMAsHS2dGzMca5GxAvz+fzVa9as2Rizr1TNd6xAjDHPA4APAsDJALBTqix3qHNmftjzvIuZ+etE9NdODLPjBNLX17dTPp8/lZnfr5PuxB7Zv4pIqtXqRZ325b5jBGKMmQMAnwCA0wFgu8QeDXU0mYENAPB5ADifiP7WCdR0hEB83z8SAC5CxL5O6JSsx8DMI4h4IhH9LOuxZFogAwMDfZVK5WsAcFjWO6JD8d/AzCdZax/ManyZFIisTI2Pj5/OzGfpcMr5R+8ZADivt7d3RRa/zGdOIEEQHMjM3wIA3/lHQwFuYoCZBwHgeGvtb7JES2YEstdee+XXr1+/AhE/nCWCFetWDFzY29t7ZlbeJpkQSG2ucf0s2Fk7W/R0ZxiGby2Xyw+4HrDzApEVKkT8Tu1oqut8Kr7GGXgSAN5NRDc03iT5ms4KRIZUTz755EW1r+HJM6Mek2Lg4u7u7jNc3bLipEB0SJXUs+mMn9/ncrmjBgcHh51BVAPinEB0SOXaI5IYHsni8i7XhlxOCcT3/XMR8VOJdYk6cpGBTxCRbFdxorgiEDTGXA4AJzjBioJIm4GvEpHswua0gaQukNr3jWsR8c1pk6H+3WEAEa/t6ek5Nu3vJakKZI899njO2NjYjQAg6XS0KANbMnDThg0bjhwdHZXtKqmU1AQi6TkrlcrPAeDlqUSuTrPCwJ2VSuW1IyMjko418ZKKQHzfX4SIvwAAk3jE6jCLDNyfz+eXr1279uGkwScuEN/3d0TEuwFgUdLBqr9MM2Cr1er+w8PDjyYZRaIC6evrm9/V1XUbAOyaZJDqq2MYuC+Xy+03ODgo30wSKYkJpJa58FfM/IpEIlMnHckAIt6Wz+cPTmprSlICyRlj/quW0rMjO06DSpSBG4joTQAQxu01EYH4vv9dRHxH3MGo/VnFwDeJ6L1xRxy7QHzfPx8RJdOIFmUgUgaY+Txr7acjNbqFsVgFEgTBicwsCZC1KANxMXASEV0al/HYBGKMkSsEJIdrbD7iIkXtZooBZuaDrbWx3G0Sy8NbLBZ7wjC8L4W7+jLVswo2MgYer1aru8bxjSRygSxbtqxrdHT0DgDYK7Lw1ZAyMDMDtxPRgVGvbEUuEJ2Uz9yTWiMeBuKYtEcqkNq8I/PpJuPpPrWaAAORz0ciE4jOOxLofnXRCAORzkciEYjOOxrpN62TIAORzUciEUgQBCuY+WMJEqCulIFpGUDEz5ZKpU+2S1PbAikUCgd4nvfrdoFoe2UgYgYYEV9VKpX+ux27bQmkdv/faj341E4XaNsYGSh1d3fv1s7O37YEoku6MXatmo6KAbnt6sxWjbUskCAIXsbMcjIw16pzbacMJMBAFQBeQUS/b8VXywIxxojDl7XiVNsoAwkz8Hsi2rMVny0JxBhzDABc1YpDbaMMpMSApDW9ulnfTQtEbpNl5mFE3LlZZ1pfGUiRgXUAUGj29t2mBeL7/lmI+JkUA43T9SoA2FEzrsRJcaq2zyKizzWDoCmBGGNeBAAjADC3GSeO170fAH7LzHdYa/+ljjUIgqOY+VQAeJXj+BVe4ww87XnekqGhoT832qQpgfi+f3EH3RH4OwA4lojWTEeW7/sfQ8QVjRKq9dxmABG/WCqVTmsUZcMC2WWXXXYeHx+XcVzWyzOI+JFSqSTZ5BsqxhhZR3cmJX9DoLXSthh4Jp/P+41maWxYIMaYKwAg9iwSMffrBmZ+nbVW0p42VYwx9wDA7k010squMiDXK3yoEXANCaS/v39JtVotN2LQ5TqIeEipVLq5FYy+7y9HxFtaaatt3GMgl8v1DA4OzjgiakggQRBcwswNKc49Kp5F1I446jEZY24HgP1cjVFxNcVAQ1tQZhRIf3//vGq1KgmDt2/KvTuVWx5WbRmCMeYUAJCbd7Vkn4GnxsbGdlq3bt3YdKHMKJAgCE5n5vMzykdk4pD4gyDYV5aDM8qFwt6CAVmRLZVKl7QlEN/312X0q/mGMAxfXy6XI5s31I4Vj+qT1jEMlInIb1kgxpi3AMD3M0jHRmY+rJXVquli1cNhGXwSZob8xumunp52iGWMuQkADpnZh1M1RBxvtNZKVsdIi340jJROV4z9mIiO2BaYbQqkUCgs9jxPtpXMOE9xJVIAiE0cEqMx5gcAcJRD8SqU9hkI8/l877Y+HG7z4TfGyKauj7fvPzELsYqjUCgUPc+7FwC6E4tIHSXFwNlEdO5UzqYTyCMA8OKkELbrh5kPt9b+pF0722pvjJFcw3p1XFwEp2v3QSJa3LBAfN8/qHYLbbqwG/QehuHryuWy3GAVSzHGfAUATorFuBp1hYFXEdFWS/hTvkF8378MEU90Bfk0OGIdVtXmHecAwNkZ4EIhtsfARUT00S1NTCUQNMY8DgA7tOcv9taxi0MT4sXehy45eISItjolu5VAMjK8UnG49Gh1DpathllbCcQY8yUA+IjLMScw55CzHy3nUnKZO8W2bQaYeYW1drP7NKd6g9yPiP2OEllh5iPi+AhYj1cn5I72fDKwVhPRbpNdbSaQJUuWvCSXy8nHQVfLtNsC2gW9cOHCuXPnzt2nXTvafisGdpT/6TKz/Mi5Gpcz4iwiok377TYTiDHmgwDwVQc7uCJfsKfbM+MgZoU0BQOFQuH5nudJcoy3uUgQM7/PWiunZyfKlgK5EQBe7yDwI4noPxzEpZBaZMD3/eMQ8coWm8fZ7Doikk26UwrkKQB4bpzem7Vd25Ub+cbDZnFo/egZMMbId4cLo7fclsXHiWjBVgLxfX83RJS9Ri6VU4lIVtW0dCgDxphfAoDcTutMCcOwv1wuD202xPJ9/wRE3JQ4zQG0JSIqOoBDIcTIQG3XuOxzmxejm6ZMM/Nx1tpvbyYQY8y3AOAfm7IUY2Vm/qS19rMxulDTjjBgjLkWAN7uCByBcRkR/dOWApEMg7s4BPJQItIrpR3qkLigGGO+AABnxGW/Bbt/IKKJqz0mVrFq6///24KhOJtMubsyTodqOx0GgiA4kZkvS8f71F43bNgwd3R09JkJgRSLxX3CMGzrssMYglOBxECqiyaDIDiZmb/sEjZm3ttau2pCIMaY9wDAN1wCKFnVp9qf7xhGhRMBA8YYmRAfG4GpyEwg4vGlUulfJwTi+/6XEfHkyKxHY+gNRCQfLrV0OAOOntacOB9Sf4NIMueDHOuHK4jofY5hUjgRM1AsFl8dhuGvIjbbtjlmvtlae0hdIA/JXL1tq9Ea2JDL5fxGEgxH61atJcmAMaYko/wkfTboa5SIFmFvb+/222233bT5SRs0GEe1W4loeRyG1Wb6DBhjnD7OTESIxWJxIAzDtenTNTUCZr7GWvtOV/EprtYYMMZ8AAC+1lrrZFoxc4BBELyemV2fDN+NiO8ulUrOCjmZLsu+l9qeP1kx3df1aOTKDEnQ4OoZkKn4k1SovwUAuV/wr64TrPieZQARl4RhuC8i7g8Am53Yc5yjE9D3/XMR8VOOA1V4ykAaDJwjbxAZB8p4UIsyoAxMYoCZLxGBfM/V44/aW8pAygxcLQKRC2Z0KTXlnlD3TjLwUxHI/wDAS52Ep6CUgRQZQMS7RCAWAAop4lDXyoCrDKwVgUgOoB5XESouZSBFBsoikD8BwItSBKGulQFXGRgVgTwJAM9zFaHiUgZSZOAxEcgzALBdiiDUtTLgKgNPikDkLPpcVxEqLmUgRQaeEoE8AQDzUwShrpUBVxn4swjkUQDY0VWEiksZSJGBh0QgDwJAb4og1LUy4CoDE8u8JHkbXEWouJSBFBmY+FCoW01S7AF17TQDd+pmRaf7R8GlzMBPRCD/DgBvTRmIulcGXGTgKjlReBkinugiOsWkDKTJgKRDFYGch4ifTBOI+lYGXGQAET8tQyzn069MIu87zCwHvEpdXV33Dg4OypVxDZe+vr7tKpXKRLK8MAwn/lywYAHWf1etVid+J3/W/33yn/Pmzdv073Ub9X9n5k126/+9/fbbb/W7yfXr9eTPOXPmTNSdys7kevWM/Pl8flP9Lf5dzOCWv5O/T24zyddmfmvtJn7X1dW1lY+6/8n16r6k/lRYar7mI6JcKSAZPJ26UWpbD5CMrOQNcigi/qThpyydik8w83ustT9Kx716jZIBY8yeAPBNAJi4g8PVIvdjOp84DgDWep53yNDQkKRH1dJBDBhjrgeAN7oakud5u7ieehQ8z3vZ0NDQH1wlUXG1zoAMebu6um4FgFe2biW+lnKJTj159SMA8OL4XLVmGRHPKJVKF7TWWltlgYH+/v4l1Wq17CDWR4lop7pAbgMAyXrnVJHkwU4BUjCxMBAEwTXMfHQsxls3+ksiWla/QOfriPj+1m1F35KZf22tzcRqR/TRzy6Lvu8fjYjXOBb1pUR0Ul0gH0LESxwD+DkiOssxTAonBgYKhcIBnuf9OgbTLZtExA+USqWv1wVyECLKLVPOFEQ8olQq/dgZQAokNgZcFEgYhq8ul8u31QWyIyLKwSlnCjMfZ62Vyx21dDgDLgqkUqnsMDIysn7TJNgY8wAALHKlLxDxK6VSybWLRV2hp6NwGGOOAIAbXAmKmUestUsEzyaBBEFwpfxf2yGQOkl3pTNixuH7/vmIeHrMbpoxfxURTVxLvUkgvu8fh4hXNmMl7rphGL6iXC7fHbcftZ8uA77vr0PEndNF8f/eZQ9WqVS6fDOBFIvFnjAMJQ2pS2UNEe3qEiDFEi0DQRCsYOaPRWu1bWu7EtGazQQif3H0fLou97bd324aCILgKGb+gWPoHieiBXVMm32pNsZcAQDvdQwwI+IV1Wr19HK5LGlStXQAA8aYYwBAVik9x8K5jojeMqVAgiB4BzN/1zHAdTiyDH1atVr91fDw8B8dxaiwGmDA0S/ndeTvJSLZij9RNnuD9PX17dTV1fVwAzG6UEVuum3qwJQLoF3GwMz3W2tjPX7tuDggn88vXLt27SYNbLUZ0Bgjd5EPuNyRii0WBobz+fz+kx+OqL0YY2Toci0A5KK2HZG9+4ho98m2phLIVwFA7k7XMnsYGGXm/ay1kmUzluL7/tsRUcThbGHmC6y1Z0wrkCAIDmHmm5yNQoFFygAzP9zV1bX/4ODgcKSGJxnLwJtjAi0z72+t/c20ApF5iTFGDlBpQuu4nhh37P4lDMNXlsvlUlyQsiIOAJg4ILUlD1MeSHLw039c/Teb7T5ZrVYPHB4evicuEjIkDnl7fNlae0pDAjHGLAWA1XERp3adYOBQIvpZXEiyJI7a8OoAa+3tDQlEKhljZA/UXnERqHZTZeCbRBTbB+GaOL6faoTNOR8loil3sm/zzHcQBCfLa6c5P1o7Aww8MHfu3KX33HOPXL0Xecnam6NGwDlE9M9TkbFNgSxevHiH7u7uxxxes468c2eJwXOJ6Ow4YjXGvAEAfpixZyasVCo9IyMjsjC1VZk2a4gxRg6xyGEWLZ3DwNuIKPLhT00c10nG0oxR9WMi2uYzPq1AHN1tmTH+3YKLiEtLpZLsloisZFgcwsEbiOjGbZExrUCWLVvWNTo6Kh+Q9A7DyB6ndA0x8+7W2vuiQpFxcfyRiAqSy7wlgUijIAhOk0/wURGqdlJn4FgiuioKFBkXh1DwHiL61nRczJi5sL+/f161WpUJzNwoSFUbqTNwIRG1fYIv6+KQLTaLFi1avHLlykpbApHGxpiLAGCrr4ypd7UCaIWBR3K5XLHZu1UmO8q6OCQWZv6QtVY25k5bZnyDSOtCobDY8zw9pDQTm9n594uI6KOtwDXGyHUFcm1BlsuU+66mCqghgUhD3/edy9+b5R5KGXs1DMOXl8vle5vB0QlvDolXUgyVSqUVjcTesED6+/sXVqtVvcSmEVazUed+RHxzo0u+vu+7mL+5Fab/0t3d/ZI1a9Y83UjjhgVSm4t8CQA+0ohhrZMJBjYw82nTjcUHBgZeWKlUZNXr0ExENDPIs4no3JmrPVujKYEUi8UFYRjKXERXtBplOBv1VjHz3Yg4xMxrEfEFAFAEgH4AOFjuOs1GGDOifLpSqSySnLsz1qxVaEog0iYIgk8xc8MKbBSI1lMGEmDgTCI6vxk/TQukdq8cAUBPM460rjKQJgPMPDh//vzdV61aNd4MjqYFIsZdzOPbTNBad/YxMNV580ZYaEkgkg3PGCM3z+7WiBOtowykzMCmbO3N4mhVIDIX2ZeZf9vsRL9ZgFpfGWiTgac8zysMDQ39uRU7LQtEnBljdNm3Fda1TZIMnEREl7bqsC2B9Pb2bj9nzpw1iNjXKgBtpwzEyMC9RPRS2XrVqo+2BCJOgyA4kJl/2SoAbacMxMQAh2G4T7sXMLUtkNqq1gWIeFpMgapZZaAVBr5ARB9vpeHkNpEIpHbyUHIK7dMuIG2vDETAwO1EdOB0JwUb9RGJQGoTdjmWK7tD5zfqXOspAzEw8Hi1Wt11eHg4kmvNIxOIBFooFA73PO8/YwhaTSoDDTHAzMuttbc2VLmBSpEKpPYmuRAAWjqM0wBeraIMTMfA+UR0ZpQURS4QnY9E2T1qq1EGEPGunp6e/WY6Y96ovXq9yAWi85Fmu0DrR8DAes/zdhsaGor8QF8sAtH5SARdriYaZoCZD7PW/rThBk1UjE0ggsH3/bMQ8TNN4NGqykBTDCDiKaVSKbYk67EKpDbc0jsPm+pyrdwoA8y8wlp7eqP1W6kXu0BqV7p9DwDe2gpAbaMMTMUAM19jrX1n3OwkIRCorWxJguBOOfgfd7+o/ekZuImIDgeAatxEJSIQCaJ2VFc2Nep2lLh7tYPty3Lu+Pj4gSMjIxuSCDMxgdREMj+Xy92BiJItQ4sy0CwDqyuVygHNZCVp1sGW9RMViDivJaC7CwAWtgte288qBh5k5r2ttX9KMurEBSLBDQwM9FUqlZ/LocQkg1VfmWXAAsAyIhpNOoJUBFITiWTsE5G8POmg1V+mGLh7zpw5r129evVf0kCdmkAk2D322OM5Y2Njcunja9IIXn26zQAz31ytVo9IakI+FRupCkQAyRLwQw899B1mPtrt7lJ0CTNwNREdl8RS7nRxpS6QGjj0ff8LkpY+4U5Qd24yEPm29VbDdEUgE/h93z8JES/RXFutdmfm20n2kQ8S0WWuROKUQGoiOQwRJd2+ZBjXMnsYeIKZj4ryNGAU1DknEAmqWCz2hGEok3f96h5FL7tv4458Pv/mtWvXPuwaVCcFMmny/nlmbvtGVtdIVzybGGBm/qK1VtLzxL6vqhXenRVIPRjf92XIdQ0APL+VALWNsww8AQBHE9FNziLMymS4dsvu93XI5fKj1BS2Vfl8/ggXh1RbRuH8G6QOuLZl/gK9I7GpB9G1yoyIF/b09Hw86uQKcQWaGYFMGnIdhIiXS1rguEhRu9EzIDc8AcDx1trfRG89PouZE4hQsXTp0u6NGzd+AgBkctcdHz1qOQIGngGAz/T29l6QlbfG5JgzKZB6AIVCIfA87woA+LsIOlJNRMwAM0uWzQ9Yax+M2HRi5jItkEnDruNkbAsAL0yMOXU0HQNlmSsS0Q1Zp6kjBCKd0NfXN7+rq0v2cp0MAM/JesdkFL8Mp+SaZbl64G8ZjWEz2B0jkHpUxWJxATN/mpnfr/OTxB7RCgBc6XneOXFkN0wsiikcdZxAJglFtqucBwDvBoBcmiR3sG/5En5tV1fXWYODg8OdGGfHCqTeWbXjvR8GgBN06BXpI/xtALiAiFZHatUxYx0vkDrfxpjnyTp8bY6yxLF+yAqc9QBweaVSuXhkZOSRrIBuB+esEchkkoIgOAoATmHmA9ohbxa1/R0AfGNsbOzf1q1bNzaL4oZZKZB6BxcKhaLnecfIpjnZZT+bOr6BWB9n5quZ+Rvlclmu1puVZVYLZHKPG2P2RMR3MPPbAWDRrHwaAB4DgOuZ+Yfz58+/ZdWqVeOzlIdNYatApngCane/HwkAfw8Au3f4QyKT7J8BwI1EtLLDY206PBXIDJQNDAxI/q7lzHywJGHJetpUZh5BxFuZ+SZEvIWI5K2hZRsMqECafDRqqVMPlttUEXE5ACxu0kTS1WW16Rfyk8vlftGp3yviIlUF0iazxpgXhWHY73negLxdmFkSc8tP0pN+y8z3I+KQ/Mh/53K5ocHBwXVthjirm6tAYuz+YrE4IOJBxCIzy5tmZ0nazcw7I2JfM65rQyNJaiAP/MOI+AAzT4ihVCqtbcaW1m2cgf8DkV/jh6DyaVEAAAAASUVORK5CYII="
icon_data = base64_icon.split(',')[1]
icon_bytes = base64.b64decode(icon_data)
class ExcelMergerApp(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setWindowTitle('xlsx多个文件合并')
        self.setGeometry(100, 100, 800, 500)
        if os.path.exists('icon.png'):
            icon = QIcon('icon.png')
            self.setWindowIcon(icon)
        else:
             # 将字节数据转换为 QPixmap
            pixmap = QPixmap()
            pixmap.loadFromData(icon_bytes)

            # 创建 QIcon 并将其设置为窗口图标
            icon = QIcon(pixmap)
            self.setWindowIcon(icon)
            pixmap.save('icon.png', 'PNG')
        

        self.info_label = QLabel('选择包含要合并的Excel文件的文件夹:')
        self.select_folder_button = QPushButton('选择文件夹')
        self.merge_button = QPushButton('合并Excel文件')

        self.folder_label = QLabel('')
        
        self.file_table = QTableWidget()
        self.file_table.setColumnCount(1)
        self.file_table.setHorizontalHeaderLabels(['文件列表'])

        layout = QVBoxLayout()
        layout.addWidget(self.info_label)
        layout.addWidget(self.select_folder_button)
        layout.addWidget(self.folder_label)
        layout.addWidget(self.file_table)
        layout.addWidget(self.merge_button)
        layout.addStretch()  
        self.setLayout(layout)

        self.select_folder_button.clicked.connect(self.get_folder)
        self.merge_button.clicked.connect(self.merge_excel_files)

    def get_folder(self):
        folder = QFileDialog.getExistingDirectory(self, "选择包含Excel文件的文件夹")
        if folder:
            self.folder_path = folder
            self.folder_label.setText(f'选择的文件夹: {folder}')
            self.populate_file_table()

    def populate_file_table(self):
        file_names = [file for file in os.listdir(self.folder_path) if file.endswith(".xlsx")]
        file_names.sort()  # Sort the file names
        self.file_table.setRowCount(len(file_names))
        for i, file_name in enumerate(file_names):
            item = QTableWidgetItem(file_name)
            self.file_table.setItem(i, 0, item)

    def merge_excel_files(self):
        if hasattr(self, 'folder_path'):
            # 添加您在上面的代码中执行的Excel文件合并操作
            unique_columns = pd.DataFrame()
            for row in range(self.file_table.rowCount()):
                file_name = self.file_table.item(row, 0).text()
                file_path = os.path.join(self.folder_path, file_name)
                df = pd.read_excel(file_path)
                file_columns = df.columns
                for column in file_columns:
                    if column not in unique_columns.columns:
                        unique_columns[column] = None
                unique_columns = pd.concat([unique_columns, df[file_columns]], ignore_index=True)

            # 保存合并后的数据到output.xlsx文件,包括列名
            output_file = "合并.xlsx"
            output_file_path = os.path.join(self.folder_path, output_file)
            unique_columns.to_excel(output_file_path, index=False)
            msg = QMessageBox()
            icon = QIcon("icon.png")
            msg.setWindowIcon(icon)
            msg.setIcon(QMessageBox.Information)
            msg.setText(f'合并完成,结果保存到 {output_file_path}')
            msg.setWindowTitle('合并完成')
            msg.exec_()
        else:
            msg = QMessageBox()
            icon = QIcon("icon.png")
            msg.setWindowIcon(icon)
            msg.setIcon(QMessageBox.Critical)
            msg.setText('请选择文件夹以合并Excel文件')
            msg.setWindowTitle('错误')
            msg.exec()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = ExcelMergerApp()
    ex.show()
    sys.exit(app.exec_())

到此这篇关于基于Python+PyQt5+Pandas编写的带图形界面的Excel合并工具的文章就介绍到这了,更多相关Python PyQt5 Excel合并工具内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Python返回真假值(True or False)小技巧

    Python返回真假值(True or False)小技巧

    这篇文章主要介绍了Python返回真假值(True or False)小技巧,本文探讨的是最简洁的条件判断语句写法,本文给出了两种简洁写法,需要的朋友可以参考下
    2015-04-04
  • Python使用XPath进行正则表达式匹配的实战指南

    Python使用XPath进行正则表达式匹配的实战指南

    在Web自动化测试和数据抓取中,我们经常遇到动态生成的HTML属性,传统XPath定位方式容易因这些变化而失效,下面我们就来看看Python中如何运用XPath正则匹配吧
    2026-04-04
  • python 限制函数调用次数的实例讲解

    python 限制函数调用次数的实例讲解

    下面小编就为大家分享一篇python 限制函数调用次数的实例讲解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-04-04
  • Python对列表进行排序的5种实现方式

    Python对列表进行排序的5种实现方式

    这篇文章介绍了五种在Python中进行排序的方法,包括sort()方法、sorted()函数、lambda表达式作为key参数进行排序、operator模块进行排序以及numpy模块进行排序,每种方法都有其适用的场景和优势,可以根据具体需要选择最合适的方法
    2025-12-12
  • python绘制散点图详细步骤(从0到1必会)

    python绘制散点图详细步骤(从0到1必会)

    这篇文章主要介绍了如何使用Python绘制散点图,包括导入包、准备数据、绘制图像、修饰图像(添加标题、坐标轴标签、颜色图例)以及整合所有代码,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-12-12
  • 经验丰富程序员才知道的15种高级Python小技巧(收藏)

    经验丰富程序员才知道的15种高级Python小技巧(收藏)

    本文将介绍15个简洁的Python技巧,向着简洁更高效,学习易懂出发,具说只有经验丰富程序员才知道的15种高级Python小技巧,喜欢的朋友快来看看吧
    2021-10-10
  • Python中的pynput使用方法

    Python中的pynput使用方法

    pynput是一个Python 库,用于监控和控制输入设备,如键盘和鼠标,本文通过一个简单的示例,展示如何使用pynput控制鼠标,本文结合实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧
    2026-02-02
  • Python中requests、aiohttp、httpx性能比拼

    Python中requests、aiohttp、httpx性能比拼

    本文主要介绍了Python中requests、aiohttp、httpx性能比拼,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06
  • Python 高级专用类方法的实例详解

    Python 高级专用类方法的实例详解

    这篇文章主要介绍了Python 高级专用类方法的实例详解的相关资料,希望通过本文大家能够掌握这部分内容,需要的朋友可以参考下
    2017-09-09
  • Python 利用argparse模块实现脚本命令行参数解析

    Python 利用argparse模块实现脚本命令行参数解析

    这篇文章主要介绍了Python 利用argparse模块实现脚本命令行参数解析,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-12-12

最新评论