python tkinter sqlite3メモ

##GUIのtkinterを使ってみる
参考元：
https://www.udemy.com/the-python-mega-course/learn/v4/content


```py
from tkinter import *

window = Tk()

def c_kg():
    gram=float(e1_value.get())*1000
    pound=float(e1_value.get())*2.20462
    ounce=float(e1_value.get())*35.274
    t1.delete("1.0", END)
    t2.delete("1.0", END)
    t3.delete("1.0", END)
    t1.insert(END, f"{gram}g")
    t2.insert(END, f"{pound}ib")
    t3.insert(END, f"{ounce}oz")

l1 = Label(window, text="kg", width=10)
l1.grid(row=0, column=0)

#変数を受け取る
e1_value=StringVar()
e1 = Entry(window, textvariable=e1_value, width=10)#☆
e1.grid(row=0, column=1)

b1 = Button(window, text="Convert", width=10, command=c_kg)
b1.grid(row=0, column=2)

t1 = Text(window, height=1, width=10)
t2 = Text(window, height=1, width=10)
t3 = Text(window, height=1, width=10)

t1.grid(row=1, column=0)
t2.grid(row=1, column=1)
t3.grid(row=1, column=2)

window.mainloop()
```

1. kgの入力を受け取り、グラム、パウンド、オンスに変換された数値を返すもの。
2. `Tk.Text`では最初のインデックスは '1.0' で表す。終わりはENDで表す。`delete`メソッドで使用されてる。参考元：http://www.shido.info/py/tkinter12.html
3. 入力を受け取るために、`StringVar()`に保存する。文字列が保存される
4. ここには存在していないが`Text`や`Entry`クラスのインスタンス化の際に、`rowspan`や`columnspan`という引数を指定できる。これはrowとcolumnそれぞれの範囲を指定できる。


##sqlite3
sqlite3はデータベースのライブラリー。データベース作ったり、編集したり。

```py

#Database operation
import sqlite3

#basic steps:
#1.Connect to a database
#2.Create a cursor(stream?) object
#3.Write an SQL query
#4.commit change
#5.quit database


#if no database file, database.db file will be created
def create_table():
    conn=sqlite3.connect("liter.db")
    cur=conn.cursor()
    #sql code, always in ""
    cur.execute("CREATE TABLE IF NOT EXISTS store (item TEXT, quantity INTEGER, price REAL)")
    conn.commit()
    conn.close()
    
def insert(item, quantity, price):
    conn=sqlite3.connect("liter.db")
    cur=conn.cursor()
    #add
    cur.execute("insert into store values (?,?,?)", (item, quantity, price))
    conn.commit()
    conn.close()
    
def view():
    conn = sqlite3.connect("liter.db")
    cur=conn.cursor()
    cur.execute("select * from store")
    raw = cur.fetchall()
    conn.close()
    return raw

def delete(item):
    conn = sqlite3.connect("liter.db")
    cur=conn.cursor()
    #(item,) ,をつけないとエラー。tupleとみなされない。ただの文字列とみなされる
    #https://stackoverflow.com/questions/16856647/sqlite3-programmingerror-incorrect-number-of-bindings-supplied-the-current-sta
    cur.execute("Delete from store where item=?", (item,))
    conn.commit()
    conn.close()
    
def update(item, quantity, price):
    conn = sqlite3.connect("liter.db")
    cur=conn.cursor()
    cur.execute("update store set quantity=?, price=? where item=?", (quantity,price,item))
    conn.commit()
    conn.close()
    
create_table()
insert("oppai", 72, 98)
update("oppai", 89, 72)
view()

#database is locked → .dbファイルをrenameして保存→元の名前に戻す
```

1. データベースのsql文の基本的な手順は、データベースへ接続→カーソル(ストリーム的なもの)を作成。sql命令文を実行。変化をデータベースへcommit。データベースと接続終わり。データベースに接続中なら何回でもsql命令文を実行できる。だから、データベースへの接続と接続終了のメソッドをそれぞれ作るのでもいい。
2. カーソルオブジェクトがデータベースを精査して、様々な動作を実行したり、検索したりする。
2. ifでデータベースにテーブルがない場合、新規作成するようにできる
2. sqlコードは""でくくる。大文字でも小文字でもいいが、sql実行分を大文字。テーブル名、カラム名を小文字で書くほうがわかりやすい
3. `カラム名 データ型`でcolumnを作成。REALはfloat型を指す
4. sql文に`?`を使うことで、`?`部分にtupleで値を渡すことができる。`?`を複数おいた場合、同じ長さのtupleを渡す必要がある
5. `?`が1つの場合でも、tupleで渡す必要がある。しかしただ()にいれるだけだと、エラー。`(文字列)`で渡すと、文字列1文字ずつが要素扱いのtupleとして扱われてしまう。解決方法は`(value, )`のように`,`で区切ればいい.
6. `cur.fetchall()`はリストの中にtuple形式の各rowが保存された形式がreturnされる
6. なんかdatabase lockedとかでたら名前を一旦変えて保存。元の名前に戻せば直る。参考元：http://fanblogs.jp/scripts/archive/61/0


寄り道：
tkinterで作られるような目に見える側→frontendって呼ばれる
sqlite3で作られるような目に見えない側→backendって呼ばれる
なるほど。初めて知った。