Robert Johns | 24 Jan, 2025
Fact checked by Jim Markus

How To Create A PDF Merger App with Python with GUI

Have you ever needed to combine multiple PDF files into one but didn’t want to rely on online tools?

In this tutorial, I’ll show you how to build a Python program that merges PDF files seamlessly using Object-Oriented Programming (OOP). By the end, you’ll have a simple application with a graphical user interface (GUI) that allows users to select PDF files, merge them, and save the result with just a few clicks.

This project is beginner-friendly and demonstrates how to use Python libraries for PDF manipulation and GUI development. Let’s get started!

Why Build a PDF Merger App?

A PDF merger app is a practical Python project to enhance your Python skills. Here’s what you’ll learn:

  • Using the PyPDF2 library to manipulate PDF files.
  • Leveraging tkinter to create a graphical user interface.
  • Understanding Object-Oriented Programming (OOP) by structuring the app as a class.

The thing I like the most about this project is that it's not only educational but genuinely useful. It's also a great addition to your portfolio, as it shows you can build something that people really need.

Let’s dive in!

Project Prerequisites

Before we begin coding, let’s review the skills and tools needed for this tutorial.

Don’t worry if you’re not a Python expert just yet! Having a few basics under your belt will make this journey smoother and more enjoyable.

Basic Python Knowledge

You should be familiar with:

  • Variables, functions, and loops.
  • Basic file handling and exception handling.

Required Libraries

We’ll use the following Python libraries:

  • PyPDF2 for merging PDF files.
  • tkinter for creating the GUI.

If you don't already have PyPDF2 installed, just run this command:

pip install PyPDF2

A Curious and Experimental Mind

To my mind, experimenting and making small adjustments are the keys to learning. So be ready to explore and debug as you go along!

Step 1: Set Up Your Project

Before I jump into coding, let’s set up the project:

1. Make sure Python is installed on your computer. If not, download it from the official Python website.
2. Open your favorite code editor or IDE.
3. Create a new Python file, for example, pdf_merger.py.

Step 2: Import Required Libraries

Let’s start by importing the libraries we’ll use:

import tkinter as tk
from tkinter import filedialog, messagebox
from PyPDF2 import PdfMerger

tkinter is used to create the graphical interface for the app.

PdfMerger from PyPDF2 will allow us to combine multiple PDF files into one single PDF file.

Step 2: Using Object-Oriented Programming in the App

We’ll structure the app using a Python class. I like this approach as it organizes related data and methods together, making the code reusable and easier to maintain.

The PDFMergerApp class will:

- Initialize the app window and its components.
- Define methods for adding, removing, and merging PDF files.
- Handle user interactions with the graphical interface.

Here’s the structure of the class:

class PDFMergerApp:
    def __init__(self, root):
        # Initialize the app window and variables

    def create_widgets(self):
        # Set up the GUI components

    def add_files(self):
        # Add PDF files to the list

    def remove_selected(self):
        # Remove selected PDF files from the list

    def merge_pdfs(self):
        # Merge the selected PDF files

Step 3: Build the GUI with OOP

Initialize the Main Window

Here’s how the __init__ method sets up the main application window:

class PDFMergerApp:
    def __init__(self, root):
        self.root = root
        self.root.title("PDF Merger")
        self.root.geometry("600x400")
        self.root.configure(bg="#f0f4f7")

        self.pdf_files = []

        self.create_widgets()

- self.root sets the main window properties.
- self.pdf_files stores the list of selected PDF files.
- self.create_widgets() initializes the GUI components.

Create the Widgets

We'll then use the create_widgets method to set up labels, buttons, and a listbox. That said, I'd highly encourage you to experiment with this stage and try out various designs and layouts to expand your tkinter skills.

def create_widgets(self):
    # Title Label
    title_label = tk.Label(
        self.root, text="PDF Merger", font=("Arial", 20), bg="#f0f4f7", fg="#333"
    )
    title_label.pack(pady=10)

    # Listbox to display selected PDF files
    self.listbox = tk.Listbox(
        self.root, selectmode=tk.MULTIPLE, width=50, height=10, font=("Arial", 12)
    )
    self.listbox.pack(pady=10)

    # Buttons Frame
    button_frame = tk.Frame(self.root, bg="#f0f4f7")
    button_frame.pack(pady=10)

    # Add File Button
    add_file_button = tk.Button(
        button_frame,
        text="Add Files",
        command=self.add_files,
        bg="#007bff",
        fg="white",
        font=("Arial", 12),
        padx=10,
        pady=5,
    )
    add_file_button.pack(side="left", padx=5)

    # Remove File Button
    remove_file_button = tk.Button(
        button_frame,
        text="Remove Selected",
        command=self.remove_selected,
        bg="#dc3545",
        fg="white",
        font=("Arial", 12),
        padx=10,
        pady=5,
    )
    remove_file_button.pack(side="left", padx=5)

    # Merge PDFs Button
    merge_button = tk.Button(
        self.root,
        text="Merge PDFs",
        command=self.merge_pdfs,
        bg="#28a745",
        fg="white",
        font=("Arial", 14),
        padx=20,
        pady=10,
    )
    merge_button.pack(pady=20)

- The create_widgets method organizes GUI elements for better readability and modularity.
- Buttons call specific methods like self.add_files and self.merge_pdfs.

Step 4: Add Functionality with OOP

Add Files

The add_files method lets users select and display PDF files:

def add_files(self):
    files = filedialog.askopenfilenames(
        filetypes=[("PDF Files", "*.pdf")], title="Select PDF Files"
    )
    for file in files:
        if file not in self.pdf_files:
            self.pdf_files.append(file)
            self.listbox.insert(tk.END, file)

