TkinterでCheckbuttonにチェックを付けると、Entryが編集できるようにする

環境：
Ubuntu 18.04.5 LTS (Windows Subsystem for Linux)
Python 3.8.0
VcXsrv 1.20.5.1

## 目標
PythonのTkinterでチェックボックス(Checkbutton)にチェックをつけると、入力欄(Entry)が有効になり入力できるようにする。
チェックを外すと、編集できなくする。
<img width="134" alt="check.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/477781/20b1dc3c-0a0c-e413-120f-6c960aa0b12e.png">
<img width="134" alt="checkme.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/477781/2c7ea0de-4d71-9016-63ae-3035f31eaddf.png">
## 方法

```python
import tkinter as tk

def change_state():
    if bool_check.get():
        # チェックをつけたとき
        entry.config(state='normal')
    else:
        # チェックをはずしたとき
        entry.config(state='disabled')

root = tk.Tk()

entry = tk.Entry()
entry.config(state='disabled')  # 最初は無効

bool_check = tk.BooleanVar()
bool_check.set(False)  # 最初はチェックなし
check = tk.Checkbutton(variable=bool_check, command=change_state)

check.pack()
entry.pack()

root.mainloop()
```

change_state関数を定義します。

変数名は何でもいいですが、例えばbool_check変数にtk.BooleanVar()を代入します。
tk.Checkbutton()の引数variableにbool_check変数を、引数commandにchange_state関数を渡してチェックボックスを作成します。

チェックの有無はbool_check.get()でブール値で返されます。
チェックをつけはずしするとchange_state()が呼ばれます。

change_state()では作製したentryのstateをチェックの有無に応じて変更します。

## 2つ以上作りたいとき
change_state()にbool_checkやentryを引数として渡せられれば、2つ以上の入力欄で同様のことができそうです。
<img width="134" alt="likethis.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/477781/a7cf30a4-b825-a2b4-6ba0-5de5799e0645.png">
しかしながら例えば、

```python
def change_state(bool_check, entry):
    if bool_check.get():
        entry.config(state='normal')
    else:
        entry.config(state='disabled')
```
のようにchange_state関数を引数付きで定義して、

```python
tk.Checkbutton(command=change_state(bool_check, entry))
```
のようにtk.Checkbutton()のcommand引数に、引数付きの関数を渡しても正しく動作しません。
正しく動作するには、commandにlambda式を渡します。すなわち、

```python
import tkinter as tk

def change_state(bool_check, entry):
    if bool_check.get():
        entry.config(state='normal')
    else:
        entry.config(state='disabled')

root = tk.Tk()

# 1つ目
entry1 = tk.Entry()
entry1.config(state='disabled')
bool_check1 = tk.BooleanVar()
bool_check1.set(False)
check1 = tk.Checkbutton(text='1', variable=bool_check1,
                        command=lambda: change_state(bool_check1, entry1))
check1.pack()
entry1.pack()

# 2つ目
entry2 = tk.Entry()
entry2.config(state='disabled')
bool_check2 = tk.BooleanVar()
bool_check2.set(False)
check2 = tk.Checkbutton(text='2', variable=bool_check2,
                        command=lambda: change_state(bool_check2, entry2))
check2.pack()
entry2.pack()

root.mainloop()

```
こちらの書き方の方が、change_state関数がグローバル変数に依存せず良いような気がします。


## 簡単な応用
チェックをはずすと、入力されていた文字列を削除して"無効"を表示してみる。

<img width="134" alt="aaa.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/477781/21a4e812-f2bf-987f-80ac-af76d5dea42f.png">
<img width="134" alt="mukou.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/477781/b67ebc85-07f7-6164-1b2b-bb8de7ee8a00.png">

```python
import tkinter as tk

def change_state():
    if bool_check.get():
        # チェックをつけたとき
        entry.config(state='normal')
        entry.delete(0, tk.END)  # normalにしてから"無効"をdeleteする
    else:
        # チェックをはずしたとき
        entry.delete(0, tk.END)  # 0文字目から終わりまで文字列を削除する
        entry.insert(0, "無効")  # Entryの0文字目に"無効"をinsert
        entry.config(state='disabled')  # insertしてからdisableにする

root = tk.Tk()

entry = tk.Entry()
entry.insert(0, "無効")  # Entryの0文字目に"無効"をinsert
entry.config(state='disabled')  # insertしてからdisableにする

bool_check = tk.BooleanVar()
bool_check.set(False)
check = tk.Checkbutton(variable=bool_check, command=change_state)

check.pack()
entry.pack()

root.mainloop()
```

初期値を与えるなど、応用ができそうです。