プログラムソースコード「ToDoアプリGUI_ver2.7.py」

2024年10月21日月曜日

source code 公開

t f B! P L

 

 

 


 

★ソースコード★

##########################################
# ToDoアプリGUI_ver2.7.py
# 2024/09/15
# -ToDo一覧に状況管理列を追加
# --コンボボックス(状況)の追加
# --データベースにstatus列追加

##########################################

##########################################
# ライブラリをインポート --- (1)
##########################################
import os
import csv
import sqlite3
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
from tkinter import filedialog

#########################################
# 変数等を宣言 --- (2)
#########################################
db_path = "ToDo_column4.sqlite3"
csv_exp_path = "exported_users.csv"

#########################################
# 関数を宣言 --- (3)
#########################################
# 関数(データベースの初期化)
def load_todos():
    if not os.path.exists(db_path):
        with sqlite3.connect(db_path) as conn:
          cur = conn.cursor()
          query = '''CREATE TABLE myItem(
                 id integer primary key autoincrement,
                 ToDo string,
                 date string,
                 status string
          )'''
          cur.execute(query)

# 関数(データのインポート)
def import_todos():
    conn = sqlite3.connect(db_path)
    cur = conn.cursor()

    #ファイルダイアログからインポート
    fTyp = [("","*")]
    iDir = os.path.abspath(os.path.dirname(__file__))
    csv_imp_path = tk.filedialog.askopenfilename(filetypes = fTyp,initialdir = iDir)

    with open(csv_imp_path, 'r') as f:
        reader = csv.reader(f)
        query = '''INSERT INTO myItem(
                 ToDo,
                 date,
                 status
        ) values(?,?,?)'''
        for row in reader:
            cur.execute(query, ( row[1], row[2],row[3]))
    conn.commit()
    conn.close()
    # ツリービュー再表示
    view_todos(tree)

# 関数(データのエクスポート)  
def export_todos():
    conn = sqlite3.connect(db_path)
    cur = conn.cursor()
   # if not os.path.exists(csv_exp_path):
    with open(csv_exp_path, 'w') as f:
      writer = csv.writer(f)
      for row in cur.execute('SELECT * FROM myItem'):
            writer.writerow(row)
    conn.close()

# 関数(テキストボックスの入力内容クリア)
def clear_text(tree):
    id_text.delete(0, tk.END)
    ToDo_text.delete(0, tk.END)
    date_text.delete(0, tk.END)
    combobox.selection_clear()#★
    combobox.set('')#★


# 関数(データベースからToDoデータ全件取得)
def get_todos():
    with sqlite3.connect(db_path) as conn:
        cur = conn.cursor()
        cur.execute('SELECT * FROM myItem')
        rows = cur.fetchall()
        return rows
             
# 関数(リストボックスにToDoデータ全件表示)
def view_todos(tree):
    #テキストボックスクリア
    clear_text(tree)
    #ツリービュークリア
    tree.delete(*tree.get_children())
    #1行毎に色違いで表示
    i=0
    for row in get_todos():
        tree.insert(parent='', index='end', tags=i, iid=row ,values=(str(row[0]), str(row[1]) ,str(row[2]),str(row[3])))
        if i % 2 == 0:
            # tagが偶数(レコードは奇数)の場合のみ、背景色の設定
            tree.tag_configure(i,background="#e6e6fa")#'yellow'
        i+=1

# 関数(データベースにデータ追加)
def add_todo(ToDo, date,status, id):
    with sqlite3.connect(db_path) as conn:
      cur = conn.cursor()
      query = '''INSERT INTO myItem(
                 ToDo,
                 date,
                 status
                ) values(?,?,?)'''
      cur.execute(query,(ToDo,date,status))
      conn.commit()
      # ツリービュー再表示
      view_todos(tree)

# 関数(データベースのデータ削除)
def delete_todo(ToDo,date,status,id):
    with sqlite3.connect(db_path) as conn:
      cur = conn.cursor()
      query = 'DELETE FROM myItem WHERE id = ?'
      cur.execute(query,[id])
      conn.commit()
      # ツリービュー再表示    
      view_todos(tree)

# 関数(データベースのデータ更新)
def update_todo(ToDo,date,status,id):
    with sqlite3.connect(db_path) as conn:
      cur = conn.cursor()
      query = '''UPDATE myItem
                 SET ToDo = ?,
                     date = ?,
                     status = ?
                 WHERE id = ?'''
      cur.execute(query,(ToDo,date,status,id))
      conn.commit()
      # ツリービュー再表示
      view_todos(tree)
   
