PDF Pythonツール tkinter ドラッグアンドドロップ(複数ファイル) ファイル指定

PythonでPDFファイルを結合してしおりを自動作成する方法・その3

はじめに:PDF結合ツールの概要

PDFファイルの結合は、ビジネスや学術の場面で頻繁に必要とされる作業です。本記事では、Pythonを使用して作成した、使いやすいGUIベースのPDF結合ツールを紹介します。このツールを使用することで、複数のPDFファイルを簡単に、かつ柔軟に結合することができます。

主な特徴

  • ドラッグ&ドロップでのファイル追加
  • ファイルの並び順をカスタマイズ可能
  • 名前の昇順・降順での自動ソート機能
  • 進捗バーによる結合プロセスの可視化

使用例:このツールでどんなことができるか

  1. 会議資料の統合: 複数の部署から送られてきたPDFファイルを1つの資料にまとめる
  2. 学術論文の作成: 序論、本論、結論、参考文献など、別々に作成したPDFを1つの論文にまとめる
  3. 電子書籍の作成: 章ごとに作成したPDFファイルを1冊の電子書籍として結合する
  4. 請求書の一括管理: 月ごとの請求書PDFを年間レポートとして結合する

インストール方法:必要な環境を整える

このツールを使用するには、以下のソフトウェアとライブラリが必要です:

  1. Python 3.6以上
  2. PyPDF2
  3. tkinter (通常はPythonに同梱)
  4. tkinterdnd2

インストール手順:

  1. Pythonをインストール(公式サイトからダウンロード)
  2. コマンドプロンプトまたはターミナルで以下のコマンドを実行:
pip install PyPDF2 tkinterdnd2

使用手順:ステップバイステップガイド

  1. プログラムを起動する
  2. 「ファイルをドラッグ&ドロップ」エリアにPDFファイルをドラッグする
  3. 必要に応じて、ファイルの順序を変更する:
    • 「↑」「↓」ボタンでファイルを移動
    • 「削除」ボタンで不要なファイルを削除
    • ラジオボタンで「名前の昇順」「名前の降順」「カスタム」を選択
  4. 「PDFを結合」ボタンをクリック
  5. 保存先とファイル名を指定
  6. 結合完了のメッセージを確認

注意点:使用時の留意事項

  • 結合するPDFファイルは2つ以上必要です
  • 大きなサイズのPDFファイルを結合する場合、処理に時間がかかる可能性があります
  • 暗号化されたPDFファイルは結合できません
  • 結合後のPDFファイルサイズに注意してください(特に多数のファイルを結合する場合)

プログラム

import tkinter as tk
from tkinter import filedialog, messagebox
from tkinter.ttk import Progressbar
import PyPDF2
import os
from tkinterdnd2 import DND_FILES, TkinterDnD

class PDFMergerGUI:
 def init(self, master):
  self.master = master
  master.title("PDF Merger")
  master.geometry("500x450")   
  self.pdf_files = []

    # ファイルリストとスクロールバー
    list_frame = tk.Frame(master)
    list_frame.pack(pady=10, padx=10, fill=tk.BOTH, expand=True)

    self.file_listbox = tk.Listbox(list_frame, selectmode=tk.SINGLE, height=10)
    self.file_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
    self.file_listbox.drop_target_register(DND_FILES)
    self.file_listbox.dnd_bind('<<Drop>>', self.drop)
    self.file_listbox.bind('<<ListboxSelect>>', self.on_select)

    scrollbar = tk.Scrollbar(list_frame, orient="vertical")
    scrollbar.config(command=self.file_listbox.yview)
    scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
    self.file_listbox.config(yscrollcommand=scrollbar.set)

    # ボタンフレーム
    button_frame = tk.Frame(master)
    button_frame.pack(pady=5)

    # 上下移動ボタン
    self.up_button = tk.Button(button_frame, text="↑", command=self.move_up, state=tk.DISABLED)
    self.up_button.pack(side=tk.LEFT)
    self.down_button = tk.Button(button_frame, text="↓", command=self.move_down, state=tk.DISABLED)
    self.down_button.pack(side=tk.LEFT)

    # 削除ボタン
    self.delete_button = tk.Button(button_frame, text="削除", command=self.delete_selected, state=tk.DISABLED)
    self.delete_button.pack(side=tk.LEFT, padx=(20, 0))

    # ソート順序選択用のラジオボタン
    self.sort_var = tk.StringVar(value="custom")
    sort_frame = tk.Frame(master)
    sort_frame.pack(pady=5)
    tk.Radiobutton(sort_frame, text="名前の昇順", variable=self.sort_var, value="asc", command=self.update_sort).pack(side=tk.LEFT)
    tk.Radiobutton(sort_frame, text="名前の降順", variable=self.sort_var, value="desc", command=self.update_sort).pack(side=tk.LEFT)
    tk.Radiobutton(sort_frame, text="カスタム", variable=self.sort_var, value="custom", command=self.update_sort).pack(side=tk.LEFT)

    # 結合ボタン
    self.merge_button = tk.Button(master, text="PDFを結合", command=self.merge_pdfs)
    self.merge_button.pack(pady=5)

    # プログレスバー
    self.progress = Progressbar(master, orient=tk.HORIZONTAL, length=300, mode='determinate')
    self.progress.pack(pady=5)

