tkinterを使ってpython GUIを作る

tkinterの使い方メモです


## パネルを表示する

オブジェクト作ってmainloop()すると表示しながら待機状態に入ってくれます。

```python:python
import tkinter as tk
root = tk.Tk()
root.mainloop()
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277233/bb7521d4-d134-530d-f99d-21ade7db75f1.png" width=30%>






## パネルの大きさを設定

```python:python
root = tk.Tk()
root.geometry("500x320")
root.mainloop()
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277233/c7baf11f-fa79-aad2-50a9-d064be07dc8c.png" width=50%>








## パネルのタイトルを設定

```python:python
root = tk.Tk()
root.geometry("250x150")
root.title('あびゃー')
root.mainloop()
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277233/7d5f3e17-c875-ce10-8ef7-6161bac0bcdf.png" width=50%>




## パーツを置く

#### 文字列ラベル

```python:python
root = tk.Tk()
root.geometry("250x150")
label = tk.Label(text='らべる')
label.pack()
root.mainloop()
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277233/a209292e-1f79-9855-da56-9edc5b917cb6.png" width=50%>
fontはfamily, size, style1, style2, ... という感じで指定します。















#### ボタン
以下はボタンを置くだけです。

```python:python
root = tk.Tk()
root.geometry("250x150")
button = tk.Button(root, text="ぼたん", width=20, height=3)
button.pack()
root.mainloop()
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277233/77725ecc-64f9-6064-ee8d-0bb71edee27c.png" width=50%>











## ボタン操作に反応する

tkinterオブジェクトのbind()メソッドを実行すれば指定したeventが発生したときに関数を呼ぶように設定できます。bind()の第1引数がeventの種類、第2引数が呼ぶ関数です。以下では1回クリックされた時に発生する<Button-1>イベントでfunc()を呼ぶようにしています。

```python:python
def func(event):
    print('ボタンを押したぞい')

root = tk.Tk()
root.geometry("250x150")
button = tk.Button(root, text="ぼたん", width=20, height=3)
button.bind('<Button-1>', func)
button.place(x=40, y=125)
root.mainloop()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277233/77725ecc-64f9-6064-ee8d-0bb71edee27c.png)















## ボタン操作に対応して表示を変更する

呼ばれる側の引数はtkinterが渡してくるeventしか受け取る事ができないので、関数内部で変数を扱う場合はグローバル変数にするか、class内に置いてclassプロパティを受け取るようにします。
 
```python:python
class TkinterClass:
    def __init__(self):
        self.count = 0

        self.root = tk.Tk()
        self.root.geometry("250x160")

        label = tk.Label(text='押した回数をカウントします')
        label.pack(pady=10)

        self.button_text = tk.StringVar()
        self.button_text.set(self.count)
        button = tk.Button(self.root, textvariable=self.button_text, font=('', 32),
                           width=8, height=1, bg='#999999', activebackground="#aaaaaa")
        button.bind('<ButtonPress>', self.func1)
        button.pack(pady=10)
        self.root.mainloop()

    def func1(self, event):
        self.count += 1
        self.button_text.set(self.count)


if __name__ == '__main__':
    tkc = TkinterClass()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277233/c98497ce-7de4-7206-48eb-e1addd8a51c7.png)
















## フォントを指定する

font family, font size, style1, style2,… の順で指定します。
styleが複数ある場合は3つめ以降に続けて書いていきます。

```python:python
root = tk.Tk()
root.geometry("250x150")
label = tk.Label(text='らべる', font=('arial', 20, 'italic', 'overstrike'))
label.pack()
root.mainloop()
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277233/b4463178-1fd4-420b-1143-6105f13c5d77.png" width=50%>
font familyは省略できます。

```python:python
root = tk.Tk()
root.geometry("250x150")
label = tk.Label(text='らべる', font=('', 20))
label.pack()
root.mainloop()
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277233/141e2e74-6320-81ed-fa16-a3609961a7d9.png" width=50%>

















## パーツの配置

#### 3つの配置方法があります

pack(): 順に置いていく
grid(): グリッドで並べていく
place(): 座標指定で置いていく

## pack()

引数なしでpack()すると中央揃えで上から順に並べます。

```python:python
root = tk.Tk()
root.geometry("250x150")

label = tk.Label(text='らべる1', font=("", 12), bg='#33ccaa', relief=tk.RIDGE, bd=2)
label.pack()

label = tk.Label(text='らべる2', font=("", 12), bg='#dd88aa', relief=tk.RIDGE, bd=2)
label.pack()

label = tk.Label(text='らべる3', font=("", 12), bg='#bbdd44', relief=tk.RIDGE, bd=2)
label.pack()

root.mainloop()
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277233/3df5829a-a792-4cf9-47ae-271ebbe42e02.png" width=50%>
#### pack(anchor=tk.W)で左寄せ