# 関数(データベースのデータ検索)
def get_search_todos(ToDo,date,status,id):
    # if文で条件分岐
    # 各テキストボックスに入力された条件で検索
    if ToDo != "" :
        with sqlite3.connect(db_path) as conn:
            cur = conn.cursor()
            # プレースホルダ
            query = '''SELECT * FROM myItem
                       WHERE ToDo
                       LIKE ? '''
            cur.execute(query,('%'+ ToDo +'%',))
            rows = cur.fetchall()
            return rows
    elif date != "" :
        with sqlite3.connect(db_path) as conn:
            cur = conn.cursor()
            # プレースホルダ
            query = '''SELECT * FROM myItem
                       WHERE date
                       LIKE ? '''
            cur.execute(query,('%'+ date +'%',))
            rows = cur.fetchall()
            return rows
    elif status != "" :
        with sqlite3.connect(db_path) as conn:
            cur = conn.cursor()
            # プレースホルダ
            query = '''SELECT * FROM myItem
                       WHERE status
                       LIKE ? '''
            cur.execute(query,('%'+ status +'%',))
            rows = cur.fetchall()
            return rows
    elif id != "" :
        with sqlite3.connect(db_path) as conn:
            cur = conn.cursor()
            #プレースホルダ
            query = '''SELECT * FROM myItem
                       WHERE id
                       LIKE ? '''
            cur.execute(query,('%'+ id +'%',))
            rows = cur.fetchall()
            return rows
    # テキストボックスに入力がない場合は、全件表示
    else :
        with sqlite3.connect(db_path) as conn:
            cur = conn.cursor()
            cur.execute('SELECT * FROM myItem')
            rows = cur.fetchall()
            return rows

# 関数(リストボックスにToDoデータ検索結果表示)
def view_search_todos(tree,ToDo,date,status,id):
    # テキストボックスクリア
    clear_text(tree)
    # ツリービュークリア
    tree.delete(*tree.get_children())
    # レコードの検索結果をリストボックスに表示
    i=0
    for row in get_search_todos(ToDo,date,status,id):
        tree.insert(parent='', index='end', tags=i, iid=row ,values=(str(row[0]), str(row[1]) ,str(row[2]) ,str(row[3])))
        if i % 2 == 0:
           # tagが偶数(レコードは奇数)の場合のみ、背景色の設定
           tree.tag_configure(i,background="#e6e6fa")#'yellow'
        i+=1

# 関数(TREEVIEW上で選択された行から情報を取得)
def select_record(event):
    # 選択行の判別
    record_id = tree.focus()
    #テキストボックスクリア
    clear_text(tree)
    # 選択行のレコードを取得
    record_values = tree.item(record_id, 'values')
    # テキストボックスに値を挿入
    id_text.insert( 0, record_values[0] )
    ToDo_text.insert( 0, record_values[1] )
    date_text.insert( 0, record_values[2] )
    combobox.set(record_values[3] )#★
    #treeviewの選択解除
    tree.selection_remove(tree.selection())

# 関数(HELPメッセージ表示)
def help_msg():
    tk.messagebox.showinfo(title="HELP",
                              message="【操作説明】\n"

                              +"「追加」ボタン\n"
                              +" 「Todo内容」、「日付」欄に入力されたデータが\n"
                              +" データベースに保存されます。\n"
                              +"\n"
                              +"「削除」ボタン\n"
                              +" 「ID」欄に入力されたIDをもつデータが\n"
                              +" データベースから削除されます\n"
                              +"\n"
                              +"「更新」ボタン\n"
                              +" 登録済みのデータの内容を変更できます。\n"
                              +" データベースに保存されます。\n"
                              +"\n"
                              +"「検索」ボタン\n"
                              +" 「ID」、「Todo内容」、「日付」欄に入力された単語で\n"
                              +" データベースを検索し、その結果を表示します。\n"
                              +"\n"
                              )

#########################################
# データベースを呼び出し --- (4)
#########################################
todos = load_todos()

#########################################
# GUI メインウィンドウの設定 --- (5-1)
#########################################
# rootウィンドウ作成,(タイトル,サイズ)の設定
root = tk.Tk()
root.title("ToDoアプリGUI")
root.geometry("600x400")

# フレームの配置
view_frame = tk.Frame(root)
view_frame.pack(anchor=tk.CENTER)

text_frame = tk.Frame(root)
text_frame.pack(anchor=tk.W)

button_frame = tk.Frame(root)
button_frame.pack(anchor=tk.CENTER)

