⑧ ドロップダウンリストの作成【python tkinter sqlite3で家計簿を作る】
⑧ ドロップダウンリストの作成【python tkinter sqlite3で家計簿を作る】
今回は、ttkモジュールを使って、ドロップダウンリスト(コンボボックス)の作成をしてみる。
前回までに作成したGUI
「内訳」の値は内訳テーブル(item)に登録された値を用いるため、直接入力よりドロップダウンリストのほうがユーザーフレンドリーである。
また、明細テーブル(acc_data)への登録は、'食費'などのitem_nameではなく、数値のitem_codeを登録するため、ドロップダウンリストで選択した値に対応するitem_codeの値を求めなければならない。
ドロップダウンリストはTkinterの拡張モジュールであるTkinter.ttkモジュールを用いる。
ちなみに、ttkにおけるウィジェット名は、コンボボックスである。
コンボボックス Combobox
始めに簡単なサンプルスクリプトを記載する。
# モジュールのインポート import tkinter as tk import tkinter.ttk as ttk # ルートフレームの作成 root = tk.Tk() # コンボボックスの作成(rootに配置,リストの値を編集不可(readonly)に設定) combo = ttk.Combobox(root, state='readonly') # リストの値を設定 combo["values"] = ("食費","住宅費","光熱費") # デフォルトの値を食費(index=0)に設定 combo.current(0) # コンボボックスの配置 combo.pack() # ボタンの作成(コールバックコマンドには、コンボボックスの値を取得しprintする処理を定義) button = tk.Button(text="表示",command=lambda:print(combo.get())) # ボタンの配置 button.pack() root.mainloop()
コンボボックスが作成され、「表示」を押下すると、インタプリタコンソールにコンボボックスの値を出力したのが確認できる。
Combboxのオプション(抜粋)
オプション名 | 入力型式 | 説明 |
---|---|---|
justify | center,left(デフォルト),right | テキストの文字寄せ |
postcommand | コールバック関数 | リストが表示される直前の処理 |
state | normal(デフォルト) readonly disable |
リストの状態 normal:リストの編集可能 readonly:リストの編集不可 disable:非活性(選択不可) |
values | tuple | リストの要素 |
width | integer | コンボボックスの幅 |
Combboxのメソッド(抜粋)
# コンボボックスに値をセットする combo.set("string") # コンボボックスの値を読み取る combo.get() # コンボボックスの初期値を設定する combo.current(0) #index = 0に設定
Combboxの値の取得
次に、コンボボックスから出力した値を用いて、データベースのitem_codeを算出する。
やり方は、コンボボックスの値を読み取り、SQLのWHERE句にセットし、該当するitem_codeを取ってくる。
# モジュールのインポート import tkinter as tk import tkinter.ttk as ttk import sqlite3 # -------------------------------- # ボタンが押下されたときのコールバック関数 def getitemcode(item_name): # データベースの接続 c = sqlite3.connect("database.db") # SELECT文の発行 WHERE句には、変数item_nameをformat関数で代入する item_code = c.execute(""" SELECT item_code FROM item WHERE item_name = '{}' """.format(item_name)) # SELECT文の結果をfetchoneメソッドで1つ表示する。 # fethoneメソッドはタプルで返ってくるので、index0を取得し出力する。 print(item_code.fetchone()[0]) # ------------------------------- # GUI部分の作成 root = tk.Tk() combo = ttk.Combobox(root, state='readonly') combo["values"] = ("食費","住宅費","光熱費") combo.current(0) combo.pack() # コールバック関数にgetitemcodeを定義 button = tk.Button(text="表示",command=lambda:getitemcode(combo.get())) button.pack() root.mainloop()
リストの値に応じたitem_codeを取得できた!
次は、リストの値を内訳テーブル(item)から作成したい。
itemテーブル内にある全てのitem_nameをタプルにすればコンボボックスのvaluesオプションに渡せる。
この処理は新たにcreateitemnameというファンクションを作成した。
# モジュールのインポート import tkinter as tk import tkinter.ttk as ttk import sqlite3 # ------------------------------- # 内訳テーブル(item)にあるitem_nameのタプルを作成する def createitemname(): # データベースの接続 c = sqlite3.connect("database.db") # 空の「リスト型」を定義 li = [] # SELECT文を発行し、item_nameを取得し、for文で回す for r in c.execute("SELECT item_name FROM item"): # item_nameをリストに追加する li.append(r) # リスト型のliをタプル型に変換して、ファンクションに戻す return tuple(li) # ------------------------------- # ボタンが押下されたときのコールバック関数 def getitemcode(item_name): c = sqlite3.connect("database.db") item_code = c.execute(""" SELECT item_code FROM item WHERE item_name = '{}' """.format(item_name)) print(item_code.fetchone()[0]) # ------------------------------ # GUI部分の作成 root = tk.Tk() combo = ttk.Combobox(root, state='readonly') # createitemname関数を用いて、データベース内のitem_nameのタプルを作成し、リストの値に指定する combo["values"] = createitemname() combo.current(0) combo.pack() button = tk.Button(text="表示",command=lambda:getitemcode(combo.get())) button.pack() root.mainloop()
データベース内にあるテーブルからリストの値に追加できた!
最後に、前回まで作成したGUIにコンボボックスの機能を実装する。
# -*- coding: utf-8 -*- import tkinter as tk import tkinter.ttk as ttk import sqlite3 # 空のデータベースを作成して接続する dbname = "database.db" c = sqlite3.connect(dbname) c.execute("PRAGMA foreign_keys = 1") # 既にデータベースが登録されている場合は、ddlの発行でエラーが出るのでexceptブロックで回避する try: # itemテーブルの定義 ddl = """ CREATE TABLE item ( item_code INTEGER PRIMARY KEY AUTOINCREMENT, item_name TEXT NOT NULL UNIQUE ) """ # SQLの発行 c.execute(ddl) # acc_dataテーブルの定義 ddl = """ CREATE TABLE acc_data ( id INTEGER PRIMARY KEY AUTOINCREMENT, acc_date DATE NOT NULL, item_code INTEGER NOT NULL, amount INTEGER, FOREIGN KEY(item_code) REFERENCES item(item_code) ) """ # itemテーブルへリファレンスデータの登録 c.execute(ddl) c.execute("INSERT INTO item VALUES(1,'食費')") c.execute("INSERT INTO item VALUES(2,'住宅費')") c.execute("INSERT INTO item VALUES(3,'光熱費')") c.execute("COMMIT") except: pass # ------------------------------- # 内訳テーブル(item)にあるitem_nameのタプルを作成する def createitemname(): # データベースの接続 c = sqlite3.connect("database.db") # 空の「リスト型」を定義 li = [] # SELECT文を発行し、item_nameを取得し、for文で回す for r in c.execute("SELECT item_name FROM item"): # item_nameをリストに追加する li.append(r) # リスト型のliをタプル型に変換して、ファンクションに戻す return tuple(li) # ------------------------------ # 登録ボタンがクリックされた時にデータをDBに登録するコールバック関数 def create_sql(item_name): # データベースに接続 c = sqlite3.connect("database.db") # item_nameをWHERE句に渡してitem_codeを取得する item_code = c.execute(""" SELECT item_code FROM item WHERE item_name = '{}' """.format(item_name)) item_code = item_code.fetchone()[0] # 日付の読み取り acc_data = entry1.get() # 金額の読み取り amount = entry3.get() # SQLを発行してDBへ登録 try: c.execute(""" INSERT INTO acc_data(acc_date,item_code,amount) VALUES('{}',{},{}); """.format(acc_data,item_code,amount)) c.execute("COMMIT;") print("1件登録しました") # ドメインエラーなどにより登録できなかった場合のエラー処理 except: print("エラーにより登録できませんでした") # rootフレームの設定 root = tk.Tk() root.title("家計簿アプリ") root.geometry("300x280") # メニューの設定 frame = tk.Frame(root,bd=2,relief="ridge") frame.pack(fill="x") button1 = tk.Button(frame,text="入力") button1.pack(side="left") button2 = tk.Button(frame,text="表示") button2.pack(side="left") button3 = tk.Button(frame,text="終了") button3.pack(side="right") # 入力画面ラベルの設定 label1 = tk.Label(root,text="【入力画面】",font=("",16),height=2) label1.pack(fill="x") # 日付のラベルとエントリーの設定 frame1 = tk.Frame(root,pady=10) frame1.pack() label2 = tk.Label(frame1,font=("",14),text="日付") label2.pack(side="left") entry1 = tk.Entry(frame1,font=("",14),justify="center",width=15) entry1.pack(side="left") # 内訳のラベルとエントリーの設定 frame2 = tk.Frame(root,pady=10) frame2.pack() label3 = tk.Label(frame2,font=("",14),text="内訳") label3.pack(side="left") # 内訳コンボボックスの作成 combo = ttk.Combobox(frame2, state='readonly',font=("",14),width=13) combo["values"] = createitemname() combo.current(0) combo.pack() # 金額のラベルとエントリーの設定 frame3 = tk.Frame(root,pady=10) frame3.pack() label4 = tk.Label(frame3,font=("",14),text="金額") label4.pack(side="left") entry3 = tk.Entry(frame3,font=("",14),justify="center",width=15) entry3.pack(side="left") # 登録ボタンの設定 button4 = tk.Button(root,text="登録", font=("",16), width=10,bg="gray", command=lambda:create_sql(combo.get())) button4.pack() # メインループ root.mainloop()
GUIが完成した!
機能試験をしてみる。
登録できているのがわかる。
次に、データベースに正しく登録されているか確認してみる。
正しく登録されていた!!
今回はここまで!
次回は表示部分のGUIを作成したい。
質問や記事の誤りがありましたらコメントください。
2017/6/4追記:sqlite3は、日付型(date型)というデータ型がない。日付として例えばBETWEEN演算子などの処理を認識させるためには、
'YYYY-MM-DD'
'YYYY-MM-DD hh:mm:ss'
の形式で記述しなければならない。
入力形式にYYYY/MM/DDと入力されていたら、replaceメソッドで'/'を'-'に置き換える処理が必要になる。
前の記事
⑦ GUIの実装 sqlite3への登録【python tkinter sqlite3で家計簿を作る】
次の記事
⑨ 表(テーブル)の作成【python tkinter sqlite3で家計簿を作る】