PR

Pythonで作るExcel検索・編集ツール – GUI対応

本サイトはアフィリエイト広告を利用しています
プログラミング

GUIを使ってExcelファイルに簡単な変更を行う方法に興味はありますか?

Hulu | Disney+ セットプラン

今回はpythonでを使ってExcelファイルに入力されている情報を編集、または追加する画面を作成します。

先日作成した一行日記に今回紹介する方法を組み合わせるなどして、pythonでどんなことができるがより理解が深まると思います。

ExcelはA列目にデータ入力しておき、GUIからデータを検索、編集します。

ソースコードの詳細な説明

このツールは、Pythonで作成したExcelファイルを操作するための簡単なGUIアプリケーションです。ユーザーは指定したExcelファイルを読み込み、キーワード検索によって行を抽出し、その内容を編集したり、新しい行を追加したりできます。特に、編集操作は元のファイルではなくコピーされたファイルに対して行われ、元データが保持される点が特徴です。以下、コードの詳細な説明を記載します。

インポート

import tkinter as tk
from tkinter import filedialog, messagebox
from openpyxl import load_workbook
import shutil
import os
  • tkinter: Python標準のGUIライブラリで、簡単なウィンドウアプリケーションを作成するのに使用します。
  • messagebox: メッセージボックス(通知や警告ダイアログ)を表示するためのモジュール。
  • filedialog: ファイル保存ダイアログを開き、ファイルの保存先を選択できるようにするためのモジュール。
  • openpyxl: Excelファイル(xlsx形式)を操作するためのPythonライブラリです。
  • load_workbook: 指定したExcelファイルをロード(読み込み)して、ワークブックオブジェクトを返します。これにより、シートのデータにアクセスし、編集が可能となります。
  • shutil: ファイルやディレクトリを操作するための標準ライブラリです。ファイルのコピーや移動、削除などの操作を提供します。
  • os: ファイルの存在確認など、システム関連の操作を行います。

グローバル変数

selected_row_index = None  # 選択された行のインデックス(元のファイルの行番号)
original_excel_file = None  # 元のExcelファイルのパス
copied_file_path = None  # Excelファイル(コピー)のパス
excel_file = None  # 読み込んだExcelファイル(コピー)
ws = None  # 現在のシート
row_map = {}  # リストボックスに表示された行と元のExcel行を対応させる辞書

これらの変数は、Excelファイルを操作する際の情報を保存します。selected_row_indexは選択された行番号、original_excel_fileは元のExcelファイルのパス、excel_fileはコピーされたファイル、wsはシート情報、row_mapはリストボックスとExcel行番号の対応を管理する辞書です。

load_excel関数

def load_excel():
    global original_excel_file, excel_file, ws, copied_file_path
    file_path = filedialog.askopenfilename(filetypes=[("Excel files", "*.xlsx")])
    if file_path:
        original_excel_file = file_path
        # ファイルのコピーを作成して編集対象とする
        copied_file_path = os.path.splitext(original_excel_file)[0] + "_copy.xlsx"
        shutil.copyfile(original_excel_file, copied_file_path)
        excel_file = load_workbook(copied_file_path)
        ws = excel_file.active  # デフォルトでアクティブシートを選択
        messagebox.showinfo("成功", f"Excelファイルが読み込まれ、コピーが作成されました: {copied_file_path}")
  • filedialog.askopenfilename() でユーザーが選択したExcelファイルを取得し、そのファイルをコピーします。コピーされたファイルがexcel_fileとしてロードされ、wsにアクティブシートが設定されます。これにより、元のファイルには影響を与えずに操作できます。

search_keyword関数

def search_keyword():
    global selected_row_index
    keyword = entry_keyword.get()
    result_listbox.delete(0, tk.END)  # リストボックスをクリア
    selected_row_index = None  # 選択された行をリセット
    row_map.clear()  # 行の対応関係をクリア
    
    if not keyword:
        messagebox.showerror("エラー", "検索キーワードを入力してください")
        return
    
    # 指定列でキーワードを検索 (例: A列を検索)
    for row_index, row in enumerate(ws.iter_rows(min_row=2, values_only=True), start=2):  # ヘッダーを除く
        for cell in row:
            if cell and keyword in str(cell):  # キーワードが含まれるか
                result_listbox.insert(tk.END, row)
                row_map[result_listbox.size() - 1] = row_index  # リストボックスのインデックスと元の行番号を対応付け
  • entry_keyword.get()で入力されたキーワードを取得し、それを基にExcelシート内を検索します。該当する行が見つかると、リストボックスにその行を表示し、row_mapにそのインデックスとExcel内の行番号を紐付けます。
  • row_mapを使用することで、ユーザーがリストボックスで選択した行が、元のExcelファイルのどの行かを追跡します。

display_selected_row関数

