memopy

pythonで作ってみました的なブログ

⑩ 複数のウィジェットを配置【python tkinter sqlite3で家計簿を作る】

⑩ 複数のウィジェットを配置【python tkinter sqlite3で家計簿を作る】

表示画面設計図
f:id:memopy:20170602215840p:plain
前回までに作成したGUI
f:id:memopy:20170602225817p:plain


今までの機能を用いて、表示画面のGUIを作成した。
また、TreeviewのHeading部のフォントを変更する方法については別ページにまとめた。
ttk Treeview Headingのfontを変更する方法 - memopy

# -*- 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")

# rootフレームの設定
root = tk.Tk()
root.title("家計簿アプリ")
root.geometry("400x500")

# メニューの設定
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=15)
frame1.pack()
label2 = tk.Label(frame1,font=("",14),text="期間 ")
label2.pack(side="left")
entry1 = tk.Entry(frame1,font=("",14),justify="center",width=12)
entry1.pack(side="left")
label3 = tk.Label(frame1,font=("",14),text=" ~ ")
label3.pack(side="left")
entry2 = tk.Entry(frame1,font=("",14),justify="center",width=12)
entry2.pack(side="left")

# 表示ボタンの設定
button4 = tk.Button(root,text="表示",
                    font=("",16),
                    width=10,bg="gray",
                    command=lambda:select_sql(entry1.get(),entry2.get()))
button4.pack()

# ツリービューの作成
tree = ttk.Treeview(root,padding=10)
tree["columns"] = (1,2,3)
tree["show"] = "headings"
tree.column(1,width=100)
tree.column(2,width=75)
tree.column(3,width=100)
tree.heading(1,text="日付")
tree.heading(2,text="内訳")
tree.heading(3,text="金額")

# ツリービューのスタイル変更
style = ttk.Style()
# TreeViewの全部に対して、フォントサイズの変更
style.configure("Treeview",font=("",12))
# TreeViewのHeading部分に対して、フォントサイズの変更と太字の設定
style.configure("Treeview.Heading",font=("",14,"bold"))

# SELECT文の作成
sql = """
SELECT acc_date,item_name,amount
FROM acc_data as a,item as i
WHERE a.item_code = i.item_code
ORDER BY acc_date
"""
# ツリービューに要素の追加
i=0
for r in c.execute(sql):
    # 金額(r[2])を通貨形式に変換
    r = (r[0],r[1],"¥{:,d}".format(r[2]))
    tree.insert("","end",tags=i,values=r)
    if i & 1:
        tree.tag_configure(i,background="#CCFFFF")
    i+=1
# ツリービューの配置
tree.pack(fill="x",padx=20,pady=20)

# メインループ
root.mainloop()

表示画面のGUIが完成した!
f:id:memopy:20170604103013p:plain

次は、表示画面のGUIに処理を実装する。

質問や記事の誤りがありましたらコメントお願いします。


前の記事
⑨ 表(テーブル)の作成【python tkinter sqlite3で家計簿を作る】
次の記事
⑪ コールバック関数の定義【python tkinter sqlite3で家計簿を作る】

ttk Treeview Headingのfontを変更する方法

ttk Treeview Headingのfontを変更する方法

ツリービュー ヘッダーのフォントを変更するのに苦労したのでまとめる。
f:id:memopy:20170604091854p:plain

styleクラスを使用すると、ウィジェットの全てのクラスに対して一括でオプションを設定できる。

import tkinter as ttk
style = ttk.Style()
# configure(オプションを一括で適用するウィジェットのクラス名,オプション・・・)
# ※今回は、フォントサイズのみ14に変更する例
style.configure("Treeview.Heading",font=("",14))

ウィジェットのクラス名指定の例

フォントサイズを14に変更するクラスの範囲を指定する例

# 全てのウィジェット
style.configure(".",font=("",14))
# Treeviewの全部
style.configure("Treeview",font=("",14))
# TreeviewのHeading部分のみ
style.configure("Treeview.Heading",font=("",14))


スタイルクラスを用いた、ページ上部のGUIスクリプト

import tkinter as tk
import tkinter.ttk as ttk

# ルート画面の作成
root = tk.Tk()

# スタイルの設定
style = ttk.Style()
# TreeViewの全部に対して、フォントサイズの変更
style.configure("Treeview",font=("",12))
# TreeViewのHeading部分に対して、フォントサイズの変更と太字の設定
style.configure("Treeview.Heading",font=("",14,"bold"))

