このページでは、Python の tkinter における update
メソッドについて解説していきます。
update
はメインウィンドウ・ボタン・ラベルなどの全ての種類のウィジェットに用意されたメソッドであり、mainloop
に戻らなくてもイベント処理(発生したイベントに関連付けられたイベントハンドラの実行)を行うことができる非常に便利なメソッドになります。
ただし、便利であるが故に注意点もあります。
そういった点も踏まえて、update
メソッドについて解説を行なっていきたいと思います。
また、update
メソッドの役割については、前述でも触れた mainloop
のことを知っておいた方が理解しやすいと思います。ですので、mainloop
のことをまだ理解されていない方は、先に下記ページを読んで mainloop
について理解しておくことをオススメします。
Contents
update
メソッドとは
前述の通り、update
は全ての種類のウィジェットに用意されたメソッドです。
実行時には引数の指定は不要で、例えば canvas
というウィジェットが存在するのであれば、下記のように記述を行うことで update
メソッドを実行することができます。
使い方は非常に簡単ですね!
canvas.update()
tkinter でのイベント処理
この update
は、即座にイベント処理を実行するメソッドになります。
前述でも紹介した mainloop
の記事でも解説していますが、tkinter で開発するアプリでは発生したイベント(ボタンのクリックイベント・キャンバスへの描画イベント等)に対し、そのイベントに関連付けられたイベントハンドラを実行することで様々な動作が実現されています。
そして、このイベントハンドラは mainloop
の中から実行されます。
より具体的には、スクリプトから mainloop
メソッドを実行することで上の図のようなループに入り、このループの中ではボタンのマウスクリックや各種ウィジェットの設定変更等のイベントが発生した際に、そのイベントに関連付けられたイベントハンドラが実行されるようになっています。
そして、そのイベントハンドラの処理が終了した際に、再びループに戻り、またイベントが発生した際にはイベントハンドラを実行するという流れでアプリの動作が実現されるようになっています。
このループを、本サイトでは mainloop
(メインループ)と呼んでいます。
例えば下記のスクリプトについて考えてみましょう!
import tkinter
def button_func():
label.config(text='Hello World!!!')
app = tkinter.Tk()
label = tkinter.Label(
app,
text='',
font=('', 40),
width=20
)
label.pack()
button = tkinter.Button(
app,
text='ボタン',
font=('', 20),
command=button_func
)
button.pack()
app.mainloop()
上記のスクリプトを実行して、ボタンをクリックすれば、label.config
の実行によってラベルの表示テキストが Hello World!!!
に更新されることになります。
アプリの動作としてはこれだけなのですが、この表示テキスト更新の際の tkinter の詳細な処理の流れは結構複雑で、具体的には次のようになります。
まず、上記のスクリプトを実行すれば mainloop
が実行されてイベント発生待ちのループの処理が行われることになります。そして、ボタンがクリックされることで「ボタンクリック」というイベントが発生し、そのイベントに関連づけられたイベントハンドラ(今回の場合は button_func
)が mainloop
から実行されます。
この時、実行中の処理は mainloop
ではなくイベントハンドラ(button_func
)に移ります。
さらに、button_func
の中で label.config
が実行されることで「ラベルの設定変更」というイベントが発生します。そして、このイベントの情報はキューに保存されます。
そして、button_func
が終了して mainloop
に戻った際に、そのキューに保存されたイベントに対するイベントハンドラが実行されます。つまり、先程キューに「ラベルの設定変更」というイベントが保存されましたので、ここで「ラベルの設定変更」に関連付けられたイベントハンドラが実行されることになります(このイベントハンドラは tkinter 本体で定義された関数となります)。
そして、このイベントハンドラの中でラベルの設定変更が実際に行われ、アプリ上のラベルの表示テキストが Hello World!!!
に変更されることになります。
この辺りの処理の流れについては、前述で紹介した mainloop
の記事でも解説していますので、この説明を聞いてイメージが湧かない方は mainloop
の記事を読んでみてください。
ここで重要なのは、ラベルの設定変更が実際に行われるのは label.config
が実行された時ではなく、「mainloop
に処理が戻った時になる」という点になります。
前述の通り、tkinter では mainloop
を実行すると mainloop
でイベントの発生待ちのループを行い、イベントが発生した際には mainloop
からイベントハンドラが実行されます
そして、イベントハンドラが終了すれば mainloop
に処理が戻ります
すなわち「mainloop
に処理が戻る」とは、実行中のイベントハンドラが終了することを意味します
ですので、例えば label.config
の後に sleep
等を利用して10秒間待機したりすると、その待機する時間の分 mainloop
に戻るのが遅れ、label.config
を実行してから約10秒後に表示テキストの変更が行われることになります。
また、例えば、sleep
等の実行によって mainloop
に処理が戻るのが遅くなると、その分ボタンクリック時に実行するイベントハンドラの実行タイミングも遅れるので、ユーザーからはボタンの反応が悪いアプリだと感じられてしまいます。
つまり、「例外」を除き、イベントが発生したとしても、mainloop
に戻らない限りはイベントハンドラは実行されないのです(この「例外」の1つが、後述で説明するように update
メソッドの実行になります)。
こういった理由から、tkinter でアプリ開発を行う際には「mainloop
に戻る」ことを意識してプログラミングを行う必要があります。例えば、特定の時間だけ待機したいのであればスリープではなく after
メソッドを利用した方が良いです。
この after
メソッドに関しては下記ページで解説していますので、詳しく知りたい方はこちらをご参照ください。
スポンサーリンク
update
メソッドの役割
ここまで解説してきた通り、ボタンクリックやラベルの設定変更等のイベントが発生した際には、mainloop
に戻った時に、それらのイベントに関連付けられたイベントハンドラが実行されることになります。
あくまでもイベントハンドラが実行されるのが「mainloop
から」となるため、イベント発生時に即座にイベントハンドラが実行されるとは限らないということになります(イベント発生時に mainloop
の中にいる場合のみ即座にイベントハンドラは実行される)。
通常は上記のような仕組みでイベントハンドラが実行されるのですが、実は例外があります。
その例外の1つが update
の実行になります。
update
メソッドが実行された際には、mainloop
に戻らなくても、即座に「既に発生したイベントに関連付けられたイベントハンドラ」の実行が行われます。
つまり、update
は即座にイベントハンドラを実行するメソッドとなります。
例えば、前述の例で挙げたように、下記のようにイベントハンドラの中で label.config
実行後に sleep
で10秒間待機した場合、ラベルの表示テキストの更新は label.config
を実行してから約10秒後に行われることになります。これは、sleep
を実行することでイベントハンドラの実行時間が増え、その分 mainloop
に戻るのが遅れるためです。
import time
def button_func():
label.config(text='Hello World!!!')
time.sleep(10)
それに対し、下記のように label.config
と sleep
の間で update
メソッドを実行するようにすれば、ラベルの表示テキストの更新は label.config
実行直後に行われることになります。
これは、update
メソッドを実行することで、今まで発生したイベントに関連付けられたイベントハンドラが即座に実行されるからです。
import time
def button_func():
label.config(text='Hello World!!!')
label.update()
time.sleep(10)
そして、ラベルの表示テキストの更新後に sleep
が行われ、10秒間待機した後に mainloop
に戻ることになります。ただし、mainloop
に戻った際には既に「ラベルの設定変更」のイベントに対するイベントハンドラは実行済みですので、この時点ではそのイベントハンドラは実行されないことになります。
こんな感じで、mainloop
に戻る前に即座にイベントハンドラを実行することができるのが update
メソッドとなります。
update
メソッドの使用例
続いて、簡単な例で update
メソッドの使用例を紹介していきたいと思います。
今回は、下のアニメのような「おみくじアプリ」の開発を例に、update
メソッドの使用例を紹介していきます。このおみくじアプリでは、ボタンが押された際にランダムに選んだおみくじの結果(大吉・吉・中吉・凶)を表示するアプリとなります。
簡単に作れそうなアプリですが、特に mainloop
やイベントハンドラの実行タイミングをご存知ない方にとっては実現が困難なアプリなのではないかと思います。
ポイントは、ボタンが押された直後に あなたの運勢は
と表示し、1秒ごとにテキストの最後にピリオド(.
)を追加する、さらにピリオドを3つ追加した1秒後におみくじの結果を表示するところになります。結果の表示を焦らす際に良く使うテクニックだと思いますが、tkinter の場合は、このような表示の実現が結構難しいです。
sleep
を利用した「おみくじアプリ」(NG 例)
この「おみくじアプリ」を実現する手段として最初に思いつくのが「sleep
で1秒待機しながらラベルの表示テキスト変更していく」だと思います。
sleep
を利用した場合、この「おみくじアプリ」のソースコードは下記のように記述することになると思います。
import tkinter
import random
import time
def omikuji():
label.config(text='あなたの運勢は')
time.sleep(1)
label.config(text='あなたの運勢は.')
time.sleep(1)
label.config(text='あなたの運勢は..')
time.sleep(1)
label.config(text='あなたの運勢は...')
time.sleep(1)
result = random.choice(('大吉', '吉', '中吉', '凶'))
label.config(text=result + 'です!')
app = tkinter.Tk()
label = tkinter.Label(
app,
width=20,
font=('', 40)
)
label.pack(padx=10, pady=10)
button = tkinter.Button(
app,
text='おみくじ',
command=omikuji
)
button.pack(padx=10, pady=10)
app.mainloop()
これで上手くいきそうな気もするかもしれませんが、このスクリプトを実行して おみくじ
ボタンを押した場合の動作は下のアニメのようになります。
おみくじ
ボタンを押しても あなたの運勢は
が表示されずにいきなりおみくじの結果が表示されてしまっています。さらに、表示されるのはボタンを押した約4秒後になります。
このような動作になってしまう原因に関しては、おそらくここまでの解説を読んでくださった方であればすぐに思いつくのではないかと思います。
前述の通り、イベントが発生した際、そのイベントに関連づけられたイベントハンドラが実行されるのは mainloop
に戻った時になります。
上記のスクリプトでは、おみくじ
ボタンがクリックされた際には「おみくじ
ボタンのクリック」のイベントに関連付けられたイベントハンドラ omikuji
が実行されます(この関連付けは、tkinter.Button
での command
の指定によって実現しています)。
このイベントハンドラ omikuji
も mainloop
から実行されるのですが、この実行を行うことで実行中の処理が mainloop
ではなく omikuji
となり、次に mainloop
に戻るタイミングは omikuji
終了時となります。
また、omikuji
の中では label.config
の実行が5回行われ、それぞれに対して「ラベルの設定変更」のイベントが発生することになります。そして、これらのイベントに関連付けられたイベントハンドラは、次に mainloop
に戻るタイミング(omikuji
終了時)にまとめて実行されることになります。
ですが、この時にラベルの設定変更が5回まとめて実行されることになるため、ラベルの表示テキストとしては最後に実行された label.config(text=result + 'です!')
の結果のみが残ることになるため、あなたの運勢は
というテキストは表示されず、いきなりおみくじの結果が表示されることになっています。
また、omikuji
の中で time.sleep(1)
を4回実行しているため、omikuji
が終了するのに約4秒の時間がかかることになります。そのため、ラベルの表示テキストが実際に変更されるタイミングが おみくじ
ボタンをクリックした約4秒後となってしまっています。
こんな感じで、tkinter でアプリを開発する際に sleep
を利用してしまうと、開発者の意図しない動作になることが多いです。
GUI を利用せずに print
を利用してコンソール出力のみを場合は sleep
を使っても意図した通りに動作してくれるのですが、tkinter の場合は上記のように意図した通りに動作してくれないので、この点が tkinter 利用の難しさの1つになるかと思います。
スポンサーリンク
after
を利用した「おみくじアプリ」
では、1秒ごとにラベルの表示テキストの更新を行うようにするためにはどうすれば良いでしょうか?
その1つの手段が after
メソッドの利用になります。
after
メソッドについては下記ページで解説をしていますが、after
メソッドを実行すれば、指定した時間だけ処理(イベントハンドラ)を遅らせて実行させることができます。
sleep
では実行時に指定した時間だけ待機されるため、その分 mainloop
に戻るまでの時間が長くなります。それに対して after
メソッドでは実行時には待機が行われずにすぐに処理が完了します。そのため、after
メソッドを利用しても mainloop
に戻るまでの時間はほとんど長くなりません。
そして、指定した時間が経過した時に、指定した処理が実行されることになります(この処理の実行も mainloop
から実行されます)。
after
メソッドを利用した場合のおみくじアプリは下記のように記述することができます。
import tkinter
import random
count = 0
def omikuji():
global count
if count == 0:
label.config(text='あなたの運勢は')
count += 1
app.after(1000, omikuji)
elif count == 1:
label.config(text='あなたの運勢は.')
count += 1
app.after(1000, omikuji)
elif count == 2:
label.config(text='あなたの運勢は..')
count += 1
app.after(1000, omikuji)
elif count == 3:
label.config(text='あなたの運勢は...')
count += 1
app.after(1000, omikuji)
elif count == 4:
result = random.choice(('大吉', '吉', '中吉', '凶'))
label.config(text=result + 'です!')
count = 0
app = tkinter.Tk()
label = tkinter.Label(
app,
width=20,
font=('', 40)
)
label.pack(padx=10, pady=10)
button = tkinter.Button(
app,
text='おみくじ',
command=omikuji
)
button.pack(padx=10, pady=10)
app.mainloop()
今回は、最初に紹介したアニメのように、1秒ごとにラベルの表示テキストが更新されていく様子が確認できると思います。
上記スクリプトでは、おみくじ
ボタンがクリックされた時に omikuji
関数がイベントハンドラとして実行されるようになっています。
omikuji
関数では、まず count == 0
の時の処理が実行され、label.config
でラベルの表示テキストが あなたの運勢は
に変更され、さらに count
を +1
した後に after
メソッドの実行を行なっています。
この after
メソッドの実行により、1000
ミリ秒後に再度 omikuji
関数が実行されるようになります。
そして、前述の通り、after
メソッドでは sleep
とは違って実行時に待機が行われませんので即座にメソッドが終了し、さらには omikuji
関数も終了することになります。
この omikuji
関数は mainloop
から実行されていますので、omikuji
関数が終了すると実行元(関数呼び出し元)の mainloop
に処理が戻ることになります。
mainloop
に処理が戻るため、先程 label.config
実行時に発生したイベントに対するイベントハンドラが mainloop
から実行されてラベルの表示テキストの更新が行われます。なので、この時点でアプリ上のラベルに表示されるテキストが あなたの運勢は
に変化することになります。
そして、1000
ミリ秒経過した際には omikuji
関数が再度実行され、次は count == 1
の時の処理が実行されます。この時も先程とほぼ同様の処理が実行されますので、アプリ上のラベルに表示されるテキストが あなたの運勢は.
に変化し(ピリオドが1つ増える)、さらに 1000
ミリ秒経過した際には、omikuji
関数が再度実行されることになります。その後もほぼ同様の動作になります。
こんな感じで、after
メソッドを利用することで、すぐに mainloop
に処理を戻すことができ、それに伴ってすぐにラベル等のウィジェットの更新が行われるようになります。
sleep
と update
を利用した「おみくじアプリ」
1秒ごとにラベルの表示テキストの更新を行うための手段の2つ目が、このページで注目している update
メソッドの利用になります。
前述の通り、update
を実行することで、それまでに発生したイベントに対するイベントハンドラの実行を行うことができます。今回の例であれば、label.config
を実行した直後に update
メソッドを実行すれば、update
メソッド実行時にアプリ上のラベルに表示されているテキストを更新することができます。
つまり、update
メソッドを利用すれば mainloop
に戻る前にラベルの表示テキストの更新を行うことができるため、わざわざ after
メソッドを利用して mainloop
にすぐに戻るように処理を記述しなくても、定期的なラベルの表示テキストの更新を実現することが可能になります。
update
メソッドを利用した場合のおみくじアプリは下記のように記述することができます。sleep を利用した「おみくじアプリ」(NG 例) で紹介したスクリプトに対し、sleep
を実行する前に update
メソッドの実行を追加しています。
import tkinter
import random
import time
def omikuji():
label.config(text='あなたの運勢は')
app.update()
time.sleep(1)
label.config(text='あなたの運勢は.')
app.update()
time.sleep(1)
label.config(text='あなたの運勢は..')
app.update()
time.sleep(1)
label.config(text='あなたの運勢は...')
app.update()
time.sleep(1)
result = random.choice(('大吉', '吉', '中吉', '凶'))
label.config(text=result + 'です!')
app = tkinter.Tk()
label = tkinter.Label(
app,
width=20,
font=('', 40)
)
label.pack(padx=10, pady=10)
button = tkinter.Button(
app,
text='おみくじ',
command=omikuji
)
button.pack(padx=10, pady=10)
app.mainloop()
上記スクリプトを実行すれば、今回も最初に紹介したアニメのように1秒ごとにラベルの表示テキストが更新されていく様子が確認できると思います。
最後の label.config
の実行を除き、label.config
実行直後に update
メソッドを実行することで、label.config
によるラベルの表示テキストの更新が即座に行われるようにしています。そして、その後に sleep
を実行することで、1秒間待機し、sleep
が終了したら同様にラベルの表示テキストの更新を行うようにしています。
最後の label.config
実行に関しては、この実行終了直後に omikuji
関数が終了して mainloop
に戻るため、わざわざ update
メソッドを実行する必要はありません。
sleep を利用した「おみくじアプリ」(NG 例) で紹介したスクリプトとの動作の違いを考えれば、update
メソッドの動作の効果は一目瞭然ではないかと思います。
こんな感じで、update
メソッドを利用することで mainloop
に戻る前にイベントハンドラの実行を行うことができます。
update
メソッドのメリット・デメリット
では、最後に update
メソッドのメリットとデメリットについて説明しておきたいと思います。
スポンサーリンク
update
メソッドのメリット
update
メソッドを利用するメリットは「スクリプトが簡単になる」だと思います。
実際、after を利用した「おみくじアプリ」 で紹介した omikuji
関数と sleep と update を利用した「おみくじアプリ」 で紹介した omikuji
関数とを比較すれば、後者の方が分かりやすいと思う方が大半なのではないかと思います。
update
メソッドを利用しない場合、前述の通り、ラベル等の表示を更新やボタンクリック時の処理を実行するためには mainloop
に処理を戻す必要があります。ですので、アプリの反応を良くするためには、常に mainloop
に戻すことを考えながらプログラミングする必要があり、それによって処理は複雑になることが多いです。
例えば after を利用した「おみくじアプリ」 で紹介した omikuji
関数では、after
メソッドを利用することで mainloop
にすぐに戻れるようにしていますが、これを実現するために関数が呼ばれた回数を管理し、その回数に応じて処理を分岐するような記述が必要となってしまっています。
それに対し、update
メソッドを利用すれば、言ってしまえば mainloop
を意識することなくプログラミングすることが可能です。それまでに発生したイベントに関連付けられたイベントハンドラを実行させたいタイミングで update
メソッドを実行すれば良いだけです。
mainloop
を意識することなくプログラミングできるので、tkinter ならではの書き方をする必要はなく、通常のコンソール出力時と同様の感覚でプログラミングすることができます。
そして、その結果、スクリプトが簡単になります。
update
メソッドのデメリット
ただ、そういったメリットもあるのですが、個人的には tkinter でアプリを開発するのであれば mainloop
を意識し、常に mainloop
にすぐに処理が戻るようにプログラミングすることを心がけたほうが良いと思います。
その1つの理由は、update
メソッドに頼って mainloop
を意識せずにプログラミングした場合、アプリの反応が悪くなる可能性があるからです。
その実例を示すために、sleep と update を利用した「おみくじアプリ」 で紹介した omikuji
関数を下記のように変更したいと思います。sleep
の引数を全て 1
から 5
に変更しています。つまり、ラベルの表示テキストの更新が5秒ごとに行われるようになります。
import tkinter
import random
import time
def omikuji():
label.config(text='あなたの運勢は')
app.update()
time.sleep(5)
label.config(text='あなたの運勢は.')
app.update()
time.sleep(5)
label.config(text='あなたの運勢は..')
app.update()
time.sleep(5)
label.config(text='あなたの運勢は...')
app.update()
time.sleep(5)
result = random.choice(('大吉', '吉', '中吉', '凶'))
label.config(text=result + 'です!')
app = tkinter.Tk()
label = tkinter.Label(
app,
width=20,
font=('', 40)
)
label.pack(padx=10, pady=10)
button = tkinter.Button(
app,
text='おみくじ',
command=omikuji
)
button.pack(padx=10, pady=10)
app.mainloop()
このスクリプトを実行し、おみくじ
ボタンを押した後にマウスでウィンドウのサイズを変更しようとしても、おそらく上手く変更することができないのではないかと思います(タイミングによっては上手く変更できるかも)。
同様に5秒間隔でラベルの表示テキストの更新が行われるよう、after を利用した「おみくじアプリ」 で紹介したスクリプトを下記のように変更して同様の操作を行なってみましょう(after
の第1引数を 1000
から 5000
に変更しています。)
import tkinter
import random
count = 0
def omikuji():
global count
if count == 0:
label.config(text='あなたの運勢は')
count += 1
app.after(5000, omikuji)
elif count == 1:
label.config(text='あなたの運勢は.')
count += 1
app.after(5000, omikuji)
elif count == 2:
label.config(text='あなたの運勢は..')
count += 1
app.after(5000, omikuji)
elif count == 3:
label.config(text='あなたの運勢は...')
count += 1
app.after(5000, omikuji)
elif count == 4:
result = random.choice(('大吉', '吉', '中吉', '凶'))
label.config(text=result + 'です!')
count = 0
app = tkinter.Tk()
label = tkinter.Label(
app,
width=20,
font=('', 40)
)
label.pack(padx=10, pady=10)
button = tkinter.Button(
app,
text='おみくじ',
command=omikuji
)
button.pack(padx=10, pady=10)
app.mainloop()
この場合は、おみくじ
ボタンを押した後にウィンドウのサイズをマウスで変更すれば、上手くウィンドウのサイズが変更可能であることが確認できるはずです。
なぜ、2つのスクリプトで前述のような動作の違いが生じるのでしょうか?
これは、mainloop
に処理を戻すかどうかによって生じる動作の違いとなります。
前者のスクリプトの場合、ラベルの表示テキスト自体は update
メソッドの実行によって即座に更新されますが、その後の sleep
を実行している間、mainloop
ではなく omikuji
関数で処理が行われていることになります。
さらに、ウィンドウのサイズ変更もラベルの表示テキストの変更同様にイベントとして扱われるため、次に mainloop
に戻るまで、もしくは次に update
メソッドが実行されるまでサイズ変更が反映されないことになります。
したがって、おみくじ
ボタンをクリックして omikuji
関数が開始されると、sleep
で待機している5秒間はウィンドウのサイズ変更が行われないようになってしまいます。
それに対して後者のスクリプトの場合、after
メソッドは「遅らせて実行する処理(関数やメソッド)」の設定のみを行なって即座に終了しますので、おみくじ
ボタンをクリックしてもすぐに mainloop
に処理が戻ることになります。つまり、5秒間の待機は omikuji
関数ではなく mainloop
の中で行われます。
mainloop
の中で待機が行われるため、5秒間の間にウィンドウのサイズ変更が行われた際にも、そのサイズ変更を即座に反映することができます。
こんな感じで、mainloop
に戻る or 戻らないかの違いは、アプリの反応性に大きく影響します。
上記の例に関しては sleep
を利用していることが問題であると言えますが、update
メソッドに頼りすぎて mainloop
に戻ることを怠ると同様の現象が発生しますので、update
メソッドに頼るよりも mainloop
でイベント処理が実行されることを意識してプログラミングするほうが良いと思います。
とは言え、mainloop
に戻すことを意識してプログラミングした場合、スクリプトが複雑になりすぎる可能性もありますので、アプリの反応性に影響が出ない程度に update
メソッドを利用するのは良いと思います。
また、アプリの反応性が悪くても問題ない場合に関しては update
メソッドを利用しても良いと思います。例えば自分の作業効率を良くするためのツールを tkinter で開発するのであれば、自身が我慢できればアプリの反応性は悪くても問題ないですよね!こういった場合も update
メソッドを利用して単純な処理でアプリを開発しても良いと思います。
まとめ
このページでは、Python の tkinter における update
メソッドについて解説しました!
update
メソッドを利用することで、mainloop
に戻ることなく、それまでに発生したイベントに関連付けられたイベントハンドラを実行することができます。
mainloop
を意識することなくウィジェット等の設定を即座に反映することができるため非常に使い勝手の良いメソッドです。ですが、update
メソッドに頼りすぎるとアプリの反応が悪くなる可能性もあるため、基本的には mainloop
に処理を戻すことを意識しながらプログラミングするようにし、要所要所でのみ update
メソッドを利用するようにするのが良いと思います。
今回の記事でも度々登場したように、tkinter でのアプリ開発では mainloop
が非常に重要になります。mainloop
のことを理解しておけば、tkinter のアプリ開発もやりやすくなるので、mainloop
については是非理解しておいてください!