Office转PDF转换器v1.0.py

发布于:2025-09-16 ⋅ 阅读:(17) ⋅ 点赞:(0)

软件介绍

这是批量将word、Excel、PPT转换为PDF格式的软件,不过PPT转换为PDF需要电脑安装了office,目前这个我还没有解决没有office也可以安装的方法。

在这里插入图片描述

软件使用

软件使用是比较简单的,导入文件/文件夹,在自定义输出路径
在这里插入图片描述
点击这里的【分析文件】
在这里插入图片描述
然后就可以转换了
在这里插入图片描述
转换完成
在这里插入图片描述

软件源码

我吧软件源码也一起放在这里了,如果有大佬可以解决不安装office也可以将PPT转换为PDF的话欢迎在评论区留下你的代码
当然,为了防止小白不懂怎么打包,我也将成品放在文末了。

import os
import sys
import gc
import time
import pythoncom
import win32com.client
from PyQt5.QtWidgets import (QApplication, QMainWindow, QPushButton, QLabel, 
                            QLineEdit, QTextEdit, QVBoxLayout, QHBoxLayout, 
                            QWidget, QFileDialog, QProgressBar, QMessageBox,
                            QGroupBox, QFormLayout, QListWidget,
                            QListWidgetItem, QMenu, QAction)
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QObject
from PyQt5.QtGui import QFont, QColor


