Python 创建一个能够筛选文件的PDF合并工具

devtools/2025/3/4 18:21:03/

合并多个 PDF 文件。这款 PDF 合并工具允许用户浏览文件夹、选择 PDF 文件,并将其合并为一个新的 PDF 文件。我们将详细分析代码结构和如何一步步实现每个功能。
C:\pythoncode\new\PDFFileInFolderMergeToNewPDFFile.py

全部代码

python">import os
import wx
import PyPDF2class PDFMergerFrame(wx.Frame):def __init__(self, parent, title):super(PDFMergerFrame, self).__init__(parent, title=title, size=(900, 600))# Create main panelself.panel = wx.Panel(self)# Create toolbarself.toolbar = self.CreateToolBar()# Add toolbar buttonsbrowse_tool = self.toolbar.AddTool(wx.ID_ANY, "浏览", wx.ArtProvider.GetBitmap(wx.ART_FOLDER_OPEN), "浏览文件夹")merge_tool = self.toolbar.AddTool(wx.ID_ANY, "合成", wx.ArtProvider.GetBitmap(wx.ART_NEW), "合成PDF文件")self.toolbar.Realize()# Bind toolbar eventsself.Bind(wx.EVT_TOOL, self.on_browse, browse_tool)self.Bind(wx.EVT_TOOL, self.on_merge, merge_tool)# Create main sizermain_sizer = wx.BoxSizer(wx.HORIZONTAL)# Create left panel for foldersleft_panel = wx.Panel(self.panel)left_sizer = wx.BoxSizer(wx.VERTICAL)folder_label = wx.StaticText(left_panel, label="文件夹:")self.folder_listbox = wx.ListBox(left_panel, size=(200, -1), style=wx.LB_SINGLE)left_sizer.Add(folder_label, 0, wx.ALL, 5)left_sizer.Add(self.folder_listbox, 1, wx.EXPAND | wx.ALL, 5)left_panel.SetSizer(left_sizer)# Create middle panel for filesmiddle_panel = wx.Panel(self.panel)middle_sizer = wx.BoxSizer(wx.VERTICAL)file_label = wx.StaticText(middle_panel, label="子文件:")self.file_listbox = wx.ListBox(middle_panel, size=(200, -1), style=wx.LB_SINGLE)middle_sizer.Add(file_label, 0, wx.ALL, 5)middle_sizer.Add(self.file_listbox, 1, wx.EXPAND | wx.ALL, 5)middle_panel.SetSizer(middle_sizer)# Create button panelbutton_panel = wx.Panel(self.panel)button_sizer = wx.BoxSizer(wx.VERTICAL)add_button = wx.Button(button_panel, label=">")remove_button = wx.Button(button_panel, label="<")button_sizer.Add(add_button, 0, wx.ALL, 5)button_sizer.Add(remove_button, 0, wx.ALL, 5)button_panel.SetSizer(button_sizer)# Create right panel for selected filesright_panel = wx.Panel(self.panel)right_sizer = wx.BoxSizer(wx.VERTICAL)selected_label = wx.StaticText(right_panel, label="已选文件:")self.selected_listbox = wx.ListBox(right_panel, size=(200, -1), style=wx.LB_SINGLE)right_sizer.Add(selected_label, 0, wx.ALL, 5)right_sizer.Add(self.selected_listbox, 1, wx.EXPAND | wx.ALL, 5)right_panel.SetSizer(right_sizer)# Add panels to main sizermain_sizer.Add(left_panel, 1, wx.EXPAND | wx.ALL, 5)main_sizer.Add(middle_panel, 1, wx.EXPAND | wx.ALL, 5)main_sizer.Add(button_panel, 0, wx.EXPAND | wx.ALL, 5)main_sizer.Add(right_panel, 1, wx.EXPAND | wx.ALL, 5)# Set main sizerself.panel.SetSizerAndFit(main_sizer)#         # Set main sizer# self.panel.SetSizerAndFit(main_sizer)# Bind eventsself.folder_listbox.Bind(wx.EVT_LISTBOX, self.on_folder_select)add_button.Bind(wx.EVT_BUTTON, self.on_add_file)remove_button.Bind(wx.EVT_BUTTON, self.on_remove_file)# Initialize variablesself.root_path = ""self.folders_with_files = []# Center and show frameself.Centre()self.Show()def on_browse(self, event):"""Handle browse button click"""dlg = wx.DirDialog(self, "选择文件夹", style=wx.DD_DEFAULT_STYLE)if dlg.ShowModal() == wx.ID_OK:self.root_path = dlg.GetPath()self.scan_folders()dlg.Destroy()def scan_folders(self):"""Scan folders and list those with PDF files"""if not self.root_path:returnself.folders_with_files = []self.folder_listbox.Clear()for root, dirs, files in os.walk(self.root_path):has_pdf = Falsefor file in files:if file.lower().endswith('.pdf'):has_pdf = Truebreakif has_pdf:self.folders_with_files.append(root)folder_name = os.path.basename(root) or rootself.folder_listbox.Append(folder_name)def on_folder_select(self, event):"""Handle folder selection"""selected_index = self.folder_listbox.GetSelection()if selected_index == wx.NOT_FOUND:returnselected_folder = self.folders_with_files[selected_index]self.file_listbox.Clear()for file in os.listdir(selected_folder):if file.lower().endswith('.pdf'):self.file_listbox.Append(file)def on_add_file(self, event):"""Add selected file to the list of files to merge"""selected_file_index = self.file_listbox.GetSelection()selected_folder_index = self.folder_listbox.GetSelection()if selected_file_index == wx.NOT_FOUND or selected_folder_index == wx.NOT_FOUND:returnselected_file = self.file_listbox.GetString(selected_file_index)selected_folder = self.folders_with_files[selected_folder_index]full_path = os.path.join(selected_folder, selected_file)# Check if already in the listfor i in range(self.selected_listbox.GetCount()):if self.selected_listbox.GetClientData(i) == full_path:returnself.selected_listbox.Append(selected_file, full_path)def on_remove_file(self, event):"""Remove selected file from the list of files to merge"""selected_index = self.selected_listbox.GetSelection()if selected_index != wx.NOT_FOUND:self.selected_listbox.Delete(selected_index)def on_merge(self, event):"""Merge selected PDF files"""if self.selected_listbox.GetCount() == 0:wx.MessageBox("请选择至少一个PDF文件", "警告", wx.OK | wx.ICON_WARNING)return# Ask for output filewith wx.FileDialog(self, "保存合并的PDF", wildcard="PDF files (*.pdf)|*.pdf",style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) as fileDialog:if fileDialog.ShowModal() == wx.ID_CANCEL:returnoutput_path = fileDialog.GetPath()try:merger = PyPDF2.PdfMerger()# Add all selected filesfor i in range(self.selected_listbox.GetCount()):file_path = self.selected_listbox.GetClientData(i)merger.append(file_path)# Write to output filemerger.write(output_path)merger.close()wx.MessageBox(f"PDF文件已成功合并为: {output_path}", "成功", wx.OK | wx.ICON_INFORMATION)except Exception as e:wx.MessageBox(f"合并PDF时出错: {str(e)}", "错误", wx.OK | wx.ICON_ERROR)class PDFMergerApp(wx.App):def OnInit(self):frame = PDFMergerFrame(None, "PDF合并工具")self.SetTopWindow(frame)return Trueif __name__ == "__main__":app = PDFMergerApp()app.MainLoop()
背景

