【python】todoリストを作成

pythonでtodoリストを作成しました。

### 持たせた機能
**・内容を保持**
**・リストの並び替え可能**


GUI部分はTkinterを使用。リスト部分はTreeViewで操作しています。
Tkinterで可愛いGUIを作成するのは難しいですが、
ボタン部分を♥にしたり、猫ちゃんのイラストで装飾して
可愛くして使用しています。

### 基本のコード
```
import tkinter as tk
from tkinter import ttk, messagebox
import os
import sys

# 実行ファイルと同じディレクトリに保存するテキストファイルのパスを設定
def get_todolist_path():
    if hasattr(sys, '_MEIPASS'):
        return os.path.join(sys._MEIPASS, "todolist.txt")
    return os.path.join(os.path.expanduser("~"), "todolist.txt")

TEXT_FILE = "todolist.txt"

# テキストファイルの読み込み
def load_data():
    try:
        if os.path.exists(TEXT_FILE):
            with open(TEXT_FILE, 'r', encoding='utf-8') as f:
                return [line.strip() for line in f.readlines()]
        else:
            return []  # ファイルがなければ空リストを返す
    except Exception as e:
        messagebox.showerror("エラー", f"データの読み込みに失敗しました: {e}")
        return []

# テキストファイルへの保存
def save_data(data):
    try:
        with open(TEXT_FILE, 'w', encoding='utf-8') as f:
            for item in data:
                f.write(f"{item}\n")
    except Exception as e:
        messagebox.showerror("エラー", f"データの保存に失敗しました: {e}")


# ToDoリストに新しい項目を追加
def add_item():
    todo = entry.get()
    if todo:
        todos = load_data()
        todos.append(todo)
        save_data(todos)
        update_list()
        entry.delete(0, tk.END)
    else:
        messagebox.showwarning("入力エラー", "タスクを入力してください。")

# ToDoリストから項目を削除
def delete_item():
    selected_items = treeview.selection()
    if selected_items:
        todos = load_data()
        for selected_item in selected_items:
            todo = treeview.item(selected_item, 'values')[0]
            todos.remove(todo)
        save_data(todos)
        update_list()
    else:
        messagebox.showwarning("削除エラー", "削除する項目を選択してください。")

# ToDoリストの順番を並び替え
def sort_items():
    todos = load_data()
    todos.sort()
    save_data(todos)
    update_list()

# リストの内容を更新
def update_list():
    for item in treeview.get_children():
        treeview.delete(item)
    
    todos = load_data()
    for todo in todos:
        treeview.insert("", "end", values=(todo,))

# 順番変更用の関数
def on_move_up():
    selected_item = treeview.selection()
    if selected_item:
        index = treeview.index(selected_item[0])
        if index > 0:  # 順番を変更できる条件
            todos = load_data()
            todos[index], todos[index-1] = todos[index-1], todos[index]
            save_data(todos)
            update_list()
        # 新しいアイテムIDを取得
        children = treeview.get_children()
        
        # インデックスが範囲内にある場合に次のアイテムを選択
        if index -1 < len(children):
            treeview.selection_set(children[index - 1])  # 次のアイテムIDを選択
            
def on_move_down():
    selected_item = treeview.selection()
    
    if selected_item:
        index = treeview.index(selected_item[0])
        todos = load_data()
        if index < len(todos) - 1:  # 順番を変更できる条件
            todos[index], todos[index+1] = todos[index+1], todos[index]
            save_data(todos)
            update_list()
        print(index)
        # 新しいアイテムIDを取得
        children = treeview.get_children()
        
        # インデックスが範囲内にある場合に次のアイテムを選択
        if index + 1 < len(children):
            treeview.selection_set(children[index + 1])  # 次のアイテムIDを選択

# アプリケーション終了
def quit():
    root.quit()
    root.destroy()
    sys.exit()        

# GUIの設定
root = tk.Tk()
root.title("♥TO DO LIST♥")
root.configure(bg='white')
root.geometry("400x320") 
root.wm_protocol('WM_DELETE_WINDOW', quit) 

# 入力フィールド
entry = ttk.Entry(root, width=30)
entry.grid(row=0, column=0, padx=10, pady=10)

frame= ttk.Frame(root, style='MyWidget.TFrame')
frame.grid(row=0, column=1,columnspan=2)

# 追加ボタン
add_button = tk.Button(frame, text="追加", command=add_item, bd=0)
add_button.grid(row=0, column=0, sticky='w', padx=5)

# 削除ボタン
delete_button = tk.Button(frame, text="削除", command=delete_item, bd=0)
delete_button.grid(row=0, column=1, sticky='w', padx=5)

# 上へ移動ボタン
move_up_button = tk.Button(frame, text="↑", command=on_move_up, bd=0)
move_up_button.grid(row=0, column=3, sticky='w', padx=5)

# 下へ移動ボタン
move_down_button = tk.Button(frame, text="↓", command=on_move_down, bd=0)
move_down_button.grid(row=0, column=4, sticky='w', padx=5)

# ToDoリスト表示用のTreeview
treeview = ttk.Treeview(root, columns=("task",), show="headings", selectmode="extended")  # extended選択を許可
treeview.heading("task", text="♥♡♥ l i s t ♥♡♥")
treeview.grid(row=1, column=0, rowspan=3, padx=10, pady=10)



# 初期表示
update_list()

root.mainloop()

```