KURORO BLOGのロゴ

このエントリーをはてなブックマークに追加
Tkinterで使われるafterとは?活用方法から注意点まで徹底解説!?

Tkinterで使われるafterとは?活用方法から注意点まで徹底解説!?

今回はTkinterで使われるafterに関して、活用方法から注意点まで徹底解説いたします。afterを使ってみたい、afterに関して詳しくなりたい方へおすすめです。是非最後までご一読ください。

目次
  1. そもそもTkinterで使われるafterとは?
  2. after関数の定義
  3. after関数で実行されるのは、特定の関数を実行する予約
  4. 特定の関数を定期実行する方法
  5. after_cancel関数を利用して、IDに紐づくafter関数の設定情報を削除
  6. after関数とtime.sleep()の違い
  7. after関数を利用する際の2つの注意点
    1. after関数を使いすぎると負荷が高くなる
    2. 指定する時間に関数が実行されるとは限らない
  8. まとめ
  9. 参考文献
目次を開く⬇︎

そもそもTkinterで使われるafterとは?

Tkinterで使われるafterとは、特定の関数を設定する時間分遅らせて実行したり、特定の関数を定期実行するために使われるものを意味します。

別名でafter関数と呼ばれます。Tkinterを活用する上でとても大切な関数になります。

after関数の定義

after関数は

1# ms : どのくらい遅らせてfuncを実行するのかを時間設定する(単位はミリ秒)
2# func : ms経過後に実行する関数
3# args(任意) : funcに渡す引数
4# 戻り値 : ID(after関数の設定情報に紐づくID)
5.after(ms, func, args)

で定義されます。戻り値としてIDが返却されます。IDafter関数の設定情報に紐づくIDを表し、IDに紐づくafter関数の設定情報を削除する場合などに利用されます。

またafter関数は、全てのWidgetに対応可能です。

Widgetに関しては、【初学者必見!?】Tkinterで使われるlabelの活用方法を徹底解説の「Tkinterの構成要素」でまとめていますので、是非ご確認ください。

例えば、以下のようなコードを作成すると

1import tkinter as tk
2
3class Application(tk.Frame):
4    # hello worldを出力する関数
5    # keyword : dict型
6    def getHelloWorld(self, keyword):
7        print(keyword['text'])
8
9    # after関数に関するサンプル関数
10    def getAfterSample(self):
11        # 5000ms後にself.getHelloWorld関数を実行
12        # 第一引数 : どのくらい遅らせて第二引数を実行するのかを時間設定する(単位はミリ秒)。
13        # 第二引数 : 第一引数経過後に実行する関数。self.getHelloWorldとする。
14        # 第三引数(任意) : 関数実行時に渡される引数
15        # 戻り値 : ID(after関数の設定情報に紐づくID)
16        return self.master.after(5000, self.getHelloWorld, {
17            "text" : "hello world",
18        })
19
20    def __init__(self, master=None):
21        # Windowの初期設定を行う。
22        super().__init__(master)
23        # Windowの画面サイズを設定する。
24        # geometryについて : https://kuroro.blog/python/rozH3S2CYE0a0nB3s2QL/
25        self.master.geometry("300x200+120+0")
26        self.getAfterSample()
27
28# Tkinter初学者参考 : https://docs.python.org/ja/3/library/tkinter.html#a-simple-hello-world-program
29if __name__ == "__main__":
30    # Windowを生成する。
31    # Windowについて : https://kuroro.blog/python/116yLvTkzH2AUJj8FHLx/
32    root = tk.Tk()
33    app = Application(master=root)
34    # Windowをループさせて、継続的にWindow表示させる。
35    # mainloopについて : https://kuroro.blog/python/DmJdUb50oAhmBteRa4fi/
36    app.mainloop()

以下の画像のように、特定の関数を設定する時間分遅らせて実行(5秒間待つと、hello worldが表示)できます。

after関数で実行されるのは、特定の関数を実行する予約

