INTRODUCTION
This program is a user-friendly PDF merger application built using Python’s tkinter library for the GUI and PyPDF2 for managing PDF files. It allows users to seamlessly select multiple PDF files, reorder them as needed, and merge them into a single document. The interface provides intuitive buttons for adding, removing, and reordering files, ensuring a smooth and efficient workflow. Once the desired order is set, the application merges the selected files and saves the output as a new PDF. It is designed for simplicity, making it accessible even to users with minimal technical experience.
PROGRAM
HERE IS THE FULL PROGRAM TO MERGE PDF FILES
import tkinter as tk from tkinter import filedialog, messagebox, simpledialog from PyPDF2 import PdfWriter, PdfReader class PDFMergerApp: def init(self, master): self.master = master self.master.title("PDF Merger") self.master.geometry("600x700") self.master.configure(bg="#f0f0f0") self.file_list = [] self.title_label = tk.Label(master, text="PDF Merger Application", font=("Arial", 14, "bold"), bg="#f0f0f0") self.title_label.pack(pady=10) self.button_frame = tk.Frame(master, bg="#f0f0f0") self.button_frame.pack(pady=5) self.add_button = tk.Button(self.button_frame, text="Add PDF Files", command=self.add_files, bg="#4CAF50", fg="white", padx=10, pady=5) self.add_button.pack(side=tk.LEFT, padx=5) self.remove_button = tk.Button(self.button_frame, text="Remove Selected Files", command=self.remove_file, bg="#f44336", fg="white", padx=10, pady=5) self.remove_button.pack(side=tk.LEFT, padx=5) self.reorder_button = tk.Button(self.button_frame, text="Reorder Files", command=self.reorder_files, bg="#2196F3", fg="white", padx=10, pady=5) self.reorder_button.pack(side=tk.LEFT, padx=5) self.merge_button = tk.Button(self.button_frame, text="Merge PDFs", command=self.merge_pdfs, bg="#FF9800", fg="white", padx=10, pady=5) self.merge_button.pack(side=tk.LEFT, padx=5) self.file_listbox = tk.Listbox(master, width=60, height=15, selectmode=tk.MULTIPLE, bg="#ffffff", fg="#333333", selectbackground="#e0e0e0") self.file_listbox.pack(pady=10) def add_files(self): files = filedialog.askopenfilenames(title="Select PDF Files", filetypes=[("PDF Files", "*.pdf")]) for file in files: if file not in self.file_list: self.file_list.append(file) self.update_file_display() else: messagebox.showwarning("Duplicate File", f"{file} is already in the list.") def remove_file(self): selected_indices = self.file_listbox.curselection() if not selected_indices: messagebox.showwarning("Selection Error", "Please select at least one file to remove.") return for index in reversed(selected_indices): self.file_listbox.delete(index) del self.file_list[index] def reorder_files(self): try: selected_index = self.file_listbox.curselection()[0] new_position = simpledialog.askinteger("Reorder File", "Enter new position (1-based):", minvalue=1, maxvalue=len(self.file_list)) if new_position is not None: new_position -= 1 if 0 <= new_position < len(self.file_list): self.file_list.insert(new_position, self.file_list.pop(selected_index)) self.update_file_display() except IndexError: messagebox.showwarning("Selection Error", "Please select a file to reorder.") def update_file_display(self): self.file_listbox.delete(0, tk.END) for index, file in enumerate(self.file_list, start=1): filename = file.split("/")[-1] self.file_listbox.insert(tk.END, f"File {index}: {filename}") def merge_pdfs(self): if not self.file_list: messagebox.showwarning("No Files", "Please add some PDF files to merge.") return output_file = filedialog.asksaveasfilename(defaultextension=".pdf", filetypes=[("PDF Files", "*.pdf")]) if not output_file: return pdf_writer = PdfWriter() for file in self.file_list: try: pdf_reader = PdfReader(file) for page in range(len(pdf_reader.pages)): pdf_writer.add_page(pdf_reader.pages[page]) except Exception as e: messagebox.showerror("Error", f"Failed to read {file}. Error: {e}") return with open(output_file, "wb") as out_file: pdf_writer.write(out_file) messagebox.showinfo("Success", "PDFs merged successfully!") self.file_list.clear() self.file_listbox.delete(0, tk.END) if name == "main": root = tk.Tk() app = PDFMergerApp(root) root.mainloop()
EXPLANATION OF THE PROGRAM
1. Import Statements
import tkinter as tk from tkinter import filedialog, messagebox, simpledialog from PyPDF2 import PdfWriter, PdfReader
2.PDFMerge class
The PDF merge class encapsulates all functionalities of the PDF merger application.it manages the GUI components and the logic for adding,removing,reordering and merging PDF files
class PDFMergerApp: def __init__(self, master): ...
a.intilization(_init_)
def __init__(self, master): self.master = master self.master.title("PDF Merger") self.master.geometry("600x700") self.master.configure(bg="#f0f0f0") self.file_list = []
The constructor sets up the main window and initializes all GUI components and variables
b.title label
self.title_label = tk.Label(master, text="PDF Merger Application", font=("Arial", 14, "bold"), bg="#f0f0f0") self.title_label.pack(pady=10)
c.button frames and buttons
self.button_frame = tk.Frame(master, bg="#f0f0f0") self.button_frame.pack(pady=5) self.add_button = tk.Button(self.button_frame, text="Add PDF Files", command=self.add_files, bg="#4CAF50", fg="white", padx=10, pady=5) self.add_button.pack(side=tk.LEFT, padx=5) self.remove_button = tk.Button(self.button_frame, text="Remove Selected Files", command=self.remove_file, bg="#f44336", fg="white", padx=10, pady=5) self.remove_button.pack(side=tk.LEFT, padx=5) self.reorder_button = tk.Button(self.button_frame, text="Reorder Files", command=self.reorder_files, bg="#2196F3", fg="white", padx=10, pady=5) self.reorder_button.pack(side=tk.LEFT, padx=5) self.merge_button = tk.Button(self.button_frame, text="Merge PDFs", command=self.merge_pdfs, bg="#FF9800", fg="white", padx=10, pady=5) self.merge_button.pack(side=tk.LEFT, padx=5)
3.Methods of PDF merge class
a.adding files
opens a dialog for users to select multiple PDF files.check for duplicates and ensures the same file isn’t added multiple times. Adds the unique file path.
def add_files(self): files = filedialog.askopenfilenames(title="Select PDF Files", filetypes=[("PDF Files", "*.pdf")]) for file in files: if file not in self.file_list: self.file_list.append(file) self.update_file_display() else: messagebox.showwarning("Duplicate File", f"{file} is already in the list.")
b.Removing files
Retrieves the indices of selected items in the listbox. removes the item from the listbox. Deletes the corresponding file path from the internal.
def remove_file(self): selected_indices = self.file_listbox.curselection() if not selected_indices: messagebox.showwarning("Selection Error", "Please select at least one file to remove.") return for index in reversed(selected_indices): self.file_listbox.delete(index) del self.file_list[index]
c.Recording files
Retrieves the index of the first selected file. removes the file from is current position. Inserts the file at the new position. updates the listbox to reflect the new order.handles the error and cathes cases where no file is selected and prompts the user accordingly.
the fidef reorder_files(self): try: selected_index = self.file_listbox.curselection()[0] new_position = simpledialog.askinteger("Reorder File", "Enter new position (1-based):", minvalue=1, maxvalue=len(self.file_list)) if new_position is not None: new_position -= 1 if 0 <= new_position < len(self.file_list): self.file_list.insert(new_position, self.file_list.pop(selected_index)) self.update_file_display() except IndexError: messagebox.showwarning("Selection Error", "Please select a file to reorder.")
d.Updating files
Remove all current entries in the listbox.Extracts the filename from the full file path.adds each file with its index and filename to the listbox.
def update_file_display(self): self.file_listbox.delete(0, tk.END) for index, file in enumerate(self.file_list, start=1): filename = file.split("/")[-1] self.file_listbox.insert(tk.END, f"File {index}: {filename}")
e.Merging files
opens a dialog for the user to specify the save location and filename. ensures the file is saved. filters to display only PDF files.intilizes a object to compile the merged PDF. opens,reads and iterates through each page of PDF.
def merge_pdfs(self): if not self.file_list: messagebox.showwarning("No Files", "Please add some PDF files to merge.") return output_file = filedialog.asksaveasfilename(defaultextension=".pdf", filetypes=[("PDF Files", "*.pdf")]) if not output_file: return pdf_writer = PdfWriter() for file in self.file_list: try: pdf_reader = PdfReader(file) for page in range(len(pdf_reader.pages)): pdf_writer.add_page(pdf_reader.pages[page]) except Exception as e: messagebox.showerror("Error", f"Failed to read {file}. Error: {e}") return with open(output_file, "wb") as out_file: pdf_writer.write(out_file) messagebox.showinfo("Success", "PDFs merged successfully!") self.file_list.clear() self.file_listbox.delete(0, tk.END)
4.Running the application
Ensures the following code runs only if the script is executed directly,not when imported as a module.intilizes the main tkinter window. starts the tkinter event loop which waits for user interactions
if __name__ == "__main__": root = tk.Tk() app = PDFMergerApp(root) root.mainloop()