def display_selected_row(event):
    global selected_row_index
    selection = result_listbox.curselection()
    if selection:
        # 選択されたリストボックスのインデックスから、元の行番号を取得
        selected_row_index = row_map.get(selection[0])
        selected_row = result_listbox.get(selection[0])
        entry_edit.delete(0, tk.END)
        entry_edit.insert(0, selected_row)
  • リストボックスで選択された行を編集用テキストボックスに表示します。選択された行番号はselected_row_indexに保存され、後で更新操作に使用されます。

update_row関数

def update_row():
    global selected_row_index, ws, copied_file_path
    new_data = entry_edit.get()
    
    if not new_data:
        messagebox.showerror("エラー", "編集内容を入力してください")
        return
    
    if selected_row_index:
        # 元の行を更新
        for col, value in enumerate(new_data.split(','), 1):
            ws.cell(row=selected_row_index, column=col, value=value.strip())
        excel_file.save(copied_file_path)  # コピーされたファイルを保存
        messagebox.showinfo("成功", f"行 {selected_row_index} を更新しました")
    else:
        messagebox.showerror("エラー", "更新する行を選択してください")
  • entry_edit.get()で編集された内容を取得し、それを元に選択された行(selected_row_index)を更新します。new_dataはカンマ区切りの形式で入力され、セルごとに分割して対応する列に値を更新します。
  • 更新内容はコピーされたExcelファイルに対して保存され、元のファイルは影響を受けません。

add_row関数

def add_row():
    global selected_row_index, ws, copied_file_path
    new_data = entry_edit.get()
    
    if not new_data:
        messagebox.showerror("エラー", "追加する内容を入力してください")
        return
    
    # 新規行を追加
    new_row = new_data.split(',')
    ws.append([value.strip() for value in new_row])
    excel_file.save(copied_file_path)  # コピーされたファイルを保存
    messagebox.showinfo("成功", "新しい行を追加しました")
  • 新しい行を追加する機能です。編集用テキストボックスに入力されたデータを取得し、ws.append()を使って新しい行として追加します。これも元のファイルではなく、コピーされたファイルに対して保存されます。

GUIの作成

# GUI作成
root = tk.Tk()
root.title("Excel キーワード検索&編集ツール")

# Excel読み込みボタン
btn_load_excel = tk.Button(root, text="Excelを読み込む", command=load_excel)
btn_load_excel.grid(row=0, column=0, padx=10, pady=10)

# 検索キーワード入力
label_keyword = tk.Label(root, text="検索キーワード:")
label_keyword.grid(row=1, column=0, padx=10, pady=10)

entry_keyword = tk.Entry(root)
entry_keyword.grid(row=1, column=1, padx=10, pady=10)

# 検索ボタン
btn_search = tk.Button(root, text="検索", command=search_keyword)
btn_search.grid(row=1, column=2, padx=10, pady=10)

# 検索結果表示リストボックス
result_listbox = tk.Listbox(root, width=80, height=10)
result_listbox.grid(row=2, column=0, columnspan=3, padx=10, pady=10)

# リストボックス内の行を選択したときのイベント
result_listbox.bind("< 	 	 	 	 	 	 	>", display_selected_row)

# 編集用テキストボックス
label_edit = tk.Label(root, text="編集内容:")
label_edit.grid(row=3, column=0, padx=10, pady=10)

entry_edit = tk.Entry(root, width=80)
entry_edit.grid(row=3, column=1, columnspan=2, padx=10, pady=10)

# 更新ボタン
btn_update = tk.Button(root, text="更新", command=update_row)
btn_update.grid(row=4, column=1, padx=10, pady=10)

# 追加ボタン
btn_add = tk.Button(root, text="追加", command=add_row)
btn_add.grid(row=4, column=2, padx=10, pady=10)

# ウィンドウを表示
root.mainloop()
  • Tkinterライブラリを使用して、Excelファイルの読み込み、検索、編集、追加機能を操作するためのGUIを作成します。ウィジェットには、ボタン、リストボックス、テキストボックスなどを配置し、ユーザーが簡単にExcel操作を行えるように設計されています。

まとめ

このツールは、Excelファイルを手軽に検索・編集できるようにするためのPythonスクリプトです。GUIを備えており、Excel操作に不慣れな人でも直感的に使えるようにしています。

全体のソース

import tkinter as tk
from tkinter import filedialog, messagebox
from openpyxl import load_workbook
import shutil
import os

# グローバル変数
selected_row_index = None  # 選択された行のインデックス(元のファイルの行番号)
original_excel_file = None  # 元のExcelファイルのパス
copied_file_path = None  # Excelファイル(コピー)のパス
excel_file = None  # 読み込んだExcelファイル(コピー)
ws = None  # 現在のシート
row_map = {}  # リストボックスに表示された行と元のExcel行を対応させる辞書

