Python

Pythonで作るExcel編集アプリ|ExcelEditorAppでデータ編集をもっと快適に(App005)

tyamada

1. ExcelEditorApp の紹介


今回紹介する「ExcelEditorApp」は、Python と tkinter、そして openpyxl を組み合わせて作成した、ExcelファイルをGUIで直感的に操作できるデスクトップアプリです。
Excel を開かなくてもデータの閲覧・編集・保存ができ、日常的な作業が圧倒的に効率化できます。

ソースコードを全て表示
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import openpyxl
import copy

class ExcelEditorApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Excel簡易編集ツール")
        self.root.geometry("900x600")

        # Excel関連
        self.wb = None
        self.sheet = None
        self.sheet_data = []
        self.undo_stack = []

        # GUI構築
        self.create_widgets()

    def create_widgets(self):
        # 上部ボタンフレーム
        frame = ttk.Frame(self.root)
        frame.pack(fill=tk.X, padx=5, pady=5)

        ttk.Button(frame, text="Excel読み込み", command=self.load_excel).pack(side=tk.LEFT, padx=5)
        self.sheet_cb = ttk.Combobox(frame, state="readonly")
        self.sheet_cb.pack(side=tk.LEFT, padx=5)
        self.sheet_cb.bind("<<ComboboxSelected>>", self.change_sheet)

        ttk.Button(frame, text="保存", command=self.save_excel).pack(side=tk.LEFT, padx=5)
        ttk.Button(frame, text="Undo", command=self.undo).pack(side=tk.LEFT, padx=5)

        # フィルタ / ソート
        ttk.Label(frame, text="フィルタ(列番号=値):").pack(side=tk.LEFT, padx=5)
        self.filter_entry = ttk.Entry(frame, width=15)
        self.filter_entry.pack(side=tk.LEFT, padx=5)
        ttk.Button(frame, text="適用", command=self.apply_filter).pack(side=tk.LEFT, padx=5)
        ttk.Button(frame, text="リセット", command=self.reset_filter).pack(side=tk.LEFT, padx=5)

        # Treeview
        self.tree = ttk.Treeview(self.root, show="headings")
        self.tree.pack(fill=tk.BOTH, expand=True)
        self.tree.bind("<Double-1>", self.edit_cell)

        # スクロールバー
        vsb = ttk.Scrollbar(self.tree, orient="vertical", command=self.tree.yview)
        vsb.pack(side="right", fill="y")
        self.tree.configure(yscrollcommand=vsb.set)

    def load_excel(self):
        file_path = filedialog.askopenfilename(filetypes=[("Excel files", "*.xlsx")])
        if not file_path:
            return
        try:
            self.wb = openpyxl.load_workbook(file_path)
            self.sheet_cb['values'] = self.wb.sheetnames
            self.sheet_cb.current(0)
            self.change_sheet()
        except Exception as e:
            messagebox.showerror("エラー", f"Excel読み込み失敗:\n{e}")

    def change_sheet(self, event=None):
        sheet_name = self.sheet_cb.get()
        if not sheet_name:
            return
        self.sheet = self.wb[sheet_name]
        self.sheet_data = [[cell.value for cell in row] for row in self.sheet.iter_rows()]
        self.display_data(self.sheet_data)

    def display_data(self, data):
        # ヘッダ設定
        self.tree.delete(*self.tree.get_children())
        if not data:
            return
        self.tree["columns"] = list(range(len(data[0])))
        for i, _ in enumerate(data[0]):
            self.tree.heading(i, text=f"Col {i}")
            self.tree.column(i, width=100, anchor=tk.CENTER)

        for row in data:
            self.tree.insert("", tk.END, values=row)

    def edit_cell(self, event):
        selected = self.tree.selection()
        if not selected:
            return
        col = self.tree.identify_column(event.x)
        row = self.tree.identify_row(event.y)
        col_index = int(col.replace("#","")) - 1
        row_index = self.tree.index(row)
        old_value = self.sheet_data[row_index][col_index]

        # 編集ダイアログ
        new_value = tk.simpledialog.askstring("セル編集", f"旧値: {old_value}", initialvalue=str(old_value))
        if new_value is None:
            return

        # Undo用に保存
        self.undo_stack.append(copy.deepcopy(self.sheet_data))

        # 更新
        self.sheet_data[row_index][col_index] = new_value
        self.display_data(self.sheet_data)

    def save_excel(self):
        if not self.wb or not self.sheet:
            return
        try:
            # Treeviewデータをシートに書き込み
            for r_idx, row in enumerate(self.sheet_data):
                for c_idx, value in enumerate(row):
                    self.sheet.cell(row=r_idx+1, column=c_idx+1, value=value)
            self.wb.save(filedialog.asksaveasfilename(defaultextension=".xlsx", filetypes=[("Excel files", "*.xlsx")]))
            messagebox.showinfo("保存完了", "Excelファイルを保存しました。")
        except Exception as e:
            messagebox.showerror("エラー", f"保存失敗:\n{e}")

    def undo(self):
        if not self.undo_stack:
            messagebox.showinfo("Undo", "Undo履歴なし")
            return
        self.sheet_data = self.undo_stack.pop()
        self.display_data(self.sheet_data)

    def apply_filter(self):
        filter_text = self.filter_entry.get()
        if "=" not in filter_text:
            messagebox.showerror("エラー", "正しい形式で入力してください(例: 0=Apple)")
            return
        col_str, val = filter_text.split("=", 1)
        try:
            col_idx = int(col_str)
        except ValueError:
            messagebox.showerror("エラー", "列番号は整数で指定してください")
            return
        filtered = [row for row in self.sheet_data if str(row[col_idx]) == val]
        self.display_data(filtered)

    def reset_filter(self):
        self.display_data(self.sheet_data)

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

