使用Python創(chuàng)建一個(gè)能夠篩選文件的PDF合并工具
背景
wxPython 是一個(gè)基于 wxWidgets 的 Python GUI 庫,它提供了創(chuàng)建跨平臺桌面應(yīng)用程序的強(qiáng)大工具。PyPDF2 則是一個(gè) Python 庫,用于處理 PDF 文件的操作,如合并、拆分、提取文本等。
本示例程序結(jié)合了 wxPython 用于構(gòu)建圖形界面和 PyPDF2 用于處理 PDF 合并的功能。
這款 PDF 合并工具允許用戶瀏覽文件夾、選擇 PDF 文件,并將其合并為一個(gè)新的 PDF 文件。我們將詳細(xì)分析代碼結(jié)構(gòu)和如何一步步實(shí)現(xiàn)每個(gè)功能。
主要功能
瀏覽文件夾:用戶可以選擇一個(gè)文件夾,程序會掃描該文件夾下所有的 PDF 文件。
選擇文件:用戶可以從文件夾中選擇需要合并的 PDF 文件。
合并文件:用戶選擇多個(gè) PDF 文件后,程序會將其合并成一個(gè)新的 PDF 文件。
全部代碼
import os import wx import PyPDF2 class PDFMergerFrame(wx.Frame): def __init__(self, parent, title): super(PDFMergerFrame, self).__init__(parent, title=title, size=(900, 600)) # Create main panel self.panel = wx.Panel(self) # 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() # Bind toolbar events self.Bind(wx.EVT_TOOL, self.on_browse, browse_tool) self.Bind(wx.EVT_TOOL, self.on_merge, merge_tool) # Create main sizer main_sizer = wx.BoxSizer(wx.HORIZONTAL) # Create left panel for folders left_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 files middle_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 panel button_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 files right_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 sizer main_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 sizer self.panel.SetSizerAndFit(main_sizer) # # Set main sizer # self.panel.SetSizerAndFit(main_sizer) # Bind events self.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 variables self.root_path = "" self.folders_with_files = [] # Center and show frame self.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: return self.folders_with_files = [] self.folder_listbox.Clear() for root, dirs, files in os.walk(self.root_path): has_pdf = False for file in files: if file.lower().endswith('.pdf'): has_pdf = True break if has_pdf: self.folders_with_files.append(root) folder_name = os.path.basename(root) or root self.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: return selected_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: return selected_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 list for i in range(self.selected_listbox.GetCount()): if self.selected_listbox.GetClientData(i) == full_path: return self.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("請選擇至少一個(gè)PDF文件", "警告", wx.OK | wx.ICON_WARNING) return # Ask for output file with 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: return output_path = fileDialog.GetPath() try: merger = PyPDF2.PdfMerger() # Add all selected files for i in range(self.selected_listbox.GetCount()): file_path = self.selected_listbox.GetClientData(i) merger.append(file_path) # Write to output file merger.write(output_path) merger.close() wx.MessageBox(f"PDF文件已成功合并為: {output_path}", "成功", wx.OK | wx.ICON_INFORMATION) except Exception as e: wx.MessageBox(f"合并PDF時(shí)出錯(cuò): {str(e)}", "錯(cuò)誤", wx.OK | wx.ICON_ERROR) class PDFMergerApp(wx.App): def OnInit(self): frame = PDFMergerFrame(None, "PDF合并工具") self.SetTopWindow(frame) return True if __name__ == "__main__": app = PDFMergerApp() app.MainLoop()
接下來,讓我們詳細(xì)分析代碼。
代碼解析
1. 初始化 wx.Frame 窗口
class PDFMergerFrame(wx.Frame): def __init__(self, parent, title): super(PDFMergerFrame, self).__init__(parent, title=title, size=(900, 600))
我們創(chuàng)建了一個(gè)繼承自 wx.Frame 的類 PDFMergerFrame,這是應(yīng)用程序的主窗口。窗口的大小為 900x600。
2. 創(chuàng)建工具欄
# 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()
在窗口中添加了一個(gè)工具欄,并且為工具欄添加了兩個(gè)按鈕:
- 瀏覽:用來選擇文件夾,瀏覽文件夾并列出包含 PDF 文件的文件夾。
- 合成:用來合并用戶選擇的 PDF 文件。
按鈕的圖標(biāo)通過 wx.ArtProvider.GetBitmap 方法加載。
3. 創(chuàng)建布局和界面控件
我們使用 wx.BoxSizer 創(chuàng)建了主界面布局,并將不同的控件添加到面板中。
# Create main sizer main_sizer = wx.BoxSizer(wx.HORIZONTAL)
main_sizer 是一個(gè)水平的 BoxSizer,用于將控件橫向排列。接下來,我們定義了四個(gè)面板,分別用于顯示:
- 文件夾選擇:顯示文件夾列表。
- 文件選擇:顯示當(dāng)前文件夾中的 PDF 文件。
- 按鈕面板:顯示添加和移除文件的按鈕。
- 已選文件:顯示用戶選擇的文件列表。
每個(gè)面板使用 wx.Panel 創(chuàng)建,并且通過 wx.ListBox 控件展示文件夾或文件列表。
4. 文件夾掃描功能
def scan_folders(self): """Scan folders and list those with PDF files""" if not self.root_path: return self.folders_with_files = [] self.folder_listbox.Clear() for root, dirs, files in os.walk(self.root_path): has_pdf = False for file in files: if file.lower().endswith('.pdf'): has_pdf = True break if has_pdf: self.folders_with_files.append(root) folder_name = os.path.basename(root) or root self.folder_listbox.Append(folder_name)
scan_folders 函數(shù)掃描用戶選擇的文件夾并列出其中包含 PDF 文件的子文件夾。使用 os.walk 遞歸遍歷文件夾,并篩選出后綴為 .pdf 的文件。如果文件夾中包含 PDF 文件,則將文件夾添加到 folder_listbox。
5. 選擇文件夾后的操作
def on_folder_select(self, event): """Handle folder selection""" selected_index = self.folder_listbox.GetSelection() if selected_index == wx.NOT_FOUND: return selected_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 中選擇一個(gè)文件夾后,on_folder_select 方法會被觸發(fā)。此時(shí),程序會列出該文件夾中的所有 PDF 文件,并顯示在 file_listbox 中供用戶選擇。
6. 添加和移除文件
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: return selected_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 list for i in range(self.selected_listbox.GetCount()): if self.selected_listbox.GetClientData(i) == full_path: return self.selected_listbox.Append(selected_file, full_path)
當(dāng)用戶選擇文件并點(diǎn)擊 > 按鈕時(shí),選中的文件將被添加到 selected_listbox 中。在添加之前,程序會檢查該文件是否已經(jīng)在列表中,防止重復(fù)添加。
移除文件的操作也是類似的,用戶可以通過 < 按鈕從 selected_listbox 中刪除已選文件。
7. 合并PDF文件
def on_merge(self, event): """Merge selected PDF files""" if self.selected_listbox.GetCount() == 0: wx.MessageBox("請選擇至少一個(gè)PDF文件", "警告", wx.OK | wx.ICON_WARNING) return # Ask for output file with 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: return output_path = fileDialog.GetPath() try: merger = PyPDF2.PdfMerger() # Add all selected files for i in range(self.selected_listbox.GetCount()): file_path = self.selected_listbox.GetClientData(i) merger.append(file_path) # Write to output file merger.write(output_path) merger.close() wx.MessageBox(f"PDF文件已成功合并為: {output_path}", "成功", wx.OK | wx.ICON_INFORMATION) except Exception as e: wx.MessageBox(f"合并PDF時(shí)出錯(cuò): {str(e)}", "錯(cuò)誤", wx.OK | wx.ICON_ERROR)
最后,合并 PDF 的操作由 on_merge 方法實(shí)現(xiàn)。用戶選擇了要合并的 PDF 文件后,程序會彈出文件保存對話框,詢問用戶保存合并后文件的位置。使用 PyPDF2.PdfMerger 將所有選擇的 PDF 文件合并并保存。
運(yùn)行結(jié)果
以上就是使用Python創(chuàng)建一個(gè)能夠篩選文件的PDF合并工具的詳細(xì)內(nèi)容,更多關(guān)于Python PDF合并的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Matplotlib繪制混淆矩陣的實(shí)現(xiàn)
對于機(jī)器學(xué)習(xí)多分類模型來說,其評價(jià)指標(biāo)除了精度之外,常用的還有混淆矩陣和分類報(bào)告,下面來展示一下如何繪制混淆矩陣,這在論文中經(jīng)常會用到。感興趣的可以了解一下2021-05-05Python使用進(jìn)程池并發(fā)執(zhí)行SQL語句的操作代碼
Python的進(jìn)程池是一種并發(fā)工具,它允許我們將任務(wù)分發(fā)給一組工作進(jìn)程,這些進(jìn)程可以同時(shí)運(yùn)行并共享一個(gè)進(jìn)程池,本文給大家介紹了Python使用進(jìn)程池并發(fā)執(zhí)行SQL語句的操作代碼,需要的朋友可以參考下2024-10-10python使用requests模塊實(shí)現(xiàn)爬取電影天堂最新電影信息
這篇文章主要介紹了python使用requests模塊實(shí)現(xiàn)爬取電影天堂最新電影信息,本文通過實(shí)例代碼給大家介紹了str/list/tuple三者之間怎么相互轉(zhuǎn)換,需要的朋友可以參考下2019-04-04python 將字符串轉(zhuǎn)換成字典dict的各種方式總結(jié)
下面小編就為大家分享一篇python 將字符串轉(zhuǎn)換成字典dict的各種方式總結(jié),具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-03-03使用ITK-SNAP進(jìn)行摳圖操作并保存mask的實(shí)例
這篇文章主要介紹了使用ITK-SNAP進(jìn)行摳圖操作并保存mask的實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-07-07Python調(diào)用C/C++動(dòng)態(tài)鏈接庫的方法詳解
這篇文章主要介紹了Python調(diào)用C/C++動(dòng)態(tài)鏈接庫的方法,需要的朋友可以參考下2014-07-07Python使用Flask框架實(shí)現(xiàn)文件上傳實(shí)例
這篇文章主要介紹了Python使用Flask庫文件上傳實(shí)例,用?Flask?處理文件上傳很容易,只要確保HTML表單中設(shè)置enctype="multipart/form-data"屬性就可以了,需要的朋友可以參考下2023-08-08