最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python結(jié)合PyQt5開發(fā)一個(gè)PDF批量合并工具

 更新時(shí)間:2026年04月15日 08:17:41   作者:小莊-Python辦公  
日常工作中經(jīng)常需要把多個(gè)?PDF?合并成一個(gè),網(wǎng)上的在線工具要么有廣告,要么有頁數(shù)限制,今天我們就用?Python?+?PyQt5?從零打造一款本地運(yùn)行,無廣告,無限制的?PDF?批量合并工具吧

日常工作中經(jīng)常需要把多個(gè) PDF 合并成一個(gè)?網(wǎng)上的在線工具要么有廣告、要么有頁數(shù)限制、要么擔(dān)心隱私泄漏。今天我們就用 Python + PyQt5 從零打造一款本地運(yùn)行、無廣告、無限制的 PDF 批量合并工具!

一、為什么要自己做?

市面上的 PDF 合并方案大致分三類:

方案缺點(diǎn)
在線網(wǎng)站(如 SmallPDF)文件上傳有大小限制,隱私風(fēng)險(xiǎn)
Adobe Acrobat正版昂貴,殺雞焉用牛刀
命令行腳本對非技術(shù)用戶不友好

我們的目標(biāo):一個(gè)有圖形界面、支持拖拽、本地運(yùn)行的小工具。

二、技術(shù)選型

需求選型理由
GUI 框架PyQt5成熟穩(wěn)定,跨平臺,控件豐富
PDF 操作PyPDF2輕量級,合并功能完善,純 Python
多線程QThread與 PyQt5 完美配合,避免界面凍結(jié)

三、安裝依賴

pip install PyQt5 PyPDF2

或者使用 requirements.txt:

pip install -r requirements.txt

四、整體架構(gòu)設(shè)計(jì)

程序分為 3 個(gè)核心模塊:

pdf_merger.py
├── MergeWorker       — 后臺合并線程
├── DragDropListWidget — 支持拖拽的文件列表控件
└── PDFMergerApp       — 主窗口(界面 + 業(yè)務(wù)邏輯)

數(shù)據(jù)流

用戶操作 → 添加文件到列表 → 點(diǎn)擊合并
                                ↓
                          啟動 MergeWorker 線程
                                ↓
                    逐個(gè) append PDF → 寫入輸出文件
                                ↓
                     信號通知主線程 → 更新日志和進(jìn)度條

五、核心代碼詳解

5.1 后臺合并線程 — MergeWorker

為什么要用線程?因?yàn)槿绻谥骶€程中執(zhí)行 IO 密集的合并操作,界面會"假死"。PyQt5 的 QThread 配合信號(Signal)可以完美解決:

class MergeWorker(QThread):
    log_signal = pyqtSignal(str)        # 日志消息
    progress_signal = pyqtSignal(int)   # 進(jìn)度百分比
    finished_signal = pyqtSignal(bool, str)  # 完成狀態(tài)

    def __init__(self, file_list, output_path):
        super().__init__()
        self.file_list = file_list
        self.output_path = output_path

    def run(self):
        merger = PdfMerger()
        total = len(self.file_list)
        try:
            for idx, fpath in enumerate(self.file_list, 1):
                self.log_signal.emit(f"[{idx}/{total}] 正在添加: {os.path.basename(fpath)}")
                merger.append(fpath)
                self.progress_signal.emit(int(idx / total * 100))

            merger.write(self.output_path)
            merger.close()
            self.finished_signal.emit(True, self.output_path)
        except Exception as e:
            self.finished_signal.emit(False, str(e))

關(guān)鍵點(diǎn)

  • 定義了三個(gè)信號:日志、進(jìn)度、完成狀態(tài)
  • run() 方法在子線程執(zhí)行,通過信號回傳到主線程更新 UI
  • 使用 try/except 捕獲異常,合并失敗不會崩潰

5.2 拖拽列表控件 — DragDropListWidget

PyQt5 的 QListWidget 本身不支持從系統(tǒng)拖入文件,我們需要重寫幾個(gè)事件:

class DragDropListWidget(QListWidget):
    files_dropped = pyqtSignal(list)  # 拖入的路徑列表

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setAcceptDrops(True)
        self.setDragDropMode(QAbstractItemView.InternalMove)

    def dragEnterEvent(self, event):
        if event.mimeData().hasUrls():
            event.acceptProposedAction()
        else:
            super().dragEnterEvent(event)

    def dropEvent(self, event):
        if event.mimeData().hasUrls():
            paths = [url.toLocalFile() for url in event.mimeData().urls() if url.toLocalFile()]
            self.files_dropped.emit(paths)
            event.acceptProposedAction()
        else:
            super().dropEvent(event)

關(guān)鍵點(diǎn)

  • setAcceptDrops(True) 允許接受外部拖拽
  • setDragDropMode(InternalMove) 同時(shí)支持列表內(nèi)部拖拽排序
  • dragEnterEvent 判斷拖入的是否為文件 URL
  • dropEvent 提取本地路徑,發(fā)射自定義信號