button2_frame = tk.Frame(root)
button2_frame.pack(anchor=tk.CENTER)

#########################################
# GUI フレーム(view)の設定 --- (5-2)
#########################################
# ツリービューの列の識別名を指定
column = ('id', 'ToDo', 'date','status')
# ツリービュー初期化
tree = ttk.Treeview(view_frame, columns=column)
# ツリービューの列の設定
tree.column('#0',width=0, stretch='no')
tree.column('id', anchor='e', width=50) # 右よせ
tree.column('ToDo',anchor='w', width=300) # 左よせ
tree.column('date', anchor='e', width=80) # 右よせ
tree.column('status', anchor='w', width=80)# 左よせ
# ツリービューの列の見出し設定
tree.heading('#0',text='')
tree.heading('id', text='ID',anchor='center')
tree.heading('ToDo', text='ToDo内容', anchor='center')
tree.heading('date',text='日付', anchor='center')
tree.heading('status',text='状況', anchor='center')
# ツリービューの行をマウスで選択したときのイベント
tree.bind("<<TreeviewSelect>>", select_record)
# ウィジェットの配置
tree.pack(anchor=tk.CENTER,pady=10)

#########################################
# GUI フレーム(text)の設定 --- (5-3) 
#########################################
# テキストボックス(ID)の設定
id_lbl1 = tk.Label(text_frame,text="ID:")
id_lbl1.pack(side=tk.LEFT)
id_text = tk.Entry(text_frame, width=5)
id_text.pack(side=tk.LEFT)

# テキストボックス(ToDo内容)の設定
add_lbl1 = tk.Label(text_frame,text="ToDo内容:")
add_lbl1.pack(side=tk.LEFT)
ToDo_text = tk.Entry(text_frame, width=20)
ToDo_text.pack(side=tk.LEFT)

# テキストボックス(日付)の設定
add_lbl2 = tk.Label(text_frame,text="日付:")
add_lbl2.pack(side=tk.LEFT)
date_text = tk.Entry(text_frame, width=15)
date_text.pack(side=tk.LEFT)

#コンボボックス(状況)の設定
add_lbl3 = tk.Label(text_frame,text="状況:")
add_lbl3.pack(side=tk.LEFT)

values = [" ", "完了", "進行中", "未着手"] # 表示する選択肢
combobox = ttk.Combobox(text_frame, values=values)
combobox.state(['readonly']) # 選択のみ可
combobox.config(width=10) # 表示幅
combobox.pack(side=tk.LEFT)

#########################################
# GUI フレーム(button)の設定  --- (5-4)
#########################################

# ボタン(ToDoデータ追加)の設定
add_button = tk.Button(button_frame, text="追加", width=20, command=lambda: add_todo(ToDo_text.get(),date_text.get(),combobox.get(),id_text.get()))
add_button.pack(side=tk.LEFT)

# ボタン(ToDoデータ削除)の設定
delete_button = tk.Button(button_frame, text="削除", width=20, command=lambda: delete_todo(ToDo_text.get(),date_text.get(),combobox.get(),id_text.get()))
delete_button.pack(side=tk.LEFT)

# ボタン(ToDoデータ更新)の設定
update_button = tk.Button(button_frame, text="更新", width=20, command=lambda: update_todo(ToDo_text.get(),date_text.get(),combobox.get(),id_text.get()))
update_button.pack(side=tk.LEFT)

# ボタン(ToDoデータ検索)の設定
search_button = tk.Button(button_frame, text="検索", width=20, command=lambda: view_search_todos(tree,ToDo_text.get(),date_text.get(),combobox.get(),id_text.get()))#
search_button.pack(side=tk.LEFT)

#########################################
# GUI フレーム(button2)の設定  --- (5-5)
#########################################

# ボタン(データインポート)の設定
import_button = tk.Button(button2_frame, text="インポート", width=20, command=lambda: import_todos())
import_button.pack(side=tk.LEFT)

# ボタン(データエクスポート)の設定
export_button = tk.Button(button2_frame, text="エクスポート", width=20, command=lambda: export_todos())
export_button.pack(side=tk.LEFT)

# ボタン(HELPメッセージ表示)の設定
help_button = tk.Button(button2_frame, text="HELP", width=20, command=lambda: help_msg())
help_button.pack(side=tk.LEFT)

#########################################
# GUI Treeviewにレコード一覧を初期表示  --- (5-6)
#########################################
view_todos(tree)

#########################################
# イベントループ開始 --- (6)
#########################################
root.mainloop()


 

 

 

 

このブログを検索

アーカイブ

カテゴリー

QooQ