【Python tkinter】after()メソッド:関数を指定時間経過後(定期的)に実行する

時計 2021.08.13 / 時計

【Python tkinter】after()メソッド:関数を指定時間経過後(定期的)に実行する

本記事ではPythontkinterで使用する、after()メソッドの使い方について解説していきます。

tkinterはPythonでGUIアプリケーションを作成する際に使われる、有名な標準ライブラリの一つです。
tkinterによるGUIアプリケーションの開発については以下記事をご参照ください。

tkinterに用意されているafter()メソッドは、指定した関数を一定時間経過後(定期的)に実行する機能を提供します。

本記事ではafter()メソッドの詳しい使い方や、サンプルコードを紹介しながら実際の使い方をご紹介していきます。

tkinter:after()メソッド

after()メソッドとは

after()メソッドでは、
指定した時間経過後に関数を実行する機能を提供します。

つまり関数の実行スケジュールを行えるということです。

すべてのウィジェットはafter()メソッドを使用できます。

構文

after(delay, callback=None)

第一引数delayには時間(ms秒)を指定し、第二引数callbackには関数を指定します。
after()メソッドでこれら引数を指定することで、ms秒後に指定した関数実行することができます。

tkinter:after()メソッドによる定期実行

after()メソッドの戻り値としてIDが返されます。
これはafter()メソッドで登録した関数の実行をafter_cancel()メソッドで取り消しする際に使用します。

またafter()メソッドで実行される関数は、mainloop内で実行されます。

重要事項

after()メソッド実行後にms秒後待機してから関数が実行されるわけではなく、mainloop内で関数は実行されます。そのためafter()メソッド実行後から指定した関数の実行までの間、別の処理やマウス・キーボード操作を行うことができます。

after()メソッドの注意点として、
指定された時間経過後に必ず関数が実行されるわけではないです。

指定した関数はmainloopで実行されるため、アプリケーションがbusy状態の場合、mainloopが実行されずに指定時間を経過しても実行されないという可能性はあります。

after()メソッドの特徴

ここまでで説明してきたafter()メソッドの特徴を以下にまとめます。

  • 指定した時間経過後に関数を実行する機能を提供
  • すべてのウィジェットに対して使用可能
  • 戻り値としてIDが返される(after_cancel()メソッドで実行の取り消しを行う)
  • after()メソッドで実行される関数はmainloop内で実行される
  • アプリがbusy状態の場合は指定時間経過しても関数が実行されない可能性がある

関数を定期的に実行する

after()メソッドの便利な使い方の一つとして、
指定した関数を一定間隔で定期的に実行する方法があります。

次のように記述することで関数の定期実行を実現できます。

def repeat():
    #ここに定期的に実行する処理を記述する
    root.after(3000, repeat)

root = tk.Tk()
root.after(3000, repeat)
root.mainloop()

上記を見てわかるように、repeat()関数は3000ms秒ごとに永遠と繰り返し実行されます。
つまりrepeat()関数が定期的に実行されていると言えます。

repeat()関数内に定期的に実行したい処理を記述することで、処理を定期的に実行するプログラムを作成できるというわけです。

サンプルコード:デジタル時計

以下プログラムでは、デジタル時計を表示します。
毎秒現在の時間を更新するためにafter()メソッドを用いております。

import tkinter as tk
from tkinter import ttk
import time

def time_string():
    return time.strftime('%H:%M:%S')

def update():
    label.configure(text=time_string())
    label.after(1000, update)

root = tk.Tk()
root.title("Digital Clock")
root.geometry("250x80")
root["bg"] = "black"

style = ttk.Style()
style.configure('TLabel', background='black', foreground='red')

label = ttk.Label(root, text=time_string(), font=('Digital-7', 40))
label.pack(expand=True)

label.after(1000, update)

root.mainloop()
tkinter:ディジタル時計

上記プログラムの重要な点を以下より解説していきます。

ラベルに時計を表示

本プログラムでは、tkinterのラベルウィジェットに時計を表示しています。

ラベルウィジェットについては以下記事で詳しく解説していますので、そちらをご参照ください。

現在の時刻を出力

現在の時刻(フォーマット済み)を出力するために、time_string()関数内でtime.strftime()を用いています。

def time_string():
    return time.strftime('%H:%M:%S')

datetimeオブジェクトを文字列に変換するstrftime()メソッドについては以下記事をご参照ください。

datetimeオブジェクトを文字列への変換(strftime()メソッド)

毎秒時計の表示を更新

時計表示を毎秒更新するためにまずはafter()メソッドを用いて、1000ms秒後にupdate()関数を実行します。

label.after(1000, update)

1000秒後に実行されるupdate()関数では、ラベル表示を現在の時刻で更新し、再度1000秒後にupdate()関数を実行するafter()メソッドを実行します。

このafter()メソッドにより定期的(1秒ごと)に処理を実行、つまり時計の表示を変更しているのです。

def update():
    label.configure(text=time_string())
    label.after(1000, update)

time.sleep()とafter()の違い

time.sleep()とafter()は指定した時間待機する、という点で似ています。
しかし実際のプログラム内での動きが異なっています。

time.sleep()では指定した時間分の待機は、time.sleep()内で行います。

つまりtime.sleep()での待機中は他の処理を実行できないということを意味します。

after()での待機は、after()内ではなくmainloop内で行われるため、after()実行後から指定した関数が実行されるまでの間、別処理の実行やマウス・キーボード操作ができます。

after()の取り消し:after_cancel()メソッド

after_cancel()メソッドとは

after()メソッドで定期的に関数を実行できますが、途中でその定期実行をストップしたい場合もありますよね。

その場合はafter_cancel()メソッドを用いて定期実行のキャンセルを行うことができます。

構文

after_cancel(id)

引数で指定するidは、after()メソッドの返り値を指定します。

サンプルコード

デジタル時計プログラムの進行を止めるストップボタンを追加したプログラムを以下に記します。

import tkinter as tk
from tkinter import ttk
import time

def time_string():
    return time.strftime('%H:%M:%S')

def update():
    global id
    label.configure(text=time_string())
    id = label.after(1000, update)
def stop_time():
    label.after_cancel(id)

root = tk.Tk()
root.title("Digital Clock")
root.geometry("250x80")
root["bg"] = "black"

style = ttk.Style()
style.configure('TLabel', background='black', foreground='red')

label = ttk.Label(root, text=time_string(), font=('Digital-7', 40))
label.pack(expand=True)

button = ttk.Button(root, text='Stop', command=stop_time)
button.pack()

label.after(1000, update)

root.mainloop()

全コードと比べてボタンウィジェットが追加されました。
追加されたボタンをクリックするとstop_time()関数が実行されます。

ボタンウィジェットについては以下記事で詳しく解説しています。

stop_time()関数内でafter_cancel()メソッドを用いて、関数の実行をキャンセルしています。

まとめ

本記事「【Python tkinter】after()メソッド:関数を指定時間経過後(定期的)に実行する」はいかがでしたか。

after()メソッドは様々なアプリケーションで利用できる汎用性の高いメソッドです。

ぜひ使いこなしてGUIアプリケーション開発に応用してみてください。