Skip to content

Commit acbf6c3

Browse files
authored
Create PDF-Merger-Tool.py
1 parent 6088a7d commit acbf6c3

1 file changed

Lines changed: 120 additions & 0 deletions

File tree

62-PDF-merger/PDF-Merger-Tool.py

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import os
2+
import tkinter as tk
3+
from tkinter import filedialog, messagebox
4+
import ttkbootstrap as tb
5+
from ttkbootstrap.constants import *
6+
from PyPDF2 import PdfMerger
7+
8+
# ---------------- GLOBALS ---------------- #
9+
pdf_files = []
10+
11+
# ---------------- FUNCTIONS ---------------- #
12+
def add_pdfs():
13+
files = filedialog.askopenfilenames(
14+
title="Select PDF files",
15+
filetypes=[("PDF Files", "*.pdf")]
16+
)
17+
for f in files:
18+
if f not in pdf_files:
19+
pdf_files.append(f)
20+
listbox.insert(tk.END, os.path.basename(f))
21+
22+
def remove_selected():
23+
sel = listbox.curselection()
24+
if not sel:
25+
return
26+
index = sel[0]
27+
pdf_files.pop(index)
28+
listbox.delete(index)
29+
30+
def move_up():
31+
sel = listbox.curselection()
32+
if not sel or sel[0] == 0:
33+
return
34+
i = sel[0]
35+
pdf_files[i-1], pdf_files[i] = pdf_files[i], pdf_files[i-1]
36+
refresh_list()
37+
listbox.selection_set(i-1)
38+
39+
def move_down():
40+
sel = listbox.curselection()
41+
if not sel or sel[0] == len(pdf_files)-1:
42+
return
43+
i = sel[0]
44+
pdf_files[i+1], pdf_files[i] = pdf_files[i], pdf_files[i+1]
45+
refresh_list()
46+
listbox.selection_set(i+1)
47+
48+
def refresh_list():
49+
listbox.delete(0, tk.END)
50+
for f in pdf_files:
51+
listbox.insert(tk.END, os.path.basename(f))
52+
53+
def merge_pdfs():
54+
if not pdf_files:
55+
messagebox.showwarning("No Files", "Add PDF files first.")
56+
return
57+
58+
output_path = filedialog.asksaveasfilename(
59+
defaultextension=".pdf",
60+
filetypes=[("PDF Files", "*.pdf")],
61+
title="Save merged PDF as"
62+
)
63+
if not output_path:
64+
return
65+
66+
try:
67+
merger = PdfMerger()
68+
for pdf in pdf_files:
69+
merger.append(pdf)
70+
merger.write(output_path)
71+
merger.close()
72+
messagebox.showinfo("Success", "PDFs merged successfully!")
73+
except Exception as e:
74+
messagebox.showerror("Error", str(e))
75+
76+
# Drag & Drop reorder
77+
drag_data = None
78+
def on_drag_start(event):
79+
global drag_data
80+
drag_data = listbox.nearest(event.y)
81+
82+
def on_drag_release(event):
83+
global drag_data
84+
if drag_data is None:
85+
return
86+
drop_index = listbox.nearest(event.y)
87+
if drop_index != drag_data:
88+
pdf_files.insert(drop_index, pdf_files.pop(drag_data))
89+
refresh_list()
90+
listbox.selection_set(drop_index)
91+
drag_data = None
92+
93+
# ---------------- GUI ---------------- #
94+
app = tb.Window(
95+
title="PDF Merger Tool",
96+
themename="darkly",
97+
size=(700, 450)
98+
)
99+
100+
main_frame = tb.Frame(app)
101+
main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
102+
103+
# Listbox
104+
listbox = tk.Listbox(main_frame, height=15)
105+
listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
106+
listbox.bind("<Button-1>", on_drag_start)
107+
listbox.bind("<ButtonRelease-1>", on_drag_release)
108+
109+
# Controls
110+
control_frame = tb.Frame(main_frame)
111+
control_frame.pack(side=tk.RIGHT, fill=tk.Y, padx=10)
112+
113+
tb.Button(control_frame, text="Add PDFs", bootstyle="primary", command=add_pdfs).pack(fill=tk.X, pady=5)
114+
tb.Button(control_frame, text="Remove Selected", bootstyle="danger", command=remove_selected).pack(fill=tk.X, pady=5)
115+
tb.Button(control_frame, text="Move Up", bootstyle="secondary", command=move_up).pack(fill=tk.X, pady=5)
116+
tb.Button(control_frame, text="Move Down", bootstyle="secondary", command=move_down).pack(fill=tk.X, pady=5)
117+
tb.Separator(control_frame).pack(fill=tk.X, pady=10)
118+
tb.Button(control_frame, text="Merge PDFs", bootstyle="success", command=merge_pdfs).pack(fill=tk.X, pady=5)
119+
120+
app.mainloop()

0 commit comments

Comments
 (0)