5.3 主窗口 — PDFMergerApp

主窗口負(fù)責(zé)布局和業(yè)務(wù)邏輯。核心布局結(jié)構(gòu):

QMainWindow
└── QVBoxLayout (根布局)
    ├── QLabel (標(biāo)題)
    ├── QLabel (副標(biāo)題)
    ├── QSplitter (垂直分割)
    │   ├── QGroupBox — 文件列表區(qū)
    │   │   ├── DragDropListWidget
    │   │   └── QHBoxLayout — 按鈕行
    │   └── QGroupBox — 日志區(qū)
    │       └── QTextEdit
    ├── QProgressBar (進(jìn)度條)
    └── QPushButton (合并按鈕)

文件收集邏輯

支持同時(shí)傳入文件和文件夾,遞歸收集所有 PDF:

def _collect_pdfs(self, paths):
    pdfs = []
    for p in paths:
        if os.path.isfile(p) and p.lower().endswith(".pdf"):
            pdfs.append(p)
        elif os.path.isdir(p):
            for root, _, files in os.walk(p):
                for f in sorted(files):
                    if f.lower().endswith(".pdf"):
                        pdfs.append(os.path.join(root, f))
    return pdfs

去重添加

同一個(gè)文件不會被重復(fù)添加:

def _add_to_list(self, new_files):
    added = 0
    for f in new_files:
        if f not in self.pdf_files:
            self.pdf_files.append(f)
            self.file_list_widget.addItem(f)
            added += 1

列表排序

上移/下移通過交換列表中的位置實(shí)現(xiàn):

def _move_up(self):
    row = self.file_list_widget.currentRow()
    if row > 0:
        item = self.file_list_widget.takeItem(row)
        self.file_list_widget.insertItem(row - 1, item)
        self.file_list_widget.setCurrentRow(row - 1)
        self.pdf_files[row], self.pdf_files[row - 1] = (
            self.pdf_files[row - 1], self.pdf_files[row]
        )

六、樣式美化

使用 Qt StyleSheet(類似 CSS)統(tǒng)一美化控件:

QMainWindow {
    background-color: #f5f7fa;
}
QGroupBox {
    border: 1px solid #dcdfe6;
    border-radius: 8px;
    background-color: #ffffff;
}
#mergeBtn {
    background-color: #3498db;
    color: white;
    font-size: 15px;
    font-weight: bold;
    border-radius: 8px;
}
QProgressBar::chunk {
    background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
        stop:0 #3498db, stop:1 #2ecc71);
    border-radius: 5px;
}

美化要點(diǎn)

  • QGroupBox 使用白色背景 + 圓角,呈現(xiàn)卡片效果
  • 合并按鈕使用藍(lán)色主題色,hover 和 pressed 有層次感
  • 進(jìn)度條漸變色(藍(lán) → 綠),視覺上更有活力
  • 字體使用 Microsoft YaHei,中文顯示清晰美觀

七、使用流程

第一步:啟動程序

python pdf_merger.py

第二步:添加文件

三種方式任選:

  • 拖拽:直接從文件資源管理器拖入 PDF 文件或文件夾
  • 添加文件:點(diǎn)擊按鈕,在文件選擇對話框中多選 PDF
  • 添加目錄:點(diǎn)擊按鈕,選擇一個(gè)文件夾,自動掃描其中所有 PDF

第三步:調(diào)整順序

  • 選中某個(gè)文件,用 ?/? 按鈕調(diào)整位置
  • 或者直接在列表中拖拽排序

第四步:點(diǎn)擊合并

  • 點(diǎn)擊 “?? 開始合并”
  • 選擇保存位置和文件名
  • 等待完成,日志區(qū)實(shí)時(shí)顯示處理進(jìn)度

八、可能遇到的問題與解決

1. 安裝 PyQt5 失敗

# 嘗試使用國內(nèi)鏡像
pip install PyQt5 -i https://pypi.tuna.tsinghua.edu.cn/simple

2. 合并時(shí)報(bào)錯(cuò) “PdfReadError”

通常是因?yàn)?PDF 文件損壞或加密。解決方法:

  • 排除問題文件(可在日志中看到是哪個(gè)文件報(bào)錯(cuò))
  • 使用其他工具先修復(fù)或解密該 PDF

3. 打包為 EXE

想分發(fā)給沒有 Python 環(huán)境的同事?使用 PyInstaller:

pip install pyinstaller
pyinstaller --onefile --windowed --name "PDF合并工具" pdf_merger.py

打包后的 EXE 位于 dist/ 目錄。

九、進(jìn)階擴(kuò)展思路

如果你想繼續(xù)完善這個(gè)工具,以下是一些擴(kuò)展方向:

