# 2024/09/15
# -データベースの検索機能追加
# --「検索」ボタン設置
# --「view_search_todos」関数追加
# --「get_search_todos」関数追加
# -表示ボタンを削除し、更新ボタンに統合
# -アプリ起動時にTreeviewにレコード一覧を初期表示
##########################################
##########################################
# ライブラリをインポート --- (1)
##########################################
import os
import csv
import sqlite3
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
from tkinter import filedialog
#from pandas import DataFrame
#########################################
# 変数等を宣言 --- (2)
#########################################
db_path = "ToDo.sqlite3"
#csv_imp_path = "users.csv"
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
)'''
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
) values(?,?)'''
for row in reader:
cur.execute(query, ( row[1], row[2]))
conn.commit()
conn.close()
# 関数(データのエクスポート)
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()
# 関数(データベースから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):
#テキストボックスクリア
id_text.delete(0, tk.END)
ToDo_text.delete(0, tk.END)
date_text.delete(0, tk.END)
tree.delete(*tree.get_children())
for row in get_todos():
tree.insert(parent='', index='end', iid=row ,values=(str(row[0]), str(row[1]) ,str(row[2])))
# 関数(データベースにデータ追加)
def add_todo(ToDo, date, id):
with sqlite3.connect(db_path) as conn:
cur = conn.cursor()
query = '''insert into myItem(
ToDo,
date
) values(?,?)'''
cur.execute(query,(ToDo,date))
conn.commit()
# 入力内容クリア
clear_text()
# 関数(データベースのデータ削除)
def delete_todo(ToDo,date,id):
with sqlite3.connect(db_path) as conn:
cur = conn.cursor()
query = 'delete from myItem where id = ?'
cur.execute(query,[id])
conn.commit()
# 入力内容クリア
clear_text()
# 関数(データベースのデータ更新)
def update_todo(ToDo,date,id):
with sqlite3.connect(db_path) as conn:
cur = conn.cursor()
query = '''update myItem set
ToDo = ?,
date = ?
where id = ?'''
cur.execute(query,(ToDo,date,id))
conn.commit()
# 入力内容クリア
clear_text()
# 関数(データベースのデータ検索)
def get_search_todos(ToDo,date,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 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,id):
#テキストボックスクリア
id_text.delete(0, tk.END)
ToDo_text.delete(0, tk.END)
date_text.delete(0, tk.END)
#リストボックスの表示クリア
tree.delete(*tree.get_children())
#レコードの検索結果をリストボックスに表示
for row in get_search_todos(ToDo,date,id):
tree.insert(parent='', index='end', iid=row ,values=(str(row[0]), str(row[1]) ,str(row[2])))
# 関数(テキストボックスの入力内容クリア)
def clear_text():
view_todos(tree)
# 関数(TREEVIEW上で選択された行から情報を取得)
def select_record(event):
# 選択行の判別
record_id = tree.focus()
# テキストボックス内の値を削除
id_text.delete( 0, tk.END )
ToDo_text.delete( 0, tk.END )
date_text.delete( 0, tk.END )
# 選択行のレコードを取得
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] )
#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')
tree = ttk.Treeview(view_frame, columns=column)
# マウスで行を選択したときのイベント
tree.bind("<<TreeviewSelect>>", select_record)
# 列の設定
tree.column('#0',width=0, stretch='no')
tree.column('id', anchor='center', width=50)
tree.column('ToDo',anchor='w', width=300)
tree.column('date', anchor='center', 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.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=50)
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)
#########################################
# GUI フレーム(button)の設定 --- (5-4)
#########################################
# ボタン(ToDoデータ全件表示)の設定
# view_button = tk.Button(button_frame, text="表示", width=20, command=lambda: view_todos(tree))
# view_button.pack(side=tk.LEFT)
# ボタン(ToDoデータ追加)の設定
add_button = tk.Button(button_frame, text="追加", width=20, command=lambda: add_todo(ToDo_text.get(),date_text.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(),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(),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(),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)
0 件のコメント:
コメントを投稿