# ツリービュー(表)の作成
tree = ttk.Treeview(root)
# 各列に対してインデックスを付ける
tree["columns"]=(1,2,3)
# ツリービューの非表示
tree["show"]="headings"
# 各列に対する設定(
tree.column(1, width=100)
tree.column(2, width=100)
tree.column(3, width=100)
# 各列のヘッダーの設定
tree.heading(1, text="日付")
tree.heading(2, text="内訳")
tree.heading(3, text="金額")
# レコードの挿入
tree.insert("" ,"end",values=("2017/5/1","食費",3500))

tree.pack()
root.mainloop()

⑨ 表(テーブル)の作成【python tkinter sqlite3で家計簿を作る】

⑨ 表(テーブル)の作成【python tkinter sqlite3で家計簿を作る】

前回までに登録画面のGUI実装が完了した。
f:id:memopy:20170601225707p:plain
今回は表示画面のGUI作成を行う。始めに、表(テーブル)の作成だ。
表(テーブル)の作成は、ttkモジュールのツリービュー(Treeview)ウィジェットを用いる。

表示画面設計図
f:id:memopy:20170602215840p:plain

ツリービュー Treeview

はじめに簡単なサンプルスクリプトを作成して、ウィジェットの機能を確認する。

# モジュールのインポート
import tkinter as tk
import tkinter.ttk as ttk

# ルートフレームの作成
root = tk.Tk()
# ツリービューの作成
tree = ttk.Treeview(root)

# 列インデックスの作成
tree["columns"] = (1,2,3)
# 表スタイルの設定(headingsはツリー形式ではない、通常の表形式)
tree["show"] = "headings"
# 各列の設定(インデックス,オプション(今回は幅を指定))
tree.column(1,width=75)
tree.column(2,width=75)
tree.column(3,width=100)
# 各列のヘッダー設定(インデックス,テキスト)
tree.heading(1,text="日付")
tree.heading(2,text="内訳")
tree.heading(3,text="金額")

# レコードの作成
# 1番目の引数-配置場所(ツリー形式にしない表設定ではブランクとする)
# 2番目の引数-end:表の配置順序を最下部に配置
#             (行インデックス番号を指定することもできる)
# 3番目の引数-values:レコードの値をタプルで指定する
tree.insert("","end",values=("2017/5/1","食費",3500))
tree.insert("","end",values=("2017/5/10","光熱費",7800))
tree.insert("","end",values=("2017/5/10","住宅費",64000))

# ツリービューの配置
tree.pack()

root.mainloop()

表が作成された。
f:id:memopy:20170602220227p:plain

表の要素に追加するためには、insertメソッドのvaluesオプションに要素をタプル型で渡してあげればよい。
データベースに登録している明細テーブル(acc_data)をSELECT文で抽出し、for文で追加するロジックを立てることになる。
始めにデータベースに登録しているレコードをSELECT文で取得してみる。
f:id:memopy:20170602221303p:plain

# -*- coding:cp932 -*-
import sqlite3
c = sqlite3.connect("database.db")

# SELECT文の作成
sql = """
SELECT acc_date,item_name,amount
FROM acc_data as a,item as i
WHERE a.item_code = i.item_code
ORDER BY acc_date
"""

# SQLを発行し、各レコードをタプルで表示
for r in c.execute(sql):
    print(r)

f:id:memopy:20170602220823p:plain
データベースのacc_dataテーブルの各レコードがタプル型で抽出できることを確認した。

次に、先ほどのツリービューを、データベースから取得したレコードを要素として追加するロジックに変更する。

# モジュールのインポート
import tkinter as tk
import tkinter.ttk as ttk
import sqlite3

# データベースの接続
c = sqlite3.connect("database.db")
# SELECT文の作成
sql = """
SELECT acc_date,item_name,amount
FROM acc_data as a,item as i
WHERE a.item_code = i.item_code
ORDER BY acc_date
"""

# ルートフレームの作成
root = tk.Tk()
# ツリービューの作成
tree = ttk.Treeview(root)

# 列インデックスの作成
tree["columns"] = (1,2,3)
# 表スタイルの設定(headingsはツリー形式ではない、通常の表形式)
tree["show"] = "headings"
# 各列の設定(インデックス,オプション(今回は幅を指定))
tree.column(1,width=75)
tree.column(2,width=75)
tree.column(3,width=100)
# 各列のヘッダー設定(インデックス,テキスト)
tree.heading(1,text="日付")
tree.heading(2,text="内訳")
tree.heading(3,text="金額")

# SELECT文で取得した各レコードを繰り返し取得
for r in c.execute(sql):
    # ツリービューの要素に追加
    tree.insert("","end",values=r)
    
# ツリービューの配置
tree.pack()

root.mainloop()

データベースのテーブルをツリービューとして表示させた!
f:id:memopy:20170602222017p:plain

~おまけ~
Treeviewは罫線がなくて表が見づらい。各レコードを2色に設定すると見やすくなる。
上記のコード、for文の中を次のように変更した。