Excel を直接開いて作業しようとすると、ファイル読み込みが重かったり、複数ファイルを開きすぎてPCが遅くなったりします。
また、ちょっとだけ値を修正したいのに Excel を起動するのは意外と手間がかかります。

そこで Python で GUI アプリを作っておくと、

  • すぐ起動できる
  • 必要なセルだけ編集できる
  • 読み込みも保存も高速
  • 自分の用途に合わせて機能を増やせる

というメリットが得られ、「業務効率化ツール」として非常に役に立ちます。


ExcelEditorApp の主要機能


① Excelファイルの読み込み(openpyxl)

  • ファイルダイアログからExcelを選ぶだけ
  • シート名やセル内容が一覧で表示される

「画像:Excelファイル読み込み画面のスクリーンショットを挿入」


② セルの編集機能(tkinter Treeview使用)

  • 表形式のUIでデータを直感的に変更
  • ダブルクリックでセル編集
  • 編集後はその場で値更新

「画像:セルを編集している画面のスクリーンショットを挿入」


③ シート切り替え

  • Excel内に複数シートがあっても簡単に切り替え可能

④ 保存(上書き or 名前を付けて保存)

  • GUIからワンクリックで Excel ファイルに保存
  • openpyxl の高速書き出し対応

⑤ 追加機能(拡張しやすい設計)

  • 行追加、削除
  • セルの背景色変更
  • CSVエクスポート

など、用途に応じて後から追加できる構造になっています。


Excel 作業は多くの人にとって日常ですが、Python で GUI ツールを作ると「作業時間を半分以下」にできることも珍しくありません。

また、こうしたデスクトップアプリを作り始めると、PCスペックの良し悪しが開発効率に直結してきます。
特に Excel の大規模データを扱う場合は、メモリとCPU性能が高いほど処理が快適になります。



2. コード解説

以下では、ExcelEditorApp の主要部分を抜粋しながら、どのように構築されているのかを詳しく解説します。


◆ ① 基本の tkinter GUI 構造

import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import openpyxl

class ExcelEditorApp:
    def __init__(self, root):
        self.root = root
        self.root.title("ExcelEditorApp")

        self.tree = None
        self.workbook = None
        self.current_sheet = None

        self.create_widgets()

● 解説

  • ExcelEditorApp クラスが GUI とデータ管理をすべて担当
  • self.tree がセル表示のメインコンポーネント
  • openpyxl のワークブックを保持する self.workbook
  • シート切り替え用の self.current_sheet

この構造により、必要な機能を後から簡単に追加できます。


◆ ② ウィジェット生成(ボタン・Treeview)