```python:python
root = tk.Tk()
root.geometry("250x150")

label = tk.Label(text='らべる1', font=("", 12), bg='#33ccaa', relief=tk.RIDGE, bd=2)
label.pack(anchor=tk.W)

label = tk.Label(text='らべる2', font=("", 12), bg='#dd88aa', relief=tk.RIDGE, bd=2)
label.pack(anchor=tk.W)

label = tk.Label(text='らべる3', font=("", 12), bg='#bbdd44', relief=tk.RIDGE, bd=2)
label.pack(anchor=tk.W)

root.mainloop()
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277233/30ae69ca-411d-2eef-177d-82b4b6a80740.png" width=50%>
#### pack(fill=tk.X)で両揃え

fill=tk.Xで幅いっぱいに広げます。

```python:python
root = tk.Tk()
root.geometry("250x150")

label = tk.Label(text='らべる1', font=("", 12), bg='#33ccaa', relief=tk.RIDGE, bd=2)
label.pack(fill=tk.X)

label = tk.Label(text='らべる2', font=("", 12), bg='#dd88aa', relief=tk.RIDGE, bd=2)
label.pack(fill=tk.X)

label = tk.Label(text='らべる3', font=("", 12), bg='#bbdd44', relief=tk.RIDGE, bd=2)
label.pack(fill=tk.X)

root.mainloop()
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277233/7b64cb22-936f-7e97-f86a-7cacbbe856b9.png" width=50%>
#### pack(padx=10, pady=10)でパディングする
pady, padxで縦横のすき間をpixelで指定できます。

```python:python
root = tk.Tk()
root.geometry("250x150")

label = tk.Label(text='らべる1', font=("", 12), bg='#33ccaa', relief=tk.RIDGE, bd=2)
label.pack(fill=tk.X, padx=10, pady=10)

label = tk.Label(text='らべる2', font=("", 12), bg='#dd88aa', relief=tk.RIDGE, bd=2)
label.pack(fill=tk.X, padx=10, pady=10)

label = tk.Label(text='らべる3', font=("", 12), bg='#bbdd44', relief=tk.RIDGE, bd=2)
label.pack(fill=tk.X, padx=10, pady=10)

root.mainloop()
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277233/dda263e7-c0d0-9ae7-6102-3c39d3758f3c.png" width=50%>
















## grid()

何も指定しないと左上から下に追加していきます。

```python:python
root = tk.Tk()
root.geometry("250x150")

label = tk.Label(text='らべる1', font=("", 12), bg='#33ccaa', relief=tk.RIDGE, bd=2)
label.grid()

label = tk.Label(text='らべる2', font=("", 12), bg='#dd88aa', relief=tk.RIDGE, bd=2)
label.grid()

label = tk.Label(text='らべる3', font=("", 12), bg='#bbdd44', relief=tk.RIDGE, bd=2)
label.grid()

root.mainloop()
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277233/f9a99392-54fa-1cba-544b-5e2252b3cbe6.png" width=50%>

#### grid(row, column, columnspan)で位置と幅を指定

row, columnで位置を指定し、rowspan, columnspanで幅を指定します。


```python:python
root = tk.Tk()
root.geometry("250x150")

label = tk.Label(text='らべる1', font=("", 12), bg='#33ccaa', relief=tk.RIDGE, bd=2)
label.grid(row=0, column=0, columnspan=2, padx=10, pady=10, sticky=tk.W+tk.E)

label = tk.Label(text='らべる2', font=("", 12), bg='#dd88aa', relief=tk.RIDGE, bd=2)
label.grid(row=1, column=0, padx=10, pady=10)

label = tk.Label(text='らべる3', font=("", 12), bg='#bbdd44', relief=tk.RIDGE, bd=2)
label.grid(row=1, column=1, padx=10, pady=10)

root.mainloop()
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277233/9108b270-d674-14c1-d8d8-0088d39b10ad.png" width=50%>

## place()

座標指定で配置します。

```python:python
root = tk.Tk()
root.geometry("250x150")

label = tk.Label(text='らべる1', font=("", 12), bg='#33ccaa', relief=tk.RIDGE, bd=2)
label.place(x=10, y=10)

label = tk.Label(text='らべる2', font=("", 12), bg='#dd88aa', relief=tk.RIDGE, bd=2)
label.place(x=85, y=40)

label = tk.Label(text='らべる3', font=("", 12), bg='#bbdd44', relief=tk.RIDGE, bd=2)
label.place(x=25, y=90)

root.mainloop()
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277233/0e19fa9a-762d-9d5f-9ba5-7dfd984ab0cb.png" width=50%>



## 表示/非表示/終了

withdraw()で一時的に非表示に出来ます。

```python:python
root.withdraw()
```
deiconify()で再表示できます。

```python:python
root.deiconify()
```
destroy()すればtkinter窓を閉じてroot.loopmain()を抜けます。

```python:python
root.destroy()
```