# SELECT文で取得した各レコードを繰り返し取得
i=0
for r in c.execute(sql):
    # ツリービューの要素に追加(tagを追加することにより、要素を識別できる)
    tree.insert("","end",tags=i,values=r)
    # tagが奇数か偶数か判定
    if i & 1:
        # tagが奇数(レコードは偶数)の場合のみ、背景色の設定
        tree.tag_configure(i,background="#CCFFFF")
    i+=1

f:id:memopy:20170602225817p:plain

今回はここまで!
質問や記事の誤りがありましたらコメントください。

関連記事
ttk Treeview Headingのfontを変更する方法 - memopy

前の記事
⑧ ドロップダウンリストの作成【python tkinter sqlite3で家計簿を作る】
次の記事
⑩ 複数のウィジェットを配置【python tkinter sqlite3で家計簿を作る】

⑧ ドロップダウンリストの作成【python tkinter sqlite3で家計簿を作る】

⑧ ドロップダウンリストの作成【python tkinter sqlite3で家計簿を作る】

今回は、ttkモジュールを使って、ドロップダウンリスト(コンボボックス)の作成をしてみる。
前回までに作成したGUI
f:id:memopy:20170530222854p:plain
「内訳」の値は内訳テーブル(item)に登録された値を用いるため、直接入力よりドロップダウンリストのほうがユーザーフレンドリーである。
また、明細テーブル(acc_data)への登録は、'食費'などのitem_nameではなく、数値のitem_codeを登録するため、ドロップダウンリストで選択した値に対応するitem_codeの値を求めなければならない。
f:id:memopy:20170601211307p:plain
f:id:memopy:20170530214729p:plain
ドロップダウンリストは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()

コンボボックスが作成され、「表示」を押下すると、インタプリタコンソールにコンボボックスの値を出力したのが確認できる。
f:id:memopy:20170601213942p:plain

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に設定
続きを読む

⑦ GUIの実装 sqlite3への登録【python tkinter sqlite3で家計簿を作る】

GUIの実装 sqlite3への登録【python tkinter sqlite3で家計簿を作る】

今回から遂に、GUIの実装(クリックしたときの処理を定義)を行う。
最終的には、入力画面に各項目を入力し、「登録」を押下するとsqlite3のDBに登録(SQLを発行)するという処理を実装する。
f:id:memopy:20170530203259p:plain

前回までに作成したGUI
f:id:memopy:20170529202941p:plain

Buttonウィジェットのクリック時の処理を定義する

import tkinter as tk

# ボタンがクリックされた時の処理をコールバック関数として定義
def callback():
    print("Hello World")

root = tk.Tk()

# ボタンを作成(rootに配置、テキストの指定、ボタンがクリックされた時に呼び出す関数(コールバック関数)を指定)
button = tk.Button(root,text="OK",command=callback)
button.pack()

root.mainloop()

OKボタンをクリックすると、インタプリタコンソールにHello Worldの文字が表示されたことがわかる。
f:id:memopy:20170530204933p:plain

引数があるコールバック関数を定義する場合

Buttonのcommandのコールバック関数に引数を用いる場合はラムダ形式で記述しなければならない。

import tkinter as tk

# 引数があるコールバック関数を定義
def callback(name):
    print("Hello World " + name)

root = tk.Tk()

# ボタンを作成(commandをラムダ形式で記述)
button = tk.Button(root,text="OK",command=lambda:callback("memopy"))
button.pack()

root.mainloop()

Entryウィジェットのテキストを読み取る

Entryウィジェットに入力されたテキストを読み取るためには、getメソッドを使う。

import tkinter as tk

# GETボタンが押された時のコールバック関数
def text_get():
    # Entryウィジェットのテキストを読み取るgetメソッド
    text = entry.get()
    print(text)

root = tk.Tk()
# Entryウィジェットの作成
entry = tk.Entry(root,width=10)
entry.pack()
# Buttonウィジェットの作成
button = tk.Button(root,text="GET",command=text_get)
button.pack()

Entry内のテキストを読み取り、インタプリタコンソールに出力した。
f:id:memopy:20170530211151p:plain

続きを読む

⑥ LabelとEntryの配置【python tkinter sqlite3で家計簿を作る】

⑥ LabelとEntryの配置【python tkinter sqlite3で家計簿を作る】

今回はLabelとEntryウィジェットの配置をする。

設計図
f:id:memopy:20170528101451p:plain
前回までに作成したGUI
f:id:memopy:20170528111550p:plain

ラベル Label

# ラベルの作成(rootに配置,テキストの指定,フォントの指定)
label1 = tk.Label(root,text="【入力画面】",font=16)
label1.pack(fill="x")

ラベルが配置された。
f:id:memopy:20170528134344p:plain

