Pythonによる誕生日リストAppのソースコード
誕生日リストAppのソースコードですが、GitHubに公開はしたものの、なーんかソースコード載せるだけではダメな気がするし見てもらいにくい気もするし、せっかく前回Markdown記法が使った記事も書けたのでこっちでも公開してみます。
外部ライブラリは使ってないので画像さえ用意してもらえれば大丈夫なはず。
モジュール遷移図

リセットボタン二つとキャンセルボタンについてはクリックイベントで済んでいるので「widget_create.py」に記述されています。
各モジュールのソースコード
長くなるので折り畳んでいます。
TOP画面
birthday_app.py
from tkinter import * from tkinter import ttk from image_file import ImageFile from widget_create import WidgetCreate class Application(ImageFile): def __init__(self, master, style=None): super().__init__() #TOP画面を作成 master.title('誕生日リスト') master.geometry('610x300+250+100') self.main_frame = Frame(master) self.main_frame.pack(pady=10) #画像 self.image_file = ImageFile() self.cake_image = self.image_file.cake_img() self.image_label = Label(self.main_frame, image=self.cake_image) self.image_label.grid(column=0, rowspan=2, row=0, padx=20, pady=15, ipady=5) #Widgetの作成 my_widget = WidgetCreate(belong=self.main_frame, style='MyWidgets4.TFrame') my_widget.button_create(master=root, my_style='ButtonStyle.TButton') if __name__ == '__main__': root = Tk() s = ttk.Style() s.configure('MyWidgets.TFrame',background='systemTransparent', relief=FLAT) s.configure('MyWidgets4.TFrame',background='systemTransparent', relief=SUNKEN) s.configure('MyWidgets2.TLabel', background='systemTransparent', relief=FLAT) s.configure('ButtonStyle.TButton', foreground='#FF0000') app = Application(master=root, style='MyWidgets4.TFrame') root.mainloop()
ウィジェットの作成
widget_create.py
from tkinter import * from tkinter import ttk from image_file import ImageFile from all_data import NewWindow from select_db import OpenData from sq_db import DbInto class WidgetCreate(ImageFile): def __init__(self, belong=None, style=None): super().__init__() #Frame self.sub_frame = ttk.Frame(belong, style=style) self.sub_frame.grid(column=1, row=0, ipadx=15, ipady=10) self.name_frame = Frame(self.sub_frame) self.name_frame.pack(padx=10, pady=20, anchor=W) self.birth_frame = Frame(self.sub_frame) self.birth_frame.pack(padx=5, anchor=W) self.birth_frames = [ Frame(self.birth_frame) for i in range(3) ] for item in self.birth_frames: item.pack(side=LEFT, padx=5) self.i_button_frame = Frame(belong) self.i_button_frame.grid(column=0, columnspan=2, row=3) self.r_button_frame = Frame(self.sub_frame) self.r_button_frame.pack() #Label self.info_label = Label(self.name_frame, text='★必要事項を入力してください★\n') self.info_label.pack(padx=5, anchor=W) self.name_lists = ['姓', '名'] self.date_text = ['西暦', '月', '日'] self.name_labels = [ Label(self.name_frame, text=label_item) for label_item in self.name_lists ] #date_labelをそれぞれのFrameに入れて作成 self.date_labels = [ Label(frame_item, text=label_item) for frame_item, label_item in zip(self.birth_frames, self.date_text) ] #Entryを作成 self.family_var = StringVar() self.first_var = StringVar() self.familyname_entry = ttk.Entry(self.name_frame, textvariable=self.family_var, width=10) self.firstname_entry = ttk.Entry(self.name_frame, textvariable=self.first_var, width=10) self.entry_list = [self.familyname_entry, self.firstname_entry] #姓名LabelとEntryをpack for label, entry in zip(self.name_labels, self.entry_list): label.pack(anchor = W, side = LEFT) entry.pack(anchor = W, side = LEFT) #Comboboxを作成 self.date_list = [ [value for value in range(1920, 2021)], [value for value in range(1, 13)], [value for value in range(1, 32)] ] self.combo_list = [ ttk.Combobox(self.birth_frames[i], state='readonly', values=self.date_list[i], width = 5, justify = RIGHT) for i in range(3) ] #生年月日LabelとComboboxをpack for label, combo in zip(self.date_labels, self.combo_list): label.pack(anchor = W, side = LEFT) combo.pack(anchor = W, side = LEFT) #----ボタン関連の作成---- def button_create(self, master, my_style=None): #登録ボタンイベント def i_button_click(): #入力値を取得 full_name = [name.get() for name in self.entry_list] birth_list = [var.get() for var in self.combo_list] result = DbInto(name_data=full_name, birth_data=birth_list) #入力内容のリセット for item in self.entry_list: item.delete(0,END) for item in self.combo_list: item.selection_clear() item.set('') #検索ボタンイベント def c_button_click(): #画像を用意 self.search_image = ImageFile() self.s_image = self.search_image.search_img() #入力値を取得 full_name = [name.get() for name in self.entry_list] birth_list = [var.get() for var in self.combo_list] #生年月日条件(birth_list)をint型に変換 for index, item in enumerate(birth_list): if item != '': birth_list[index] = int(item) sum_item = full_name + birth_list #条件設定の有無で分岐 if any(sum_item) is False: all_search = NewWindow(image=self.s_image) else: condition_data = OpenData(conditions=sum_item, image=self.s_image) #名前リセット def name_reset(): for item in self.entry_list: item.delete(0,END) #生年月日リセット def date_reset(): for item in self.combo_list: item.selection_clear() item.set('') #ボタンを作成 self.i_button = ttk.Button(self.i_button_frame, text='新規登録', width=9, command=i_button_click) self.i_button.pack(side=LEFT) self.c_button = ttk.Button(self.i_button_frame, text='データ検索', width=9, command=c_button_click) self.c_button.pack(side=LEFT, padx=20) self.d_button = ttk.Button(self.i_button_frame, text='× キャンセル ×', style=my_style, width=11, command=master.destroy) self.d_button.pack(side=LEFT, padx=10) #余白調整のLabel self.space_label = Label(self.r_button_frame, text='') self.space_label.pack() #リセットボタン self.nr_button = ttk.Button(self.r_button_frame, text='Name Reset', command=name_reset) self.nr_button.pack(side=LEFT) self.dr_button = ttk.Button(self.r_button_frame, text='Date Reset', command=date_reset) self.dr_button.pack(padx=15, side=LEFT)
画像ファイルの準備
image_file.py
from tkinter import * from tkinter import ttk class ImageFile(): def __init__(self): self.f = 'image_birthday/calender_woman.png' self.f2 = 'image_birthday/sweets_cake_pavlova.png' self.f3 = 'image_birthday/search_mushimegane2-2.png' def calender_img(self): self.calender_image = PhotoImage(file=self.f) return self.calender_image def cake_img(self): self.cake_image = PhotoImage(file=self.f2) return self.cake_image def search_img(self): self.search_image = PhotoImage(file=self.f3) return self.search_image if __name__ == '__main__': ImageFile()
登録機能
sq_db.py
from tkinter import * from tkinter import messagebox as mb import sqlite3 import datetime as dt class DbInto(): def __init__(self, name_data, birth_data): full_name = name_data birth_list = birth_data if '' in full_name: mb.showwarning('空欄エラー', '姓名に空欄があります') else: try: birth_list = [int(i) for i in birth_data] except ValueError: mb.showerror('空欄エラー', '生年月日を入力してください') else: try: birthday = dt.date(birth_list[0], birth_list[1], birth_list[2]) except ValueError: mb.showwarning('入力値エラー', f'{birth_list[1]}月は{birth_list[2]}日までありません') else: birthday_info = ( '{}{}さんの生年月日を{}年{}月{}日で登録します。'.format(full_name[0], full_name[1], birth_list[0], birth_list[1], birth_list[2]) ) res = mb.askquestion('結果', birthday_info) if res == 'yes': into_data = [ full_name[0], full_name[1], birth_list[0], birth_list[1], birth_list[2] ] self.data_into_db(data=into_data) mb.showinfo('完了', '★登録しました★') def data_into_db(self, data): #Connectionオブジェクトを作る。 conn = sqlite3.connect('birthday.db') c = conn.cursor() #----データの追加---- c.execute("INSERT INTO birthday VALUES(?, ?, ?, ?, ?)", data) #----追加終了---- #保存する。 conn.commit() #データベースをクローズする。 conn.close()
データ表示のための新しいウィンドウ作成
toplevel_create.py
from tkinter import * from tkinter import ttk class TopLevelCreate(): def __init__(self, image=None, title=None): #Toplevel self.my_win = Toplevel() self.my_win.title(title) self.my_win.geometry('400x400+300+120') self.my_win.resizable(0,1) #Flame self.image_frame = ttk.Frame(self.my_win, padding=15) self.image_frame.pack() #画像を用意 self.search_label = Label(self.image_frame, image=image) self.search_label.pack() #メッセージ self.info_label = Label(self.image_frame, text='★データが10件以上の場合はスクロールして下さい★', pady=5, padx=5) self.info_label.pack()
全データ表示機能
all_data.py
from tkinter import * from tkinter import ttk import sqlite3 from toplevel_create import TopLevelCreate #--tkinter部品作成-- class NewWindow(TopLevelCreate): def __init__(self, image=None): super().__init__(title='全登録データ', image=image) #画像を用意 #--sqlite3の操作-- conn = sqlite3.connect('birthday.db') c = conn.cursor() c.execute('SELECT * FROM birthday') r_tuple = tuple(c.fetchall()) conn.close #---------------- data_count = len(r_tuple) count_info = f'全データ:{data_count}件' c_info_label = Label(self.image_frame, text=count_info) c_info_label.pack(anchor=W) #----データを表示---- data_frame = ttk.Frame(self.my_win, relief=SOLID, padding=15) data_frame.pack() final_data = [] for index, item in enumerate(r_tuple): final_data.append( ' [{}] {}{}:{}年{}月{}日生まれ'.format( index+1, r_tuple[index][0], r_tuple[index][1], r_tuple[index][2], r_tuple[index][3], r_tuple[index][4]) ) #データ表示用Listbox&Scrollbar v = StringVar(value=final_data) list_box = Listbox(data_frame, listvariable=v, width=30) list_box.grid(row=0, column=0) scroll = ttk.Scrollbar(data_frame, orient=VERTICAL, command=list_box.yview) list_box['yscrollcommand'] = scroll.set scroll.grid(row=0, column=1, sticky=(N, S))
指定条件データ表示機能
select_db.py
from tkinter import * from tkinter import ttk from toplevel_create import TopLevelCreate import sqlite3 #====検索機能モジュール==== class OpenData(TopLevelCreate): def __init__(self, conditions=None, image=None): super().__init__(title='指定検索データ', image=image) #条件データを受け取る full_conditions = conditions #条件の入っている列番号(インデックス) conditions_index = [index for index,item in enumerate(full_conditions) if item != ''] #条件から空白を除外 full_conditions = [elem for elem in full_conditions if elem != ''] #----sqlite3操作---- conn = sqlite3.connect('birthday.db') c = conn.cursor() c.execute("SELECT * FROM birthday") all_data = c.fetchall() selection_data = [] for item in all_data: select_result = True for key, value in enumerate(conditions_index): if item[value] != full_conditions[key]: select_result = False if select_result == True: selection_data.append(item) conn.close #--------------------- data_count = len(selection_data) count_info = f'条件一致データ:{data_count}件' c_info_label = Label(self.image_frame, text=count_info) c_info_label.pack(anchor=W) #----データを表示---- data_frame = ttk.Frame(self.my_win, relief=SOLID, padding=15) data_frame.pack() final_data = [] for index, item in enumerate(selection_data): final_data.append( ' [{}] {}{}:{}年{}月{}日生まれ'.format( index+1, selection_data[index][0], selection_data[index][1], selection_data[index][2], selection_data[index][3], selection_data[index][4]) ) #データ表示用Listbox&Scrollbar v = StringVar(value=final_data) list_box = Listbox(data_frame, listvariable=v, width=30) list_box.grid(row=0, column=0) scroll = ttk.Scrollbar(data_frame, orient=VERTICAL, command=list_box.yview) list_box['yscrollcommand'] = scroll.set scroll.grid(row=0, column=1, sticky=(N, S))
以上です。現時点での私の技量での最良ですが、何かご指摘がありましたらお願い致します。