def drop(self, event):
    files = event.data.split()
    for file in files:
        if file.lower().endswith('.pdf'):
            file = file.strip('{}')  # 波括弧を削除
            if file not in self.pdf_files:
                self.pdf_files.append(file)
                self.file_listbox.insert(tk.END, os.path.basename(file))
        else:
            messagebox.showwarning("警告", f"{file} はPDFファイルではありません。")
    self.update_sort()

def on_select(self, event):
    if self.file_listbox.curselection():
        self.up_button.config(state=tk.NORMAL)
        self.down_button.config(state=tk.NORMAL)
        self.delete_button.config(state=tk.NORMAL)
    else:
        self.up_button.config(state=tk.DISABLED)
        self.down_button.config(state=tk.DISABLED)
        self.delete_button.config(state=tk.DISABLED)

def move_up(self):
    selected = self.file_listbox.curselection()[0]
    if selected > 0:
        text = self.file_listbox.get(selected)
        self.file_listbox.delete(selected)
        self.file_listbox.insert(selected - 1, text)
        self.file_listbox.select_set(selected - 1)
        self.pdf_files[selected], self.pdf_files[selected - 1] = self.pdf_files[selected - 1], self.pdf_files[selected]

def move_down(self):
    selected = self.file_listbox.curselection()[0]
    if selected < self.file_listbox.size() - 1:
        text = self.file_listbox.get(selected)
        self.file_listbox.delete(selected)
        self.file_listbox.insert(selected + 1, text)
        self.file_listbox.select_set(selected + 1)
        self.pdf_files[selected], self.pdf_files[selected + 1] = self.pdf_files[selected + 1], self.pdf_files[selected]

def delete_selected(self):
    selected = self.file_listbox.curselection()
    if selected:
        index = selected[0]
        self.file_listbox.delete(index)
        del self.pdf_files[index]
        if self.file_listbox.size() > 0:
            if index == self.file_listbox.size():
                self.file_listbox.select_set(index - 1)
            else:
                self.file_listbox.select_set(index)
        self.on_select(None)  # ボタンの状態を更新

def update_sort(self):
    sort_type = self.sort_var.get()
    if sort_type != "custom":
        self.pdf_files.sort(key=lambda x: os.path.basename(x), reverse=(sort_type == "desc"))
        self.file_listbox.delete(0, tk.END)
        for file in self.pdf_files:
            self.file_listbox.insert(tk.END, os.path.basename(file))

def merge_pdfs(self):
    if len(self.pdf_files) < 2:
        messagebox.showwarning("警告", "結合するには少なくとも2つのPDFファイルが必要です。")
        return

    output_file = filedialog.asksaveasfilename(defaultextension=".pdf", filetypes=[("PDF files", "*.pdf")])
    if not output_file:
        return

    merger = PyPDF2.PdfMerger()

    total_files = len(self.pdf_files)
    self.progress['value'] = 0
    self.progress['maximum'] = total_files

    for i, file in enumerate(self.pdf_files):
        with open(file, 'rb') as f:
            merger.append(f, outline_item=os.path.basename(file))
        self.progress['value'] = i + 1
        self.master.update_idletasks()

    merger.write(output_file)
    merger.close()

    messagebox.showinfo("完了", f"PDFの結合が完了しました。\n保存先: {output_file}")
    self.pdf_files = []
    self.file_listbox.delete(0, tk.END)
    self.progress['value'] = 0

if name == "main":
  root = TkinterDnD.Tk()
  gui = PDFMergerGUI(root)
  root.mainloop()

あるいは、下のテキストファイルをダウンロードし、「.txt」を「.py」に変えることでそのまま使えます。

まとめ:PDF結合ツールの可能性

本記事で紹介したPDF結合ツールは、ビジネスや学術の現場で大いに役立つ可能性を秘めています。Pythonの強力な機能とシンプルなGUIを組み合わせることで、複雑なPDF操作を誰でも簡単に行えるようになります。

PDFファイルの操作は、デジタル時代のドキュメント管理において重要な役割を果たします。このツールを起点として、より高度なPDF操作ツールの開発に挑戦してみてはいかがでしょうか。

-PDF, Pythonツール, tkinter, ドラッグアンドドロップ(複数ファイル), ファイル指定