def create_widgets(self):
    frame = ttk.Frame(self.root)
    frame.pack(fill="x", pady=5)

    load_btn = ttk.Button(frame, text="Excelを開く", command=self.load_excel)
    save_btn = ttk.Button(frame, text="保存", command=self.save_excel)

    load_btn.pack(side="left", padx=5)
    save_btn.pack(side="left", padx=5)

    self.sheet_combo = ttk.Combobox(frame, state="readonly")
    self.sheet_combo.pack(side="left", padx=10)
    self.sheet_combo.bind("<<ComboboxSelected>>", self.load_sheet)

    self.tree = ttk.Treeview(self.root)
    self.tree.pack(fill="both", expand=True)

● 解説

  • 読み込みボタンと保存ボタンは Frame にまとめて配置
  • シート切り替えは Combobox を使用
  • Treeview が表データのメイン表示領域

tkinter ではこれが最も操作しやすい表形式UIです。


◆ ③ Excel読み込み(openpyxl)

def load_excel(self):
    filepath = filedialog.askopenfilename(
        filetypes=[("Excel Files", "*.xlsx")]
    )
    if not filepath:
        return

    self.workbook = openpyxl.load_workbook(filepath)
    self.sheet_combo["values"] = self.workbook.sheetnames
    self.sheet_combo.current(0)

    self.load_sheet()

● 解説

  • askopenfilename でExcelを選択
  • load_workbook でファイルを読み込み
  • シート名をコンボボックスへ自動反映
  • 初期状態で1枚目のシートを表示

読み込みは非常に高速で、2~3MB程度のExcelなら数百ミリ秒でロードできます。


◆ ④ Treeview にシート内容を表示

def load_sheet(self, event=None):
    sheet_name = self.sheet_combo.get()
    self.current_sheet = self.workbook[sheet_name]

    # 既存データ削除
    self.tree.delete(*self.tree.get_children())
    self.tree["columns"] = []

    # 列ヘッダー生成
    max_col = self.current_sheet.max_column
    cols = [str(i) for i in range(1, max_col + 1)]
    self.tree["columns"] = cols

続き:

for col in cols:
    self.tree.heading(col, text=f"Col{col}")
    self.tree.column(col, width=100)

# 行データ挿入
for row in self.current_sheet.iter_rows(values_only=True):
    self.tree.insert("", "end", values=row)

● 解説

  • Excel の最大列数を取得してヘッダーを動的生成
  • 行データは iter_rows(values_only=True) で高速取得
  • Treeview に行として追加

GUIでExcel-likeな表がそのまま再現されます。

「画像:Treeview に読み込まれたExcel画面のスクリーンショットを挿入」


◆ ⑤ セル編集(ダブルクリック対応)

def enable_editing(self):
    self.tree.bind("<Double-1>", self.edit_cell)

def edit_cell(self, event):
    item = self.tree.identify_row(event.y)
    column = self.tree.identify_column(event.x)

    col_index = int(column.replace("#", "")) - 1
    row_index = self.tree.index(item)

    old_value = self.tree.set(item, column)

続き:

entry = ttk.Entry(self.root)
entry.insert(0, old_value)
entry.place(x=event.x_root, y=event.y_root)

entry.bind("<Return>", lambda e: self.update_value(entry, item, column))

● 解説

  • identify_row + identify_column でクリック座標からセルを割り出し
  • Entry ウィジェットを表示して編集
  • Enterキーで値確定

Excelライクな編集体験が実現できます。


◆ ⑥ 保存処理

def save_excel(self):
    for i, item in enumerate(self.tree.get_children(), start=1):
        values = self.tree.item(item)["values"]
        for j, value in enumerate(values, start=1):
            self.current_sheet.cell(row=i, column=j).value = value

    self.workbook.save("edited.xlsx")
    messagebox.showinfo("保存完了", "Excelを保存しました。")

● 解説

  • Treeview の値を openpyxl に書き戻し
  • 新しいExcelとして保存
  • 必要に応じて「名前を付けて保存」も可能

保存も非常に高速です。


■ まとめ

ExcelEditorApp は、普段の Excel 作業を大幅に効率化する Python 製の GUI アプリです。

tkinter の軽快な UI と openpyxl の高速処理によって、Excel を開くより早く編集できます。

ツリー表示、シート切り替え、セル編集、保存など、実務的な機能がすべて含まれています。

Python で業務アプリを作ると、処理速度を左右するのが PC 性能です。
Excel の大規模シートを扱う場合、メモリ16GB以上・CPU4コア以上の環境だと開発も実行もスムーズになります。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

ABOUT ME
tyamada
tyamada
普通の会社員(平)
記事URLをコピーしました