Remove Selected Files

The remove_selected method removes selected files:

def remove_selected(self):
    selected_indices = self.listbox.curselection()
    for index in reversed(selected_indices):
        self.pdf_files.pop(index)
        self.listbox.delete(index)

Merge PDFs

The merge_pdfs method combines the selected PDFs:

def merge_pdfs(self):
    if not self.pdf_files:
        messagebox.showwarning("No Files", "Please add at least two PDF files to merge.")
        return

    save_path = filedialog.asksaveasfilename(
        defaultextension=".pdf",
        filetypes=[("PDF Files", "*.pdf")],
        title="Save Merged PDF As",
    )
    if not save_path:
        return

    try:
        merger = PdfMerger()
        for pdf_file in self.pdf_files:
            merger.append(pdf_file)

        merger.write(save_path)
        merger.close()

        messagebox.showinfo("Success", f"Merged PDF saved to:\n{save_path}")
    except Exception as e:
        messagebox.showerror("Error", f"An error occurred while merging PDFs:\n{e}")

Step 5: Run the Application

Finally, initialize and run the app:

if __name__ == "__main__":
    root = tk.Tk()
    app = PDFMergerApp(root)
    root.mainloop()

With this block, we create the Tkinter root window, instantiate an instance of the PDFMergerAPp class, and then start the Tkinter event loop with root.mainloop().

Full Program Source Code

Here’s the complete code for the Python PDF Merger App:

'''
Hackr.io Python Tutorial: PDF Merger
'''
import tkinter as tk
from tkinter import filedialog, messagebox
from PyPDF2 import PdfMerger


class PDFMergerApp:
    def __init__(self, root):
        self.root = root
        self.root.title("PDF Merger")
        self.root.geometry("600x400")
        self.root.configure(bg="#f0f4f7")

        self.pdf_files = []

        self.create_widgets()

    def create_widgets(self):
        # Title Label
        title_label = tk.Label(
            self.root, text="PDF Merger", font=("Arial", 20), bg="#f0f4f7", fg="#333"
        )
        title_label.pack(pady=10)

        # Listbox to display selected PDF files
        self.listbox = tk.Listbox(
            self.root, selectmode=tk.MULTIPLE, width=50, height=10, font=("Arial", 12)
        )
        self.listbox.pack(pady=10)

        # Buttons Frame
        button_frame = tk.Frame(self.root, bg="#f0f4f7")
        button_frame.pack(pady=10)

        # Add File Button
        add_file_button = tk.Button(
            button_frame,
            text="Add Files",
            command=self.add_files,
            bg="#007bff",
            fg="white",
            font=("Arial", 12),
            padx=10,
            pady=5,
        )
        add_file_button.pack(side="left", padx=5)

        # Remove File Button
        remove_file_button = tk.Button(
            button_frame,
            text="Remove Selected",
            command=self.remove_selected,
            bg="#dc3545",
            fg="white",
            font=("Arial", 12),
            padx=10,
            pady=5,
        )
        remove_file_button.pack(side="left", padx=5)

        # Merge PDFs Button
        merge_button = tk.Button(
            self.root,
            text="Merge PDFs",
            command=self.merge_pdfs,
            bg="#28a745",
            fg="white",
            font=("Arial", 14),
            padx=20,
            pady=10,
        )
        merge_button.pack(pady=20)

    def add_files(self):
        files = filedialog.askopenfilenames(
            filetypes=[("PDF Files", "*.pdf")], title="Select PDF Files"
        )
        for file in files:
            if file not in self.pdf_files:
                self.pdf_files.append(file)
                self.listbox.insert(tk.END, file)

    def remove_selected(self):
        selected_indices = self.listbox.curselection()
        for index in reversed(selected_indices):
            self.pdf_files.pop(index)
            self.listbox.delete(index)

    def merge_pdfs(self):
        if not self.pdf_files:
            messagebox.showwarning(
                "No Files", "Please add at least two PDF files to merge.")
            return

        save_path = filedialog.asksaveasfilename(
            defaultextension=".pdf",
            filetypes=[("PDF Files", "*.pdf")],
            title="Save Merged PDF As",
        )
        if not save_path:
            return

        try:
            merger = PdfMerger()
            for pdf_file in self.pdf_files:
                merger.append(pdf_file)

            merger.write(save_path)
            merger.close()

            messagebox.showinfo(
                "Success", f"Merged PDF saved to:\n{save_path}")
        except Exception as e:
            messagebox.showerror(
                "Error", f"An error occurred while merging PDFs:\n{e}")


# Main Application
if __name__ == "__main__":
    root = tk.Tk()
    app = PDFMergerApp(root)
    root.mainloop()

Wrapping Up

Congratulations! You’ve just built a Python PDF merger app using OOP, that's quite something! Hopefully, this project has shown you how Python can combine libraries like PyPDF2 and tkinter to create practical and genuinely useful applications.

Feel free to expand this project by:

  • Allowing users to rearrange the order of selected files.
  • Adding a preview feature to display the content of selected PDFs.
  • Supporting other file types, such as images or text files.

Happy coding!

By Robert Johns

Technical Editor for Hackr.io | 15+ Years in Python, Java, SQL, C++, C#, JavaScript, Ruby, PHP, .NET, MATLAB, HTML & CSS, and more... 10+ Years in Networking, Cloud, APIs, Linux | 5+ Years in Data Science | 2x PhDs in Structural & Blast Engineering

View all post by the author

Subscribe to our Newsletter for Articles, News, & Jobs.

I accept the Terms and Conditions.

Disclosure: Hackr.io is supported by its audience. When you purchase through links on our site, we may earn an affiliate commission.

In this article

Learn More

Please login to leave comments