class ConversionWorker(QObject):
    """转换工作线程,负责后台执行转换任务"""
    progress_updated = pyqtSignal(int, str)  # 进度更新信号 (进度值, 状态文本)
    conversion_finished = pyqtSignal(str)    # 转换完成信号 (完成消息)
    log_message = pyqtSignal(str)            # 日志消息信号

    def __init__(self, file_items, output_path):
        super().__init__()
        self.file_items = file_items  # 包含路径和文件名的字典列表
        self.output_path = output_path
        self.is_running = True

    def stop(self):
        """停止转换任务"""
        self.is_running = False

    def run(self):
        """执行转换任务"""
        try:
            # 初始化COM组件
            pythoncom.CoInitialize()
            
            # 确保PDF文件夹存在
            pdf_folder = self.output_path
            if not os.path.exists(pdf_folder):
                os.makedirs(pdf_folder)
                self.log_message.emit(f"已创建PDF文件夹: {pdf_folder}")

            # 分类文件
            words = []
            excels = []
            ppts = []
            
            for item in self.file_items:
                file_path = item['path']
                filename = item['name']
                lower_filename = filename.lower()
                
                if lower_filename.endswith(('.doc', '.docx')):
                    words.append({"path": file_path, "name": filename})
                elif lower_filename.endswith(('.xls', '.xlsx')):
                    excels.append({"path": file_path, "name": filename})
                elif lower_filename.endswith(('.ppt', '.pptx')):
                    ppts.append({"path": file_path, "name": filename})

            total_files = len(words) + len(excels) + len(ppts)
            processed_files = 0
            
            # 初始化转换统计变量
            word_success, word_failed = 0, 0
            excel_success, excel_failed = 0, 0
            ppt_success, ppt_failed = 0, 0
            
            # 转换Word文件
            if words and self.is_running:
                self.log_message.emit("\n【开始 Word -> PDF 转换】")
                word_success, word_failed = self.convert_words(words)
                processed_files += len(words)
                progress = int((processed_files / total_files) * 100) if total_files > 0 else 100
                self.progress_updated.emit(progress, f"已完成Word转换: {word_success}成功, {word_failed}失败")

            # 转换Excel文件
            if excels and self.is_running:
                self.log_message.emit("\n【开始 Excel -> PDF 转换】")
                excel_success, excel_failed = self.convert_excels(excels)
                processed_files += len(excels)
                progress = int((processed_files / total_files) * 100) if total_files > 0 else 100
                self.progress_updated.emit(progress, f"已完成Excel转换: {excel_success}成功, {excel_failed}失败")

            # 转换PPT文件
            if ppts and self.is_running:
                self.log_message.emit("\n【开始 PPT -> PDF 转换】")
                ppt_success, ppt_failed = self.convert_ppts(ppts)
                processed_files += len(ppts)
                progress = int((processed_files / total_files) * 100) if total_files > 0 else 100
                self.progress_updated.emit(progress, f"已完成PPT转换: {ppt_success}成功, {ppt_failed}失败")

            if self.is_running:
                total_success = word_success + excel_success + ppt_success
                total_failed = word_failed + excel_failed + ppt_failed
                self.conversion_finished.emit(
                    f"转换完成!\n总计: {total_files}个文件\n成功: {total_success}个\n失败: {total_failed}个\nPDF文件保存位置: {self.output_path}"
                )
            else:
                self.conversion_finished.emit("转换已取消")
                
        except Exception as e:
            self.log_message.emit(f"转换过程出错: {str(e)}")
            self.conversion_finished.emit(f"转换出错: {str(e)}")
        finally:
            # 释放COM组件
            pythoncom.CoUninitialize()
            gc.collect()

    def convert_words(self, words):
        """转换Word文件为PDF"""
        success = 0
        failed = 0
        word = None
        doc = None
        
        try:
            self.log_message.emit("打开Word进程...")
            word = win32com.client.Dispatch("Word.Application")
            word.Visible = 0
            word.DisplayAlerts = False
            
            for i, item in enumerate(words):
                if not self.is_running:
                    break
                    
                filename = item["name"]
                file_path = item["path"]
                self.log_message.emit(f"正在转换: {filename} ({i+1}/{len(words)})")
                from_file = os.path.join(file_path, filename)
                to_filename = self.change_suffix_to_pdf(filename)
                to_file = self.to_file_join(self.output_path, to_filename)
                
                try:
                    doc = word.Documents.Open(from_file)
                    doc.SaveAs(to_file, 17)  # 17 表示PDF格式
                    self.log_message.emit(f"转换完成: {to_filename}")
                    success += 1
                except Exception as e:
                    self.log_message.emit(f"转换失败 {filename}: {str(e)}")
                    failed += 1
                finally:
                    if doc:
                        doc.Close()
                        doc = None
                        time.sleep(0.5)
                        
        except Exception as e:
            self.log_message.emit(f"Word转换出错: {str(e)}")
            failed += len(words) - success
        finally:
            if doc:
                try:
                    doc.Close()
                except:
                    pass
            if word:
                try:
                    word.Quit()
                except:
                    pass
            self.log_message.emit("关闭Word进程")
            time.sleep(1)
            
        return success, failed

    def convert_excels(self, excels):
        """转换Excel文件为PDF"""
        success = 0
        failed = 0
        excel = None
        wb = None
        ws = None
        
        try:
            self.log_message.emit("打开Excel进程...")
            excel = win32com.client.Dispatch("Excel.Application")
            excel.Visible = 0
            excel.DisplayAlerts = False
            
            for i, item in enumerate(excels):
                if not self.is_running:
                    break
                    
                filename = item["name"]
                file_path = item["path"]
                self.log_message.emit(f"正在转换: {filename} ({i+1}/{len(excels)})")
                from_file = os.path.join(file_path, filename)
                
                try:
                    wb = excel.Workbooks.Open(from_file)
                    sheet_count = wb.Worksheets.Count
                    
                    for j in range(sheet_count):
                        ws = wb.Worksheets(j+1)
                        to_filename = self.add_worksheet_order(filename, j+1)
                        to_file = self.to_file_join(self.output_path, to_filename)
                        
                        ws.ExportAsFixedFormat(0, to_file)  # 0 表示PDF格式
                        self.log_message.emit(f"转换完成: {to_filename}")
                        success += 1
                        time.sleep(0.5)
                        
                except Exception as e:
                    self.log_message.emit(f"转换失败 {filename}: {str(e)}")
                    failed += 1
                finally:
                    if ws:
                        try:
                            ws = None
                        except:
                            pass
                    if wb:
                        try:
                            wb.Close(SaveChanges=False)
                            wb = None
                        except:
                            pass
                    time.sleep(0.5)
                            
        except Exception as e:
            self.log_message.emit(f"Excel转换出错: {str(e)}")
            failed += len(excels) - success
        finally:
            if ws:
                try:
                    ws = None
                except:
                    pass
            if wb:
                try:
                    wb.Close(SaveChanges=False)
                except:
                    pass
            if excel:
                try:
                    excel.Quit()
                except:
                    pass
            self.log_message.emit("关闭Excel进程")
            time.sleep(1)
            
        return success, failed

    def convert_ppts(self, ppts):
        """转换PPT文件为PDF(增强版错误处理)"""
        success = 0
        failed = 0
        powerpoint = None
        ppt = None
        
        try:
            self.log_message.emit("打开PowerPoint进程...")
            # 创建PowerPoint实例
            powerpoint = win32com.client.Dispatch("PowerPoint.Application")
            
            # 尝试设置可见性
            try:
                powerpoint.Visible = 1  # 显示窗口
                self.log_message.emit("PowerPoint窗口已显示")
            except Exception as e:
                self.log_message.emit(f"无法设置PowerPoint可见性: {str(e)}")
            
            powerpoint.DisplayAlerts = 0  # 禁用警告
            
            for i, item in enumerate(ppts):
                if not self.is_running:
                    break
                    
                filename = item["name"]
                file_path = item["path"]
                self.log_message.emit(f"正在转换: {filename} ({i+1}/{len(ppts)})")
                from_file = os.path.abspath(os.path.join(file_path, filename))
                to_filename = self.change_suffix_to_pdf(filename)
                to_file = os.path.abspath(self.to_file_join(self.output_path, to_filename))
                
                # 检查文件是否存在
                if not os.path.exists(from_file):
                    self.log_message.emit(f"文件不存在: {from_file}")
                    failed += 1
                    continue
                
                # 检查文件是否可访问
                if not os.access(from_file, os.R_OK):
                    self.log_message.emit(f"没有文件读取权限: {from_file}")
                    failed += 1
                    continue
                
                # 确保输出目录可写
                if not os.access(self.output_path, os.W_OK):
                    self.log_message.emit(f"输出目录没有写入权限: {self.output_path}")
                    failed += 1
                    continue
                
                # 确保输出文件不存在
                if os.path.exists(to_file):
                    try:
                        os.remove(to_file)
                        self.log_message.emit(f"已删除已存在的文件: {to_filename}")
                    except Exception as e:
                        self.log_message.emit(f"无法删除已存在的文件 {to_filename}: {str(e)}")
                        failed += 1
                        continue
                
                try:
                    # 尝试多种方式打开文件
                    try:
                        # 方式1: 标准打开
                        ppt = powerpoint.Presentations.Open(
                            FileName=from_file,
                            ReadOnly=True,
                            WithWindow=True  # 显示窗口可能解决权限问题
                        )
                    except:
                        self.log_message.emit("尝试备用方式打开文件...")
                        # 方式2: 备用打开方式
                        ppt = powerpoint.Presentations.Open(
                            FileName=from_file,
                            ReadOnly=False,
                            WithWindow=True
                        )
                    
                    time.sleep(2)  # 更长延迟确保文件加载
                    
                    if not ppt:
                        raise Exception("无法打开演示文稿")
                        
                    if ppt.Slides.Count == 0:
                        self.log_message.emit(f"跳过空文件: {filename}")
                        failed += 1
                        continue
                    
                    # 尝试多种转换方法
                    conversion_methods = [
                        # 方法1: SaveAs PDF格式
                        lambda: ppt.SaveAs(to_file, 32),
                        # 方法2: ExportAsFixedFormat PDF格式
                        lambda: ppt.ExportAsFixedFormat(to_file, 2, Intent=1),
                        # 方法3: 另存为PDF的另一种参数组合
                        lambda: ppt.SaveAs(to_file, 32, EmbedTrueTypeFonts=True)
                    ]
                    
                    converted = False
                    for method_idx, convert_method in enumerate(conversion_methods, 1):
                        try:
                            self.log_message.emit(f"尝试转换方法 {method_idx}...")
                            convert_method()
                            time.sleep(3)  # 更长延迟确保转换完成
                            
                            # 检查文件是否生成
                            if os.path.exists(to_file) and os.path.getsize(to_file) > 0:
                                self.log_message.emit(f"转换完成: {to_filename}")
                                success += 1
                                converted = True
                                break
                        except Exception as e:
                            self.log_message.emit(f"转换方法 {method_idx} 失败: {str(e)}")
                            # 删除可能的空文件
                            if os.path.exists(to_file) and os.path.getsize(to_file) == 0:
                                os.remove(to_file)
                    
                    if not converted:
                        raise Exception("所有转换方法均失败")
                        
                except Exception as e:
                    self.log_message.emit(f"转换失败 {filename}: {str(e)}")
                    failed += 1
                finally:
                    if ppt:
                        try:
                            ppt.Close()
                            ppt = None
                        except Exception as e:
                            self.log_message.emit(f"关闭PPT时出错: {str(e)}")
                    time.sleep(1)
                
        except Exception as e:
            self.log_message.emit(f"PPT转换出错: {str(e)}")
            failed += len(ppts) - success
        finally:
            if ppt:
                try:
                    ppt.Close()
                except:
                    pass
            if powerpoint:
                try:
                    # 先关闭所有演示文稿
                    for presentation in powerpoint.Presentations:
                        presentation.Close()
                    # 退出程序
                    powerpoint.Quit()
                    powerpoint = None
                except Exception as e:
                    self.log_message.emit(f"关闭PowerPoint时出错: {str(e)}")
            # 强制释放资源
            gc.collect()
            time.sleep(1)
            self.log_message.emit("关闭PowerPoint进程")
            
        return success, failed

    @staticmethod
    def change_suffix_to_pdf(file):
        """修改文件后缀为PDF"""
        return file[:file.rfind('.')] + ".pdf"

    @staticmethod
    def add_worksheet_order(file, i):
        """为Excel工作表添加序号"""
        return file[:file.rfind('.')] + f"_工作表{i}.pdf"

    @staticmethod
    def to_file_join(output_path, file):
        """生成PDF文件路径"""
        return os.path.join(output_path, file)