見出しにも書いた通り、after関数で実行されるのは、特定の関数を実行する予約です。

つまりafter関数を実行するだけでは、特定の関数は実行されません。

特定の関数を実行するためには、mainloop関数が必要になります。

例えば「after関数の定義」で紹介したコード内の、mainloop関数部分をコメントアウトすると、

1import tkinter as tk
2
3class Application(tk.Frame):
4    # hello worldを出力する関数
5    # keyword : dict型
6    def getHelloWorld(self, keyword):
7        print(keyword['text'])
8
9    # after関数に関するサンプル関数
10    def getAfterSample(self):
11        # 5000ms後にself.getHelloWorld関数を実行
12        # 第一引数 : どのくらい遅らせて第二引数を実行するのかを時間設定する(単位はミリ秒)。
13        # 第二引数 : 第一引数経過後に実行する関数。self.getHelloWorldとする。
14        # 第三引数(任意) : 関数実行時に渡される引数
15        # 戻り値 : ID(after関数の設定情報に紐づくID)
16        return self.master.after(5000, self.getHelloWorld, {
17            "text" : "hello world",
18        })
19
20    def __init__(self, master=None):
21        # Windowの初期設定を行う。
22        super().__init__(master)
23        # Windowの画面サイズを設定する。
24        # geometryについて : https://kuroro.blog/python/rozH3S2CYE0a0nB3s2QL/
25        self.master.geometry("300x200+120+0")
26        self.getAfterSample()
27
28# Tkinter初学者参考 : https://docs.python.org/ja/3/library/tkinter.html#a-simple-hello-world-program
29if __name__ == "__main__":
30    # Windowを生成する。
31    # Windowについて : https://kuroro.blog/python/116yLvTkzH2AUJj8FHLx/
32    root = tk.Tk()
33    app = Application(master=root)
34    # Windowをループさせて、継続的にWindow表示させる。
35    # mainloopについて : https://kuroro.blog/python/DmJdUb50oAhmBteRa4fi/
36    # コメントアウト
37    # app.mainloop()

以下の画像のように、Tkinterの画面は表示されず、hello worldを閲覧できなくなります。

mainloop関数に関して詳しく知りたい場合は、【図解付き!?】Tkinterで使われるmainloopをわかりやすく解説をご確認ください。

特定の関数を定期実行する方法

after関数では、特定の関数を設定する時間分遅らせて実行する以外に、特定の関数を定期実行することができます。

定期実行したい関数内でafter関数を宣言すると、

1# hello worldを出力する関数
2# keyword : dict型
3def getHelloWorld(self, keyword):
4    print(keyword['text'])
5    # 5000ms後にself.getHelloWorld関数を実行
6    # 第一引数 : どのくらい遅らせて第二引数を実行するのかを時間設定する(単位はミリ秒)。
7    # 第二引数 : 第一引数経過後に実行する関数。self.getHelloWorldとする。
8    # 第三引数(任意) : 関数実行時に渡される引数
9    # 戻り値 : ID(after関数の設定情報に紐づくID)
10    return self.master.after(5000, self.getHelloWorld, {
11        "text" : "hello world",
12    })

定期実行が可能になります。

例えば、以下のようなコードを作成すると