wxPython 是一个基于 wxWidgets 的 Python GUI 库,它提供了创建跨平台桌面应用程序的强大工具。PyPDF2 则是一个 Python 库,用于处理 PDF 文件的操作,如合并、拆分、提取文本等。

本示例程序结合了 wxPython 用于构建图形界面和 PyPDF2 用于处理 PDF 合并的功能。

主要功能
  1. 浏览文件夹:用户可以选择一个文件夹,程序会扫描该文件夹下所有的 PDF 文件。
  2. 选择文件:用户可以从文件夹中选择需要合并的 PDF 文件。
  3. 合并文件:用户选择多个 PDF 文件后,程序会将其合并成一个新的 PDF 文件。

接下来,让我们详细分析代码。

代码解析

1. 初始化 wx.Frame 窗口
python">class PDFMergerFrame(wx.Frame):def __init__(self, parent, title):super(PDFMergerFrame, self).__init__(parent, title=title, size=(900, 600))

我们创建了一个继承自 wx.Frame 的类 PDFMergerFrame,这是应用程序的主窗口。窗口的大小为 900x600

2. 创建工具栏
python"># Create toolbar
self.toolbar = self.CreateToolBar()# Add toolbar buttons
browse_tool = self.toolbar.AddTool(wx.ID_ANY, "浏览", wx.ArtProvider.GetBitmap(wx.ART_FOLDER_OPEN), "浏览文件夹")
merge_tool = self.toolbar.AddTool(wx.ID_ANY, "合成", wx.ArtProvider.GetBitmap(wx.ART_NEW), "合成PDF文件")
self.toolbar.Realize()