def load_excel():
    global original_excel_file, excel_file, ws, copied_file_path
    file_path = filedialog.askopenfilename(filetypes=[("Excel files", "*.xlsx")])
    if file_path:
        original_excel_file = file_path
        # ファイルのコピーを作成して編集対象とする
        copied_file_path = os.path.splitext(original_excel_file)[0] + "_copy.xlsx"
        shutil.copyfile(original_excel_file, copied_file_path)
        excel_file = load_workbook(copied_file_path)
        ws = excel_file.active  # デフォルトでアクティブシートを選択
        messagebox.showinfo("成功", f"Excelファイルが読み込まれ、コピーが作成されました: {copied_file_path}")

def search_keyword():
    global selected_row_index
    keyword = entry_keyword.get()
    result_listbox.delete(0, tk.END)  # リストボックスをクリア
    selected_row_index = None  # 選択された行をリセット
    row_map.clear()  # 行の対応関係をクリア
    
    if not keyword:
        messagebox.showerror("エラー", "検索キーワードを入力してください")
        return
    
    # 指定列でキーワードを検索 (例: A列を検索)
    for row_index, row in enumerate(ws.iter_rows(min_row=2, values_only=True), start=2):  # ヘッダーを除く
        for cell in row:
            if cell and keyword in str(cell):  # キーワードが含まれるか
                result_listbox.insert(tk.END, row)
                row_map[result_listbox.size() - 1] = row_index  # リストボックスのインデックスと元の行番号を対応付け

def display_selected_row(event):
    global selected_row_index
    selection = result_listbox.curselection()
    if selection:
        # 選択されたリストボックスのインデックスから、元の行番号を取得
        selected_row_index = row_map.get(selection[0])
        selected_row = result_listbox.get(selection[0])
        entry_edit.delete(0, tk.END)
        entry_edit.insert(0, selected_row)

def update_row():
    global selected_row_index, ws, copied_file_path
    new_data = entry_edit.get()
    
    if not new_data:
        messagebox.showerror("エラー", "編集内容を入力してください")
        return
    
    if selected_row_index:
        # 元の行を更新
        for col, value in enumerate(new_data.split(','), 1):
            ws.cell(row=selected_row_index, column=col, value=value.strip())
        excel_file.save(copied_file_path)  # コピーされたファイルを保存
        messagebox.showinfo("成功", f"行 {selected_row_index} を更新しました")
    else:
        messagebox.showerror("エラー", "更新する行を選択してください")

def add_row():
    global selected_row_index, ws, copied_file_path
    new_data = entry_edit.get()
    
    if not new_data:
        messagebox.showerror("エラー", "追加する内容を入力してください")
        return
    
    # 新規行を追加
    new_row = new_data.split(',')
    ws.append([value.strip() for value in new_row])
    excel_file.save(copied_file_path)  # コピーされたファイルを保存
    messagebox.showinfo("成功", "新しい行を追加しました")

# GUI作成
root = tk.Tk()
root.title("Excel キーワード検索&編集ツール")

# Excel読み込みボタン
btn_load_excel = tk.Button(root, text="Excelを読み込む", command=load_excel)
btn_load_excel.grid(row=0, column=0, padx=10, pady=10)

# 検索キーワード入力
label_keyword = tk.Label(root, text="検索キーワード:")
label_keyword.grid(row=1, column=0, padx=10, pady=10)

entry_keyword = tk.Entry(root)
entry_keyword.grid(row=1, column=1, padx=10, pady=10)

# 検索ボタン
btn_search = tk.Button(root, text="検索", command=search_keyword)
btn_search.grid(row=1, column=2, padx=10, pady=10)

# 検索結果表示リストボックス
result_listbox = tk.Listbox(root, width=80, height=10)
result_listbox.grid(row=2, column=0, columnspan=3, padx=10, pady=10)

# リストボックス内の行を選択したときのイベント
result_listbox.bind("< 	 	 	>", display_selected_row)

# 編集用テキストボックス
label_edit = tk.Label(root, text="編集内容:")
label_edit.grid(row=3, column=0, padx=10, pady=10)

entry_edit = tk.Entry(root, width=80)
entry_edit.grid(row=3, column=1, columnspan=2, padx=10, pady=10)

# 更新ボタン
btn_update = tk.Button(root, text="更新", command=update_row)
btn_update.grid(row=4, column=1, padx=10, pady=10)

# 追加ボタン
btn_add = tk.Button(root, text="追加", command=add_row)
btn_add.grid(row=4, column=2, padx=10, pady=10)

# ウィンドウを表示
root.mainloop()
おそうじ革命DUSKIN(ダスキン)
Hulu | Disney+ セットプラン

コメント

タイトルとURLをコピーしました