方向說明
支持加密 PDF在 append 前使用 PdfReader 解密
選擇頁面范圍允許用戶選擇每個(gè) PDF 的特定頁面
預(yù)覽功能使用 pdf2image 生成縮略圖預(yù)覽
保存/加載配置記住上次的文件列表和輸出路徑
多語言使用 Qt 的 i18n 機(jī)制支持英文等
打包發(fā)布使用 PyInstaller / Nuitka 打包為單文件 EXE

十、完整項(xiàng)目結(jié)構(gòu)

19-批量PDF合并工具/
├── pdf_merger.py        # 主程序源碼
├── requirements.txt     # 依賴清單
├── README.md            # 項(xiàng)目說明
└── blog.md              # 本篇開發(fā)博客

總結(jié)

通過這篇文章,我們從零實(shí)現(xiàn)了一個(gè)功能完整的 PDF 批量合并工具:

  • PyPDF2 負(fù)責(zé) PDF 的讀取與合并
  • PyQt5 構(gòu)建了美觀的圖形界面
  • QThread 保證了合并過程中界面不凍結(jié)
  • 拖拽功能 讓操作更加便捷
  • QSS 樣式 讓界面更加美觀

整個(gè)項(xiàng)目只有一個(gè) Python 文件,代碼約 300 行,簡潔易懂。希望這個(gè)小工具能幫到你,也希望這篇教程能給你一些 PyQt5 桌面開發(fā)的啟發(fā)!

到此這篇關(guān)于Python結(jié)合PyQt5開發(fā)一個(gè)PDF批量合并工具的文章就介紹到這了,更多相關(guān)Python批量合并PDF內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 對python中詞典的values值的修改或新增KEY詳解

    對python中詞典的values值的修改或新增KEY詳解

    今天小編就為大家分享一篇對python中詞典的values值的修改或新增KEY詳解,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-01-01
  • Python設(shè)計(jì)模式之建造者模式實(shí)例詳解

    Python設(shè)計(jì)模式之建造者模式實(shí)例詳解

    這篇文章主要介紹了Python設(shè)計(jì)模式之建造者模式,簡單說明了建造者模式的概念、原理,并結(jié)合實(shí)例形式分析了Python定義及使用建造者模式相關(guān)操作技巧,需要的朋友可以參考下
    2019-01-01
  • python實(shí)現(xiàn)聚類算法原理

    python實(shí)現(xiàn)聚類算法原理

    這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)聚類算法原理,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-02-02
  • python 拷貝特定后綴名文件,并保留原始目錄結(jié)構(gòu)的實(shí)例

    python 拷貝特定后綴名文件,并保留原始目錄結(jié)構(gòu)的實(shí)例

    下面小編就為大家分享一篇python 拷貝特定后綴名文件,并保留原始目錄結(jié)構(gòu)的實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-04-04
  • numpy庫ndarray多維數(shù)組的維度變換方法(reshape、resize、swapaxes、flatten)

    numpy庫ndarray多維數(shù)組的維度變換方法(reshape、resize、swapaxes、flatten)

    這篇文章主要介紹了numpy庫ndarray多維數(shù)組的維度變換方法(reshape、resize、swapaxes、flatten),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • python實(shí)現(xiàn)自動解數(shù)獨(dú)小程序

    python實(shí)現(xiàn)自動解數(shù)獨(dú)小程序

    這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)自動解數(shù)獨(dú)小程序,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • python實(shí)現(xiàn)簡易五子棋游戲(控制臺版)

    python實(shí)現(xiàn)簡易五子棋游戲(控制臺版)

    這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)簡易五子棋游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • Python函數(shù)定義及傳參方式詳解(4種)

    Python函數(shù)定義及傳參方式詳解(4種)

    這篇文章主要介紹了Python函數(shù)定義及傳參方式詳解(4種),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • Python爬取365好書中小說代碼實(shí)例

    Python爬取365好書中小說代碼實(shí)例

    這篇文章主要介紹了Python爬取365好書中小說代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • Python結(jié)合JSON實(shí)現(xiàn)動態(tài)按鈕管理程序

    Python結(jié)合JSON實(shí)現(xiàn)動態(tài)按鈕管理程序

    這篇文章主要為大家詳細(xì)介紹了如何使用Python的wxPython庫結(jié)合JSON配置文件,開發(fā)一個(gè)支持動態(tài)按鈕創(chuàng)建,文件執(zhí)行和配置管理的桌面應(yīng)用程序,感興趣的可以了解下
    2025-04-04

最新評論

枝江市| 年辖:市辖区| 额敏县| 垣曲县| 河间市| 东至县| 罗甸县| 交口县| 绥化市| 红安县| 华池县| 松原市| 桐梓县| 开远市| 同江市| 平陆县| 密山市| 阿瓦提县| 巩义市| 宣威市| 昌都县| 安岳县| 房产| 高邑县| 天祝| 新河县| 萨迦县| 六安市| 神池县| 青川县| 太仓市| 历史| 都江堰市| 沛县| 清新县| 定襄县| 贵定县| 周口市| 大荔县| 芜湖市| 天气|