1import tkinter as tk
2
3class Application(tk.Frame):
4    # hello worldを出力する関数
5    # keyword : dict型
6    def getHelloWorld(self, keyword):
7        print(keyword['text'])
8        # 5000ms後にself.getHelloWorld関数を実行
9        # 第一引数 : どのくらい遅らせて第二引数を実行するのかを時間設定する(単位はミリ秒)。
10        # 第二引数 : 第一引数経過後に実行する関数。self.getHelloWorldとする。
11        # 第三引数(任意) : 関数実行時に渡される引数
12        # 戻り値 : ID(after関数の設定情報に紐づくID)
13        return self.master.after(5000, self.getHelloWorld, {
14            "text" : "hello world",
15        })
16
17    # after関数に関するサンプル関数
18    def getAfterSample(self):
19        # 5000ms後にself.getHelloWorld関数を実行
20        # 第一引数 : どのくらい遅らせて第二引数を実行するのかを時間設定する(単位はミリ秒)。
21        # 第二引数 : 第一引数経過後に実行する関数。self.getHelloWorldとする。
22        # 第三引数(任意) : 関数実行時に渡される引数
23        # 戻り値 : ID(after関数の設定情報に紐づくID)
24        return self.master.after(5000, self.getHelloWorld, {
25            "text" : "hello world",
26        })
27
28    def __init__(self, master=None):
29        # Windowの初期設定を行う。
30        super().__init__(master)
31        # Windowの画面サイズを設定する。
32        # geometryについて : https://kuroro.blog/python/rozH3S2CYE0a0nB3s2QL/
33        self.master.geometry("300x200+120+0")
34        self.getAfterSample()
35
36# Tkinter初学者参考 : https://docs.python.org/ja/3/library/tkinter.html#a-simple-hello-world-program
37if __name__ == "__main__":
38    # Windowを生成する。
39    # Windowについて : https://kuroro.blog/python/116yLvTkzH2AUJj8FHLx/
40    root = tk.Tk()
41    app = Application(master=root)
42    # Windowをループさせて、継続的にWindow表示させる。
43    # mainloopについて : https://kuroro.blog/python/DmJdUb50oAhmBteRa4fi/
44    app.mainloop()

以下の画像のように5秒ごとに、hello worldが表示されます。

after_cancel関数を利用して、IDに紐づくafter関数の設定情報を削除

after_cancel関数を利用すると、IDに紐づくafter関数の設定情報を削除できます。

after_cancel関数は

1# 第一引数 : ID(after関数の設定情報に紐づくID)
2# 戻り値 : なし
3.after_cancel(id)

で定義されます。戻り値はありません。

例えば、以下のようなコードを作成すると

1import tkinter as tk
2
3class Application(tk.Frame):
4    # hello worldを出力する関数
5    # keyword : dict型
6    def getHelloWorld(self, keyword):
7        print(keyword['text'])
8
9    # after関数に関するサンプル関数
10    def getAfterSample(self):
11        # 5000ms後にself.getHelloWorld関数を実行
12        # 第一引数 : どのくらい遅らせて第二引数を実行するのかを時間設定する(単位はミリ秒)。
13        # 第二引数 : 第一引数経過後に実行する関数。self.getHelloWorldとする。
14        # 第三引数(任意) : 関数実行時に渡される引数
15        # 戻り値 : ID(after関数の設定情報に紐づくID)
16        return self.master.after(5000, self.getHelloWorld, {
17            "text" : "hello world",
18        })
19
20    # after関数をキャンセルする関数
21    # id : ID(after関数の設定情報に紐づくID)
22    def removeAfterSample(self, id):
23        # 第一引数 : after関数の設定情報に紐づくID
24        self.master.after_cancel(id)
25
26    def __init__(self, master=None):
27        # Windowの初期設定を行う。
28        super().__init__(master)
29        # Windowの画面サイズを設定する。
30        # geometryについて : https://kuroro.blog/python/rozH3S2CYE0a0nB3s2QL/
31        self.master.geometry("300x200+120+0")
32
33        id = self.getAfterSample()
34        self.removeAfterSample(id)
35
36# Tkinter初学者参考 : https://docs.python.org/ja/3/library/tkinter.html#a-simple-hello-world-program
37if __name__ == "__main__":
38    # Windowを生成する。
39    # Windowについて : https://kuroro.blog/python/116yLvTkzH2AUJj8FHLx/
40    root = tk.Tk()
41    app = Application(master=root)
42    # Windowをループさせて、継続的にWindow表示させる。
43    # mainloopについて : https://kuroro.blog/python/DmJdUb50oAhmBteRa4fi/
44    app.mainloop()

以下の画像のように、IDに紐づくafter関数の設定情報が削除されて、何秒経過してもhello worldは表示されません。

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