class FileListWidget(QListWidget):
    """自定义文件列表部件,支持右键删除"""
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.show_context_menu)
        
    def show_context_menu(self, position):
        """显示右键菜单"""
        menu = QMenu()
        delete_action = QAction("删除选中项", self)
        delete_action.triggered.connect(self.delete_selected_items)
        delete_action.setFont(QFont("Microsoft YaHei", 10))
        menu.addAction(delete_action)
        menu.exec_(self.mapToGlobal(position))
        
    def delete_selected_items(self):
        """删除选中的项"""
        for item in self.selectedItems():
            row = self.row(item)
            self.takeItem(row)


class OfficeToPdfConverter(QMainWindow):
    """Office转PDF转换器主窗口"""
    def __init__(self):
        super().__init__()
        # 定义颜色常量(保持原有按钮风格)
        self.BUTTON_BLUE = QColor(33, 150, 243)     # 按钮蓝色(#2196F3)
        self.BUTTON_GREEN = QColor(76, 175, 80)     # 按钮绿色(#4CAF50)
        self.BUTTON_RED = QColor(244, 67, 54)       # 按钮红色(#f44336)
        self.LINE_EDIT_BG = QColor(245, 245, 245)   # 文本框背景色(浅灰色)
        
        self.worker = None
        self.thread = None
        self.file_items = []  # 存储文件信息的列表
        self.init_ui()

    def init_ui(self):
        """初始化用户界面"""
        # 设置窗口基本属性
        self.setWindowTitle("Office转PDF转换器@阿幸")
        self.setGeometry(100, 100, 900, 800)
        self.setMinimumSize(700, 600)

        # 创建主布局
        main_layout = QVBoxLayout()
        main_layout.setContentsMargins(20, 20, 20, 20)
        main_layout.setSpacing(15)

        # 创建标题
        title_label = QLabel("Office文件转PDF转换器")
        title_font = QFont("SimHei", 16, QFont.Bold)
        title_label.setFont(title_font)
        title_label.setAlignment(Qt.AlignCenter)
        main_layout.addWidget(title_label)

        # 创建文件选择区域
        file_selection_group = QGroupBox("添加文件或文件夹")
        file_selection_layout = QVBoxLayout()
        
        # 文件操作按钮(保持原有风格)
        file_btn_layout = QHBoxLayout()
        add_file_btn = self.create_button("添加文件", self.add_files, self.BUTTON_BLUE)
        add_folder_btn = self.create_button("添加目录", self.add_folder, self.BUTTON_BLUE)
        clear_btn = self.create_button("清空列表", self.clear_file_list, self.BUTTON_RED)
        
        file_btn_layout.addWidget(add_file_btn)
        file_btn_layout.addWidget(add_folder_btn)
        file_btn_layout.addWidget(clear_btn)
        
        # 文件列表
        self.file_list_widget = FileListWidget()
        self.file_list_widget.setAlternatingRowColors(True)
        self.file_list_widget.setToolTip("右键可删除选中项")
        
        file_selection_layout.addLayout(file_btn_layout)
        file_selection_layout.addWidget(self.file_list_widget)
        file_selection_group.setLayout(file_selection_layout)
        main_layout.addWidget(file_selection_group)

        # 输出路径选择区域
        output_path_group = QGroupBox("选择PDF输出文件夹")
        output_path_layout = QHBoxLayout()
        
        self.output_path_edit = QLineEdit()
        self.setup_line_edit_bg(self.output_path_edit)
        self.output_path_edit.setPlaceholderText("请选择PDF文件的保存位置")
        # 默认输出路径为当前目录下的pdf子文件夹
        default_output = os.path.join(os.getcwd(), 'pdf')
        self.output_path_edit.setText(default_output)
        
        browse_output_btn = self.create_button("浏览...", self.browse_output_folder, self.BUTTON_BLUE)
        
        output_path_layout.addWidget(self.output_path_edit)
        output_path_layout.addWidget(browse_output_btn)
        output_path_group.setLayout(output_path_layout)
        main_layout.addWidget(output_path_group)

        # 创建文件统计区域
        stats_group = QGroupBox("文件统计")
        stats_layout = QFormLayout()
        
        self.word_count = QLabel("0")
        self.excel_count = QLabel("0")
        self.ppt_count = QLabel("0")
        self.total_count = QLabel("0")
        
        # 设置统计区域字体
        font = QFont("Microsoft YaHei", 10)
        self.word_count.setFont(font)
        self.excel_count.setFont(font)
        self.ppt_count.setFont(font)
        self.total_count.setFont(font)
        
        stats_layout.addRow("Word文件 (.doc, .docx):", self.word_count)
        stats_layout.addRow("Excel文件 (.xls, .xlsx):", self.excel_count)
        stats_layout.addRow("PPT文件 (.ppt, .pptx):", self.ppt_count)
        stats_layout.addRow("总计可转换文件:", self.total_count)
        
        stats_group.setLayout(stats_layout)
        main_layout.addWidget(stats_group)

        # 创建进度条区域
        progress_layout = QVBoxLayout()
        
        self.progress_bar = QProgressBar()
        self.progress_bar.setValue(0)
        self.progress_status = QLabel("准备就绪")
        self.progress_status.setFont(QFont("Microsoft YaHei", 10))
        self.progress_status.setAlignment(Qt.AlignCenter)
        
        progress_layout.addWidget(self.progress_bar)
        progress_layout.addWidget(self.progress_status)
        main_layout.addLayout(progress_layout)

        # 创建按钮区域(保持原有风格)
        btn_layout = QHBoxLayout()
        
        self.analyze_btn = self.create_button("分析文件", self.analyze_files, self.BUTTON_BLUE, 100)
        self.convert_btn = self.create_button("开始转换", self.start_conversion, self.BUTTON_GREEN, 100)
        self.convert_btn.setEnabled(False)
        self.cancel_btn = self.create_button("取消", self.cancel_conversion, self.BUTTON_RED, 100)
        self.cancel_btn.setEnabled(False)
        
        btn_layout.addWidget(self.analyze_btn)
        btn_layout.addWidget(self.convert_btn)
        btn_layout.addWidget(self.cancel_btn)
        main_layout.addLayout(btn_layout)

        # 创建日志区域
        log_group = QGroupBox("转换日志")
        log_layout = QVBoxLayout()
        
        self.log_text = QTextEdit()
        self.log_text.setReadOnly(True)
        self.log_text.setLineWrapMode(QTextEdit.WidgetWidth)
        self.log_text.setFont(QFont("Microsoft YaHei", 10))
        self.setup_line_edit_bg(self.log_text)
        
        log_layout.addWidget(self.log_text)
        log_group.setLayout(log_layout)
        main_layout.addWidget(log_group)

        # 设置中心部件
        central_widget = QWidget()
        central_widget.setLayout(main_layout)
        self.setCentralWidget(central_widget)

        # 状态栏信息
        self.statusBar().showMessage("就绪")

    def create_button(self, text, callback, color, fixed_width=80):
        """创建统一风格的按钮(保持原有风格)"""
        button = QPushButton(text)
        button.setFont(QFont("Microsoft YaHei", 10, QFont.Bold))
        button.setFixedWidth(fixed_width)
        button.clicked.connect(callback)
        self.setup_button_style(button, color)
        return button
        
    def setup_line_edit_bg(self, widget):
        """设置文本框背景颜色(保持原有风格)"""
        palette = widget.palette()
        palette.setColor(palette.Base, self.LINE_EDIT_BG)
        palette.setColor(palette.Text, QColor(0, 0, 0))
        widget.setPalette(palette)
        widget.setAutoFillBackground(True)
        
    def setup_button_style(self, button, base_color):
        """设置按钮样式(保持原有风格)"""
        button.setStyleSheet(f"""
            QPushButton {{
                background-color: rgb({base_color.red()}, {base_color.green()}, {base_color.blue()});
                color: white;
                border: none;
                padding: 5px;
                border-radius: 4px;
            }}
            QPushButton:hover {{
                background-color: rgb({int(base_color.red()*0.8)}, {int(base_color.green()*0.8)}, {int(base_color.blue()*0.8)});
            }}
            QPushButton:pressed {{
                background-color: rgb({int(base_color.red()*0.7)}, {int(base_color.green()*0.7)}, {int(base_color.blue()*0.7)});
            }}
            QPushButton:disabled {{
                background-color: rgb(160, 160, 160);
            }}
        """)
        button.setFocusPolicy(Qt.NoFocus)

    def add_files(self):
        """添加单个或多个文件"""
        file_paths, _ = QFileDialog.getOpenFileNames(
            self, "选择Office文件", os.getcwd(), 
            "Office文件 (*.doc *.docx *.xls *.xlsx *.ppt *.pptx)"
        )
        
        if file_paths:
            added_count = 0
            for file_path in file_paths:
                file_dir = os.path.dirname(file_path)
                file_name = os.path.basename(file_path)
                
                # 检查是否已在列表中
                is_duplicate = False
                for i in range(self.file_list_widget.count()):
                    if self.file_list_widget.item(i).data(Qt.UserRole) == file_path:
                        is_duplicate = True
                        break
                
                if not is_duplicate:
                    item = QListWidgetItem(file_name)
                    item.setData(Qt.UserRole, file_path)
                    self.file_list_widget.addItem(item)
                    self.file_items.append({"path": file_dir, "name": file_name})
                    added_count += 1
            
            if added_count > 0:
                self.log_text.append(f"已添加 {added_count} 个文件")
                self.analyze_btn.setEnabled(True)

    def add_folder(self):
        """添加目录中的所有Office文件"""
        folder = QFileDialog.getExistingDirectory(self, "选择文件夹", os.getcwd())
        if folder:
            office_extensions = ('.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx')
            added_count = 0
            
            for root, _, files in os.walk(folder):
                for file in files:
                    if file.lower().endswith(office_extensions):
                        file_path = os.path.join(root, file)
                        
                        # 检查是否已在列表中
                        is_duplicate = False
                        for i in range(self.file_list_widget.count()):
                            if self.file_list_widget.item(i).data(Qt.UserRole) == file_path:
                                is_duplicate = True
                                break
                        
                        if not is_duplicate:
                            item = QListWidgetItem(file)
                            item.setData(Qt.UserRole, file_path)
                            self.file_list_widget.addItem(item)
                            self.file_items.append({"path": root, "name": file})
                            added_count += 1
            
            if added_count > 0:
                self.log_text.append(f"从目录中添加了 {added_count} 个文件")
                self.analyze_btn.setEnabled(True)
            else:
                QMessageBox.information(self, "提示", "所选目录中没有找到可转换的Office文件")

    def clear_file_list(self):
        """清空文件列表"""
        if self.file_list_widget.count() > 0:
            self.file_list_widget.clear()
            self.file_items = []
            self.log_text.append("已清空文件列表")
            self.reset_stats()
            self.analyze_btn.setEnabled(False)
            self.convert_btn.setEnabled(False)
        else:
            QMessageBox.information(self, "提示", "文件列表已为空")

    def reset_stats(self):
        """重置文件统计"""
        self.word_count.setText("0")
        self.excel_count.setText("0")
        self.ppt_count.setText("0")
        self.total_count.setText("0")

    def analyze_files(self):
        """分析文件类型并统计数量"""
        word_count = 0
        excel_count = 0
        ppt_count = 0
        
        for item in self.file_items:
            filename = item["name"].lower()
            if filename.endswith(('.doc', '.docx')):
                word_count += 1
            elif filename.endswith(('.xls', '.xlsx')):
                excel_count += 1
            elif filename.endswith(('.ppt', '.pptx')):
                ppt_count += 1
        
        total = word_count + excel_count + ppt_count
        
        self.word_count.setText(str(word_count))
        self.excel_count.setText(str(excel_count))
        self.ppt_count.setText(str(ppt_count))
        self.total_count.setText(str(total))
        
        self.log_text.append(f"文件分析完成: Word {word_count}个, Excel {excel_count}个, PPT {ppt_count}个, 总计 {total}个")
        
        if total > 0:
            self.convert_btn.setEnabled(True)
        else:
            self.convert_btn.setEnabled(False)
            QMessageBox.warning(self, "警告", "没有可转换的文件")

    def browse_output_folder(self):
        """选择输出文件夹"""
        folder = QFileDialog.getExistingDirectory(self, "选择PDF输出文件夹", os.getcwd())
        if folder:
            self.output_path_edit.setText(folder)

    def start_conversion(self):
        """开始转换任务"""
        output_path = self.output_path_edit.text().strip()
        if not output_path:
            QMessageBox.warning(self, "警告", "请选择PDF输出文件夹")
            return
            
        if not self.file_items:
            QMessageBox.warning(self, "警告", "请先添加文件")
            return
            
        # 禁用相关按钮
        self.analyze_btn.setEnabled(False)
        self.convert_btn.setEnabled(False)
        self.cancel_btn.setEnabled(True)
        
        # 初始化进度条
        self.progress_bar.setValue(0)
        self.progress_status.setText("准备开始转换...")
        
        # 创建线程和工作对象
        self.thread = QThread()
        self.worker = ConversionWorker(self.file_items, output_path)
        self.worker.moveToThread(self.thread)
        
        # 连接信号槽
        self.thread.started.connect(self.worker.run)
        self.worker.progress_updated.connect(self.update_progress)
        self.worker.log_message.connect(self.log_text.append)
        self.worker.conversion_finished.connect(self.conversion_complete)
        self.worker.conversion_finished.connect(self.thread.quit)
        self.thread.finished.connect(self.thread.deleteLater)
        self.thread.finished.connect(lambda: self.worker.deleteLater())
        
        # 开始转换
        self.thread.start()
        self.log_text.append("===== 开始转换 =====")

    def update_progress(self, value, status):
        """更新进度条和状态"""
        self.progress_bar.setValue(value)
        self.progress_status.setText(status)

    def conversion_complete(self, message):
        """转换完成处理"""
        self.log_text.append("===== 转换结束 =====")
        QMessageBox.information(self, "转换结果", message)
        
        # 恢复按钮状态
        self.analyze_btn.setEnabled(True)
        self.convert_btn.setEnabled(True)
        self.cancel_btn.setEnabled(False)
        self.progress_status.setText("转换完成")

    def cancel_conversion(self):
        """取消转换任务"""
        if self.worker and self.thread and self.thread.isRunning():
            if QMessageBox.question(self, "确认取消", "确定要取消转换吗?", 
                                  QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes:
                self.worker.stop()
                self.progress_status.setText("正在取消...")
                self.cancel_btn.setEnabled(False)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    app.setStyle("Fusion")
    window = OfficeToPdfConverter()
    window.show()
    sys.exit(app.exec_())
    

软件下载

夸克
迅雷


网站公告

今日签到

点亮在社区的每一天
去签到