Python & PyQt5 实现 .his 文件批量转 Excel 工具

在数据分析和处理过程中,数据格式的多样性常常带来不同的技术挑战。例如,历史数据或日志数据可能存储在 .his 格式的文件中。为了便于分析和操作,我们通常需要将这些文件转为更常见的表格格式如 Excel 文件(.xlsx)。在本文中,我们将介绍一个基于 Python 和 PyQt5 的 GUI 工具,展示如何实现 .his 文件到 Excel 的批量转换,并实现动态 UI 美化和多线程功能。

功能特点

  • 支持单个文件或文件夹批量转换 :用户可以选择单个 .his 文件或包含多个 .his 文件的文件夹进行批量转换。
  • 动态 UI 美化:使用随机颜色和渐变背景实现界面美化,增强用户体验。
  • 进度条显示和日志更新:转换过程中,进度条实时更新,且日志输出转换结果和状态信息。
  • 多线程支持:避免阻塞 UI 界面,提高程序响应速度。

pandas 用于处理表格数据和生成 Excel 文件,而 PyQt5 用于实现 GUI 界面。

核心代码解析

以下是项目的完整代码,并逐步讲解关键部分。

1. UI 美化类 UIStyler

首先,我们定义了一个用于美化界面的类 UIStyler,通过随机颜色和渐变背景实现一个视觉吸引力的用户界面。

import random

class UIStyler:
    def __init__(self, widget):
        self.widget = widget
        self.apply_styles()

    def apply_styles(self):
        colors = ["#3498db", "#2ecc71", "#e74c3c", "#9b59b6", "#e67e22"]
        random_color = random.choice(colors)

        self.widget.setStyleSheet(f"""
            QWidget {{
                background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1, stop:0 {random_color}, stop:1 #ffffff);
            }}
            QLabel {{
                color: {random_color};
                font-size: 18px;
                font-weight: bold;
            }}
            QPushButton {{
                background-color: {random_color};
                color: white;
                border-radius: 8px;
                padding: 8px;
            }}
            QPushButton:hover {{
                background-color: #2980b9;
            }}
            QProgressBar {{
                border: 2px solid #dce4ec;
                border-radius: 5px;
                background: white;
                color: black;
            }}
            QProgressBar::chunk {{
                background-color: {random_color};
                width: 20px;
            }}
            QTextEdit {{
                border: 2px solid {random_color};
                background-color: #f0f8ff;
                color: black;
            }}
        """)

2. 数据转换类 ConverterThread

ConverterThread 使用 QThread 实现多线程操作,保证文件转换过程不会阻塞 UI 界面。通过 log_messageprogress 信号,我们可以在 UI 中实时更新日志和进度条状态。

from PyQt5 import QtCore
import pandas as pd

class ConverterThread(QtCore.QThread):
    progress = QtCore.pyqtSignal(int)
    log_message = QtCore.pyqtSignal(str)

    def __init__(self, input_path, output_folder, is_single_file):
        super().__init__()
        self.input_path = input_path
        self.output_folder = output_folder
        self.is_single_file = is_single_file

    def run(self):
        if self.is_single_file:
            self.convert_single_his_to_excel(self.input_path)
        else:
            self.convert_folder_his_to_excel(self.input_path)

    def convert_single_his_to_excel(self, his_file):
        if not os.path.exists(self.output_folder):
            os.makedirs(self.output_folder)

        excel_file_path = os.path.join(self.output_folder, os.path.basename(his_file).replace('.his', '.xlsx'))
        try:
            with open(his_file, 'r', encoding='utf-8') as file:
                lines = file.readlines()

            header = lines[1].strip().split('\t')
            data = [line.strip().split('\t') for line in lines[2:]]
            df = pd.DataFrame(data, columns=header)

            df.to_excel(excel_file_path, index=False)
            self.log_message.emit(f"已转换: {his_file} -> {excel_file_path}")
        except Exception as e:
            self.log_message.emit(f"转换 {his_file} 失败: {e}")

    def convert_folder_his_to_excel(self, input_folder):
        files = [f for f in os.listdir(input_folder) if f.endswith('.his')]
        total_files = len(files)

        for i, filename in enumerate(files):
            his_file_path = os.path.join(input_folder, filename)
            self.convert_single_his_to_excel(his_file_path)
            progress_value = int((i + 1) / total_files * 100)
            self.progress.emit(progress_value)

3. 主界面类 HISConverterUI

HISConverterUI 是主界面类,包含文件选择、日志显示、进度条等界面元素。它负责与用户的交互。

from PyQt5 import QtWidgets, QtCore
from PyQt5.QtWidgets import QFileDialog, QMessageBox, QVBoxLayout, QHBoxLayout, QLabel, QProgressBar, QTextEdit