after関数とtime.sleep()は時間を遅らせる観点でみると、とても似ています。しかしプログラムの扱いに関して、明確な違いが存在します。

after関数はプログラムを停止することなく、ボタンクリックなどを受け付けます。

反対にtime.sleep()はプログラムを停止して、ボタンクリックなどを受け付けません。

例えば、以下のようなコードを作成して、time.sleep(3)箇所をコメントアウトすると

1import tkinter as tk
2import time
3
4class Application(tk.Frame):
5    # helloを出力する関数
6    def getHello(self):
7        # コメントアウト
8        # time.sleep(3)
9        self.master.after(3000, self.getHello)
10        print('hello')
11
12    # time.sleepとafter関数を比較する関数
13    def confirmTimeVsAfter(self):
14        # Windowを親要素としてbutton Widgetを作成する。
15        # command : ボタンをクリックした場合に、実行する関数を設定。self.getHelloとする。
16        # text : テキスト情報
17        # Buttonについて : https://kuroro.blog/python/oFju6EngDtcYtIiMIDf1/
18        button = tk.Button(self.master, command=self.getHello, text='クリック')
19        # Windowを親要素として、button Widgetをどのように配置するのか?
20        # packについて : https://kuroro.blog/python/UuvLfIBIEaw98BzBZ3FJ/
21        button.pack()
22
23    def __init__(self, master=None):
24        # Windowの初期設定を行う。
25        super().__init__(master)
26        # Windowの画面サイズを設定する。
27        # geometryについて : https://kuroro.blog/python/rozH3S2CYE0a0nB3s2QL/
28        self.master.geometry("300x200+120+0")
29        self.confirmTimeVsAfter()
30
31# Tkinter初学者参考 : https://docs.python.org/ja/3/library/tkinter.html#a-simple-hello-world-program
32if __name__ == "__main__":
33    # Windowを生成する。
34    # Windowについて : https://kuroro.blog/python/116yLvTkzH2AUJj8FHLx/
35    root = tk.Tk()
36    app = Application(master=root)
37    # Windowをループさせて、継続的にWindow表示させる。
38    # mainloopについて : https://kuroro.blog/python/DmJdUb50oAhmBteRa4fi/
39    app.mainloop()

以下の画像のように、after関数が実行される間もボタンクリックでき、helloが表示されます。

反対にtime.sleep(3)箇所のコメントアウトを外して、self.master.after(3000, self.getHello)箇所をコメントアウトすると、

1# helloを出力する関数
2def getHello(self):
3-    # time.sleep(3)
4+    time.sleep(3)
5-    self.master.after(3000, self.getHello)
6+    # コメントアウト
7+    # self.master.after(3000, self.getHello)
8     print('hello')

以下の画像のように、time.sleep()が実行される間はボタンクリックできず一度にたくさんのhelloが表示されなくなります。

after関数を利用する際の2つの注意点

after関数を利用する上で2点注意すべきことがあります。

after関数を使いすぎると負荷が高くなる

after関数の設定時間が短かったり、after関数で設定する関数の処理が重い場合に、高い負荷がかかってしまい、円滑に処理されなくなる可能性があります。

高い負荷を与えないためにも、

  • after関数の設定時間を長めにとる
  • after関数で設定する関数の処理を軽くする

を意識して開発する必要があります。

指定する時間に関数が実行されるとは限らない

「after関数で実行されるのは、特定の関数を実行する予約」でも書きましたが、特定の関数を実行するのはmainloop関数になります。

mainloop関数は、その他の関数に対しても処理しなければならないので、負荷がかかっている場合には、after関数の実行が遅れる可能性があります。

多少のずれは起こる前提で、after関数を利用しましょう。

まとめ

  • Tkinterで使われるafterとは、特定の関数を設定する時間分遅らせて実行したり、特定の関数を定期実行するために使われるものを意味します。
  • 別名でafter関数と呼ばれます。
  • 特定の関数を実行するのはmainloop関数

参考文献