当前位置:首页>python>批量转PDF别再花钱了!教你用Python做个桌面小工具

批量转PDF别再花钱了!教你用Python做个桌面小工具

  • 2026-09-07 19:32:30
批量转PDF别再花钱了!教你用Python做个桌面小工具

欢迎大家B站搜索:丁老师的技术随笔

不用充WPS会员!自己写了个docx批量转PDF小工具

采用 PySide6+Python|自制批量转PDF工具,附代码思路

文末有打包完成的Docx转PDF工具.exe文件,无需安装,双击即可使用.

界面效果

完整代码

#!/usr/bin/env python3# -*- coding: utf-8 -*-"""批量把 .docx 转 PDF —— PySide6 GUIauthor : qustdjx"""import sys, os, pathlib, threading, time, tracebackfrom typing import Listfrom PySide6.QtCore import Qt, QThread, Signal, QObjectfrom PySide6.QtWidgets import (    QApplication, QWidget, QVBoxLayout, QHBoxLayout,    QPushButton, QLineEdit, QFileDialog,    QProgressBar, QTextEdit, QLabel)# 用 docx2pdf 做转换(底层调用 Word COM,Windows 需装 Word;macOS 用 Office 或 Pages)from docx2pdf import convert# ========== 后台线程 ==========class Worker(QObject):    # 信号    log_signal   = Signal(str)      # 给日志框    progress_max = Signal(int)      # 设置进度条最大值    progress     = Signal(int)      # 当前进度    finished     = Signal(bool)     # 全部完成/被中止    def __init__(self, input_dir: str, output_dir: str):        super().__init__()        self.input_dir  = input_dir        self.output_dir = output_dir        self._running   = True    def stop(self):        self._running = False    def run(self):        try:            # 收集所有 docx            docx_files: List[pathlib.Path] = []            for root, _, files in os.walk(self.input_dir):                for f in files:                    if f.lower().endswith(".docx"):                        docx_files.append(pathlib.Path(root) / f)            total = len(docx_files)            if total == 0:                self.log_signal.emit("未找到任何 .docx 文件。")                self.finished.emit(True)                return            self.progress_max.emit(total)            self.log_signal.emit(f"共找到 {total} 个文件,开始转换…")            for idx, docx in enumerate(docx_files, 1):                if not self._running:                    self.log_signal.emit("*** 用户中止 ***")                    self.finished.emit(False)                    return                # 构造输出路径,保持目录层级                rel_path = docx.relative_to(self.input_dir)                out_pdf  = pathlib.Path(self.output_dir) / rel_path.with_suffix(".pdf")                out_pdf.parent.mkdir(parents=True, exist_ok=True)                self.log_signal.emit(f"[{idx}/{total}]  {docx.name}")                try:                    # docx2pdf 的 convert 接口:输入可以是文件或目录,这里指定单文件                    convert(str(docx), str(out_pdf))                except Exception as e:                    self.log_signal.emit(f"  失败:{e}")                self.progress.emit(idx)                time.sleep(0.05)   # 给 UI 一点刷新时间            self.log_signal.emit("=== 全部完成!===")            self.finished.emit(True)        except Exception as e:            self.log_signal.emit("发生异常:\n" + traceback.format_exc())            self.finished.emit(False)# ========== 主窗口 ==========class MainWindow(QWidget):    def __init__(self):        super().__init__()        self.setWindowTitle("批量 docx → PDF 转换器")        self.resize(700, 500)        # 输入目录        line_in, btn_in = self._make_browser("输入目录")        self.line_in = line_in        btn_in.clicked.connect(lambda: self.browse_dir(line_in))        # 输出目录        line_out, btn_out = self._make_browser("输出目录")        self.line_out = line_out        btn_out.clicked.connect(lambda: self.browse_dir(line_out))        # 控制按钮        self.btn_start = QPushButton("开始转换")        self.btn_stop  = QPushButton("中止")        self.btn_stop.setEnabled(False)        self.btn_start.clicked.connect(self.start)        self.btn_stop.clicked.connect(self.stop)        hbox = QHBoxLayout()        hbox.addWidget(self.btn_start)        hbox.addWidget(self.btn_stop)        # 进度条        self.progress = QProgressBar()        self.progress.setTextVisible(True)        # 日志        self.log = QTextEdit()        self.log.setReadOnly(True)        # 整体布局        vbox = QVBoxLayout(self)        vbox.addWidget(QLabel("请选择输入/输出目录,然后点击“开始转换”"))        vbox.addLayout(self._make_browser_layout("输入目录", line_in, btn_in))        vbox.addLayout(self._make_browser_layout("输出目录", line_out, btn_out))        vbox.addLayout(hbox)        vbox.addWidget(self.progress)        vbox.addWidget(self.log)        vbox.setStretchFactor(self.log, 1)        # 线程相关        self.thread: QThread | None = None        self.worker: Worker | None = None    # --------------- UI 小工具 ---------------    def _make_browser(self, title: str):        line = QLineEdit()        line.setClearButtonEnabled(True)        btn = QPushButton("浏览…")        return line, btn    def _make_browser_layout(self, title: str, line: QLineEdit, btn: QPushButton):        h = QHBoxLayout()        h.addWidget(QLabel(title + ":"))        h.addWidget(line)        h.addWidget(btn)        return h    def browse_dir(self, line: QLineEdit):        path = QFileDialog.getExistingDirectory(self, "选择目录")        if path:            line.setText(path)    # --------------- 转换逻辑 ---------------    def start(self):        in_dir  = self.line_in.text().strip()        out_dir = self.line_out.text().strip()        if not in_dir or not out_dir:            self.log.append("请先选择输入/输出目录!")            return        if not os.path.isdir(in_dir):            self.log.append("输入目录无效!")            return        # 初始化界面        self.btn_start.setEnabled(False)        self.btn_stop.setEnabled(True)        self.progress.setValue(0)        self.log.clear()        # 启动线程        self.thread = QThread()        self.worker = Worker(in_dir, out_dir)        self.worker.moveToThread(self.thread)        self.thread.started.connect(self.worker.run)        self.worker.finished.connect(self.thread.quit)        self.worker.finished.connect(self.done)        self.worker.log_signal.connect(self.log_append)        self.worker.progress_max.connect(self.progress.setMaximum)        self.worker.progress.connect(self.progress.setValue)        self.thread.start()    def stop(self):        if self.worker:            self.worker.stop()    def done(self, success: bool):        self.btn_start.setEnabled(True)        self.btn_stop.setEnabled(False)        self.thread = None        self.worker = None    def log_append(self, txt: str):        self.log.append(txt)# ========== main ==========if __name__ == "__main__":    app = QApplication(sys.argv)    w   = MainWindow()    w.show()    sys.exit(app.exec())

.exe 文件打包

使用pyinstaller进行 .exe 打包,让系统不安装python 也可以正常使用

pyinstaller --onefile --windowed --icon=app.ico --name="Docx转PDF工具" main.py

打包效果:

.exe 文件下载地址

通过网盘分享的文件:Docx转PDF工具.exe 链接: https://pan.baidu.com/s/1Ako0EVG_qA7ahEq7sjkJhA 提取码: 6det

通过网盘分享的文件:Docx转PDF工具.exe 提取码: 6det

END

● 开箱即用! Streamlit 万能模板,复制就能跑通 90% 的 AI 演示项目

● YOLO26 模型已发布 可供下载

●  让YOLOv8n 目标识别快速跑起来

关注二维码

获取更多精彩内容

最新文章

随机文章