在窗口中添加了一个工具栏,并且为工具栏添加了两个按钮:

  • 浏览:用来选择文件夹,浏览文件夹并列出包含 PDF 文件的文件夹。
  • 合成:用来合并用户选择的 PDF 文件。

按钮的图标通过 wx.ArtProvider.GetBitmap 方法加载。

3. 创建布局和界面控件

我们使用 wx.BoxSizer 创建了主界面布局,并将不同的控件添加到面板中。

python"># Create main sizer
main_sizer = wx.BoxSizer(wx.HORIZONTAL)

main_sizer 是一个水平的 BoxSizer,用于将控件横向排列。接下来,我们定义了四个面板,分别用于显示:

  • 文件夹选择:显示文件夹列表。
  • 文件选择:显示当前文件夹中的 PDF 文件。
  • 按钮面板:显示添加和移除文件的按钮。
  • 已选文件:显示用户选择的文件列表。

每个面板使用 wx.Panel 创建,并且通过 wx.ListBox 控件展示文件夹或文件列表。

4. 文件夹扫描功能
python">def scan_folders(self):"""Scan folders and list those with PDF files"""if not self.root_path:returnself.folders_with_files = []self.folder_listbox.Clear()for root, dirs, files in os.walk(self.root_path):has_pdf = Falsefor file in files:if file.lower().endswith('.pdf'):has_pdf = Truebreakif has_pdf:self.folders_with_files.append(root)folder_name = os.path.basename(root) or rootself.folder_listbox.Append(folder_name)

scan_folders 函数扫描用户选择的文件夹并列出其中包含 PDF 文件的子文件夹。使用 os.walk 递归遍历文件夹,并筛选出后缀为 .pdf 的文件。如果文件夹中包含 PDF 文件,则将文件夹添加到 folder_listbox

5. 选择文件夹后的操作
python">def on_folder_select(self, event):"""Handle folder selection"""selected_index = self.folder_listbox.GetSelection()if selected_index == wx.NOT_FOUND:returnselected_folder = self.folders_with_files[selected_index]self.file_listbox.Clear()for file in os.listdir(selected_folder):if file.lower().endswith('.pdf'):self.file_listbox.Append(file)

用户在 folder_listbox 中选择一个文件夹后,on_folder_select 方法会被触发。此时,程序会列出该文件夹中的所有 PDF 文件,并显示在 file_listbox 中供用户选择。

6. 添加和移除文件
python">def on_add_file(self, event):"""Add selected file to the list of files to merge"""selected_file_index = self.file_listbox.GetSelection()selected_folder_index = self.folder_listbox.GetSelection()if selected_file_index == wx.NOT_FOUND or selected_folder_index == wx.NOT_FOUND:returnselected_file = self.file_listbox.GetString(selected_file_index)selected_folder = self.folders_with_files[selected_folder_index]full_path = os.path.join(selected_folder, selected_file)# Check if already in the listfor i in range(self.selected_listbox.GetCount()):if self.selected_listbox.GetClientData(i) == full_path:returnself.selected_listbox.Append(selected_file, full_path)

当用户选择文件并点击 > 按钮时,选中的文件将被添加到 selected_listbox 中。在添加之前,程序会检查该文件是否已经在列表中,防止重复添加。

移除文件的操作也是类似的,用户可以通过 < 按钮从 selected_listbox 中删除已选文件。

7. 合并PDF文件
python">def on_merge(self, event):"""Merge selected PDF files"""if self.selected_listbox.GetCount() == 0:wx.MessageBox("请选择至少一个PDF文件", "警告", wx.OK | wx.ICON_WARNING)return# Ask for output filewith wx.FileDialog(self, "保存合并的PDF", wildcard="PDF files (*.pdf)|*.pdf",style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) as fileDialog:if fileDialog.ShowModal() == wx.ID_CANCEL:returnoutput_path = fileDialog.GetPath()try:merger = PyPDF2.PdfMerger()# Add all selected filesfor i in range(self.selected_listbox.GetCount()):file_path = self.selected_listbox.GetClientData(i)merger.append(file_path)# Write to output filemerger.write(output_path)merger.close()wx.MessageBox(f"PDF文件已成功合并为: {output_path}", "成功", wx.OK | wx.ICON_INFORMATION)except Exception as e:wx.MessageBox(f"合并PDF时出错: {str(e)}", "错误", wx.OK | wx.ICON_ERROR)

最后,合并 PDF 的操作由 on_merge 方法实现。用户选择了要合并的 PDF 文件后,程序会弹出文件保存对话框,询问用户保存合并后文件的位置。使用 PyPDF2.PdfMerger 将所有选择的 PDF 文件合并并保存。

运行结果

在这里插入图片描述


http://www.ppmy.cn/devtools/164529.html

相关文章

互联网时代如何保证数字足迹的安全,以防个人信息泄露?

用户在网络上所做的几乎所有事情&#xff0c;包括浏览、社交媒体活动、搜索查询、在线订阅&#xff0c;甚至购物&#xff0c;都会留下一条数据线索&#xff0c;这些数据可用于创建用户在线身份的详细档案。如果这些信息暴露&#xff0c;恶意行为者可能会利用它们将用户置于各种…

Grafana接入Zabbix数据源

1. 对接 Zabbix 1.1 安装 Zabbix 插件 在线安装&#xff1a; 1.2 配置 Zabbix 数据源 点击 Configuration > Data Sources > Add data source。选择 Zabbix&#xff0c;填写&#xff1a; URL&#xff1a;http://<zabbix-server>/api_jsonrpc.phpUsername&#x…

C# dll文件的反编译获取源码

目录 前言操作流程结论 前言 上一篇文章介绍了将C# cs类文件加密为dll文件&#xff0c;在此给大家写一篇关于反编译dll文件的文章。 操作流程 首先&#xff0c;我们需要准备一个C#反编译工具&#xff0c;我这里用的是免费的软件JetBrains dotPeek&#xff0c;类似的有很多&am…

Windows 环境下 Nginx、PHP 与 ThinkPHP 开发环境搭建

Windows 环境下 Nginx、PHP 与 ThinkPHP 开发环境搭建 目录 安装 Nginx 和 PHP配置 Nginx配置 PHP启动服务ThinkPHP 配置常见问题排查 1. 安装 Nginx 和 PHP 安装 Nginx 访问 Nginx 官网 下载 Windows 版本解压到指定目录&#xff0c;如 C:\nginx 安装 PHP 访问 PHP 官网…

C# 矩形面积和周长的程序(Program for Area And Perimeter Of Rectangle)

矩形是平面上的平面图形。 它有四条边和四个相等的角&#xff0c;每个角都是 90 度。 矩形的四条边并不像正方形那样长度相等&#xff0c;而是彼此相对的边长度相等。 矩形的两条对角线长度相等。 例子&#xff1a; 输入&#xff1a;4 5 输出&#xff1a;面积 20 …

HttpServletRequest 和 HttpServletResponse 不同JDK版本的引入

java中&#xff0c;可能会用到JWT令牌校验&#xff0c; 这时&#xff0c;大概率会用到 HttpServletRequest&#xff0c;和 HttpServletResponse。 若为 JDK8&#xff0c;SpringBoot 2.7.3 的版本则引入&#xff1a; import javax.servlet.http.HttpServletRequest; import ja…

【多线程-第三天-NSOperation的练习-tableView异步下载网络图片-沙盒缓存 Objective-C语言】

一、沙盒缓存 1.下边我们来看沙盒缓存,但是,我们先要来看一下,为什么要学这个东西,为什么要做这件事情,好,我们先来运行一下我们的程序, 好,图片,先是从网络上下载, 下载完成之后,就保存到了内存中,保存到我们那个图片的缓存池中来,现在,我把程序关掉,我再开,图…

数据挖掘中特征发现与特征提取的数学原理

好的&#xff0c;我将深入研究数据挖掘中特征发现与特征提取的数学原理&#xff0c;涵盖统计学基础、特征工程的数学方法、以及在机器学习和深度学习中的应用。 我会整理相关数学公式和理论&#xff0c;包括主成分分析&#xff08;PCA&#xff09;、独立成分分析&#xff08;I…