class HISConverterUI(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        self.setWindowTitle('HIS文件转Excel工具')
        self.setGeometry(100, 100, 500, 600)

        main_layout = QVBoxLayout()
        self.title_label = QLabel('HIS 文件转换工具', self)
        self.title_label.setAlignment(QtCore.Qt.AlignCenter)
        self.title_label.setStyleSheet("font-size: 18px; font-weight: bold; margin-bottom: 20px;")
        main_layout.addWidget(self.title_label)

        btn_layout = QHBoxLayout()
        self.select_file_btn = QtWidgets.QPushButton('选择单个文件')
        self.select_file_btn.clicked.connect(self.select_file)
        btn_layout.addWidget(self.select_file_btn)

        self.select_folder_btn = QtWidgets.QPushButton('选择文件夹')
        self.select_folder_btn.clicked.connect(self.select_folder)
        btn_layout.addWidget(self.select_folder_btn)

        main_layout.addLayout(btn_layout)

        self.progress_bar = QProgressBar(self)
        main_layout.addWidget(self.progress_bar)

        self.his_file_list = QTextEdit(self)
        self.his_file_list.setReadOnly(True)
        main_layout.addWidget(self.his_file_list)

        self.convert_btn = QtWidgets.QPushButton('开始转换')
        self.convert_btn.clicked.connect(self.start_conversion)
        main_layout.addWidget(self.convert_btn)

        self.add_footer_info(main_layout)

        self.setLayout(main_layout)
        self.ui_styler = UIStyler(self)

        self.input_path = ''
        self.output_folder = './output'
        self.is_single_file = False
        self.thread = None

    def select_file(self):
        file_path, _ = QFileDialog.getOpenFileName(self, "选择一个.his文件", "", "HIS Files (*.his);;All Files (*)")
        if file_path:
            self.input_path = file_path
            self.is_single_file = True
            self.his_file_list.clear()
            self.his_file_list.append(f"已选择文件: {file_path}")
            QMessageBox.information(self, "文件选择", f"已选择文件: {file_path}")

    def select_folder(self):
        folder_path = QFileDialog.getExistingDirectory(self, "选择文件夹")
        if folder_path:
            self.input_path = folder_path
            self.is_single_file = False
            self.show_his_files_in_folder(folder_path)

    def start_conversion(self):
        if self.input_path:
            self.progress_bar.setValue(0)
            self.thread = ConverterThread(self.input_path, self.output_folder, self.is_single_file)
            self.thread.progress.connect(self.update_progress)
            self.thread.log_message.connect(self.append_log)
            self.thread.start()
            QMessageBox.information(self, "转换进行中", "文件转换已开始!")
        else:
            QMessageBox.warning(self, "警告", "请先选择文件或文件夹!")

    def update_progress(self, value):
        self.progress_bar.setValue(value)

    def append_log(self, message):
        self.his_file_list.append(message)

    def add_footer_info(self, layout):
        self.footer_label = QLabel(self)
        self.footer_label.setText("版权所有 © 2024 贵州安然智行科技有限责任公司\n联系方式: gzarzx@163.com | 电话: +085183865795")
        self.footer_label.setAlignment(QtCore.Qt.AlignCenter)
        self.footer_label.setStyleSheet("font-size: 12px; color: black; padding: 2px;")
        layout.addWidget(self.footer_label)

总结

本文提供了一个完整的 .his 文件批量转换为 Excel 工具,并通过动态美化、进度显示、多线程等技术提升了用户体验。希望该工具能为您的数据处理工作提供便利。

相关推荐
versatile_zpc9 分钟前
C++初阶:类和对象(上)
开发语言·c++
尘浮生10 分钟前
Java项目实战II基于微信小程序的移动学习平台的设计与实现(开发文档+数据库+源码)
java·开发语言·数据库·spring boot·学习·微信小程序·小程序
娅娅梨1 小时前
C++ 错题本--not found for architecture x86_64 问题
开发语言·c++
汤米粥1 小时前
小皮PHP连接数据库提示could not find driver
开发语言·php
冰淇淋烤布蕾1 小时前
EasyExcel使用
java·开发语言·excel
拾荒的小海螺1 小时前
JAVA:探索 EasyExcel 的技术指南
java·开发语言
秀儿还能再秀1 小时前
机器学习——简单线性回归、逻辑回归
笔记·python·学习·机器学习
马剑威(威哥爱编程)2 小时前
哇喔!20种单例模式的实现与变异总结
java·开发语言·单例模式
白-胖-子2 小时前
【蓝桥等考C++真题】蓝桥杯等级考试C++组第13级L13真题原题(含答案)-统计数字
开发语言·c++·算法·蓝桥杯·等考·13级
好睡凯2 小时前
c++写一个死锁并且自己解锁
开发语言·c++·算法