Labelのオプション(抜粋)
オプション名 入力型式 説明
anchor center(デフォルト),n,ne,e,se,s,sw,w,nw ラベル内における文字の配置場所
中心(center)からの方位角
background
bg
背景色
borderwidth
bd
integer ラベルの枠幅
font font_object 文字のフォント
foreground
fg
string 文字色
height integer ラベルの縦の長さ
justify center(デフォルト),left,right 複数行のテキストの文字寄せ
relief flat(デフォルト),sunken,raised,groove,ridge ラベル枠の形状
ラベル枠の形状を有効にするためには、必ずborderwidthの値を1以上に設定しなければならない
text string ラベルに表示させる文字
underline boolean 下線を引く場合はTrue,付けない場合はFalse(デフォルト)
width integer ボタンの横の長さ
wraplength integer ラベルを複数行に表示した場合における行間

エントリー Entry

# エントリーの作成(rootに配置,フォントの指定,文字の中央揃え,Entry横幅の指定)
entry1 = tk.Entry(root,font=("",12),justify="center",width=15)
entry1.pack()

1行の入力欄が作成された!
f:id:memopy:20170528221335p:plain

Entryのオプション(抜粋)
オプション名 入力型式 説明
background
bg
背景色
borderwidth
bd
integer エントリーの枠幅
font font_object 文字のフォント
foreground
fg
string 文字色
justify center,left(デフォルト),right テキストの文字寄せ
relief flat,sunken(デフォルト),raised,groove,ridge エントリー枠の形状
width integer エントリーの横の長さ
続きを読む

⑤ FrameとLabelFrameの違い【python tkinter sqlite3で家計簿を作る】

⑤ FrameとLabelFrameの違い【python tkinter sqlite3で家計簿を作る】

今回は、FrameとLabelFrameという機能を掘り下げていきたい。
前回の記事では、Buttonのウィジェットをpackメソッドを用いて、画面上に配置したが、packメソッドでは、思った通りの場所にウィジェットを配置できないことが多い。
そのため、Frameというウィジェットを配置する枠を画面上に配置して、その中にウィジェットを入れると簡単にレイアウトできるようになる。

設計図
f:id:memopy:20170528110228p:plain
前回までに作成したGUI
f:id:memopy:20170527213534p:plain

フレーム Frame

# -*- coding:utf-8 -*-
import tkinter as tk
root = tk.Tk()
root.title("家計簿アプリ")
root.geometry("300x300")

# フレームの作成(フレームをrootに配置,フレーム淵を2pt,フレームの形状をridge)
frame = tk.Frame(root,bd=2,relief="ridge")
# フレームを画面に配置し、横方向に余白を拡張する
frame.pack(fill="x")

# 作成したフレームにボタン1を配置
button1 = tk.Button(frame,text="入力")
# ボタンを左から配置する
button1.pack(side="left")

# 作成したフレームにボタン2を配置
button2 = tk.Button(frame,text="表示")
# ボタンを左から配置する
button2.pack(side="left")

# 作成したフレームにボタン3を配置
button3 = tk.Button(frame,text="終了")
# ボタンを右から配置する
button3.pack(side="right")

root.mainloop()

仕切りのあるフレームが作成された
f:id:memopy:20170528111550p:plain

Frameのオプション(抜粋)
オプション名 入力型式 説明
background
bg
背景色
borderwidth
bd
integer フレーム枠の幅
padx integer フレーム内の横の余白
pady integer フレーム内の縦の余白
relief flat(デフォルト),
sunken,raised,groove,ridge
フレームの形状
f:id:memopy:20170611094823p:plain
フレームの形状を有効にするためには、必ずborderwidthの値を1以上に設定しなければならない

ラベル フレーム LabelFrame

フレームにラベルを付けたウィジェットも存在する

# -*- coding:utf-8 -*-
import tkinter as tk
root = tk.Tk()
root.title("家計簿アプリ")
root.geometry("300x300")

# ラベルフレームの作成(ラベルフレームのtextをmenuに設定)
frame = tk.LabelFrame(root,bd=2,relief="ridge",text="menu")
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")

root.mainloop()

f:id:memopy:20170528113235p:plain

LabelFrameのオプション(抜粋)※フレームからの差分のみ
オプション名 入力型式 説明
text string ラベルに表示するテキスト
labelanchor n,ne,e,se,s,sw,w,nw(デフォルト) ラベルの配置場所
font font_object 文字のフォント

今回はここまで!
質問や記事の間違いがありましたらコメントお願いします。

前の記事
④ Buttonウィジェットの配置【python tkinter sqlite3で家計簿を作る】
次の記事
⑥ LabelとEntryの配置【python tkinter sqlite3で家計簿を作る】