下記ページで Tkinter のイベント処理について解説しました。
Tkinterの使い方:イベント処理を行うTkinter では bind
実行時に下記の形式のイベントシーケンス指定することで、「どのイベント」が発生した時にイベント処理を行うかを設定することが可能です。
"<[modifier-]event_type[-detail]>"
event_type
にはイベントの種類を記述しますが、どんなイベントがどんなタイミング(どんな操作をした時)に発生するかが具体的に分からないと何を設定すれば良いか分かりにくいですよね…。
そこで、今回は Tkinter で利用可能なイベントの種類(event_type
)や、そのイベントが発生するタイミング等を調べる方法について解説したいと思います。
確かにどんなイベントがどんなタイミングで発生するのかってイマイチ分かってないんだよね…
ネット上に情報も少ないし…
英語のサイトだと詳しく説明しているところもあるようだけどね…
ただ自力で簡単に調べることもできるので、今回はその方法を解説していくよ
利用可能なイベントを調べる
Tkinter で利用可能なイベントの種類は、tkinter.EventType
で列挙型(enum
)として定義されています。
enum
について詳しく知りたい方は別途調べていただくと良いと思いますが、要は下記により tkinter.EventType
で定義されているイベントの種類を全て表示することが可能です。
import tkinter
print(tkinter.EventType.__members__)
実行すると下記のような辞書形式で表示されると思います(表示結果の前半のみ載せています)。
{'KeyPress': <EventType.KeyPress: '2'>, 'Key': <EventType.KeyPress: '2'>, 'KeyRelease': <EventType.KeyRelease: '3'>, 'ButtonPress': <EventType.ButtonPress: '4'>, 'Button': <EventType.ButtonPress: '4'>, 'ButtonRelease': <EventType.ButtonRelease: '5'>, 'Motion': <EventType.Motion: '6'>,
基本的に、この辞書の各「キー名」が「イベントシーケンスの event_type
に指定可能な文字列」となります。
"<[modifier-]event_type[-detail]>"
またキー名は異なるのに、「値が同じ」ものもいくつか見られますね。
これらは異なるキー名でも、イベント処理を行うイベントの種類としては全く同じであることを示しています(どっちを指定しても良いということ)。
例えば上の表示例だと、KeyPress
と Key
、ButtonPress
と Button
は同じイベントの種類を表すことが確認できます。
ただし、理由は分からない(バージョン要因?OS要因?)のですが、表示されるキー名全てが bind
出来るわけではないようです。
したがって、下記のように tkinter.EventType
で定義されるキー名全てに対して bind
に成功するかどうかを確認し、成功した場合のみキー名を表示するようにしてやれば、実際に利用可能なイベントを調べることが可能です。
import tkinter
def event_handler(event):
pass
app = tkinter.Tk()
for event_type in tkinter.EventType.__members__.keys():
event_seq= "<" + event_type + ">"
try:
app.bind_all(event_seq, event_handler)
print(event_type)
except tkinter.TclError:
#print("bind error:", event_type)
pass
app.mainloop()
実行すると下記のように bind
可能なイベントの種類が表示されるはずです)。
KeyPress Key KeyRelease ButtonPress Button ButtonRelease Motion Enter Leave FocusIn FocusOut
ここでは表示結果の前半のみを載せています。全て知りたい方は是非自身でスクリプトを実行して調べてみてください!
この表示されるイベント名が、利用可能なイベントシーケンスの event_type
全てになります。
スクリプトの except
の print
部分のコメントアウトを外せば、どの種類のイベントが bind
に失敗しているかも確認することもできます。
イベントの発生タイミングを調べる
利用可能なイベントを調べるで紹介したスクリプトでは、下記を利用可能な全イベント種類に対して行っています。
app.bind_all(event_seq, event_handler)
したがって、下記ページで解説したように「アプリ内の全ウィジェット」に対して「全イベント」が発生した際に event_handler
が実行されることになります。
また、イベントハンドラの引数は tkinter.Event
クラスのインスタンスであり、type
プロパティにはイベントハンドラを実行する引き金になったイベントの種類が格納されています(この辺りも上記ページで解説しています)。
なので、event_handler
の中で引数の type
プロパティを表示するようにしてやれば、イベントが発生した時にどの種類のイベントが発生したかが表示されるようになります。
これにより、アプリに対してどんな操作をすれば、どの種類のイベントが発生するかを確認することができ、各イベントの発生タイミングを調べることが可能です。
ここまでの解説を踏まえ、イベントの発生タイミングを調べるスクリプトは下記のようになります。
# -*- coding:utf-8 -*-
import tkinter
# イベントハンドラ
def event_handler(event):
print(event.type)
app = tkinter.Tk()
app.title("イベント")
# 利用可能なイベントを全てbind
for event_type in tkinter.EventType.__members__.keys():
event_seq= "<" + event_type + ">"
try:
app.bind_all(event_seq, event_handler)
#print(event_type)
except tkinter.TclError:
#print("bind error:", event_type)
pass
# メインループ
app.mainloop()
実行するとアプリが起動し、アプリ起動時に発生するイベントの種類(Expose
・Map
・Visibility
・Activate
など)が表示されると思います。
さらに、アプリ上でマウスを動かす、マウスボタンをクリックする、ウィンドウサイズを変更する、キーボードのキーを押す、などを行えば、それぞれに対応したイベントの種類が表示される(Motion
・ButtonPress
・ButtonRelease
・Configure
・Expose
・KeyPress
・KeyRelease
など)と思います(特に Motion
に関しては大量に表示されると思います。)。
こんな感じで、アプリに対して操作をした時に、発生したイベントの種類が表示されるので、イベントの発生タイミングを調べることが可能です。
大量にイベントの種類が表示されるのが嫌であれば、直前に発生したイベントの種類と異なる場合のみ表示するようなことも可能です。
# イベントハンドラ
pre_event = {}
def event_handler(event):
global pre_event
now_event = {}
now_event['type'] = event.type
if now_event != pre_event:
print(event.type)
pre_event['type'] = event.type
スポンサーリンク
イベントの詳細を調べる
イベントの発生タイミングを調べるで紹介したスクリプトではイベントの発生タイミングを表示するだけでしたが、イベントハンドラの引数 event
のプロパティを表示することで、発生したイベントの詳細を調べることも可能です。
例えば下記スクリプトでは、どのウィジェットに対するイベントが発生したかを widget
を、どのキーが押されたかを keysym
をそれぞれ表示することで確認できるようにしています。
# -*- coding:utf-8 -*-
import tkinter
# イベントハンドラ
pre_event = {}
def event_handler(event):
global pre_event
now_event = {}
now_event["type"] = event.type
now_event["widget"] = event.widget
now_event["keysym"] = event.keysym
# 前回と異なるイベントの場合のみ表示
if now_event != pre_event:
print(
"type:" + str(event.type),
"widget" + str(event.widget),
"keysym:" + event.keysym,
)
pre_event["type"] = event.type
pre_event["widget"] = event.widget
pre_event["keysym"] = event.keysym
app = tkinter.Tk()
app.geometry("620x550")
app.title("イベント")
# まずはてきとうにウィジェットを配置
button = tkinter.Button(
app,
width=10,
height=2,
text="ボタン",
)
button.pack()
canvas = tkinter.Canvas(
app,
width=100,
height=100,
bg="red"
)
canvas.pack()
label = tkinter.Label(
app,
width=10,
height=2,
text="ラベル"
)
label.pack()
# 利用可能なイベントを全てbind
for event_type in tkinter.EventType.__members__.keys():
event_seq= "<" + event_type + ">"
try:
app.bind_all(event_seq, event_handler)
#print(event_type)
except tkinter.TclError:
#print("bind error:", event_type)
pass
# メインループ
app.mainloop()
実行すると下のアニメーションのように、アプリに対して操作した時などに発生したイベントの種類(type
)、どのウィジェットに対するイベントか(widget
)、どのキーが押されたかの情報(keysym
)が表示されます。
widget
に関してはウィジェットのインスタンス名ではなく、下記のような形式で表示されるので注意してください(複数同じ種類のウィジェットを作成した場合は最後に数字が付加される)。
!ウィジェットの種類名
また keysym
に関してはキーボードに無関係のイベントでは ??
で表示されます。
今回は widget
と keysym
のみを表示していますが、他にも tkinter.Event
のプロパティを表示することで他の情報を確認することも可能です。
プロパティにどんなものがあるかは下記ページで紹介していますので、興味のある方はこちらもご確認ください。
Tkinterの使い方:イベント処理を行うまた、上記のようなスクリプトでイベントの詳細を調べることで、イベントシーケンスにどのような指定を行えば良いかを理解することもできます。
イベントシーケンスの detail
について考えてみましょう。
"<[modifier-]event_type[-detail]>"
この detail
には keysym
を指定してやることで、その keysym
に対応するキーの Press や Release に対するイベント処理を行うことができるようになります。
なので、イベント処理を行いたいキーに対してどうdetail
を指定すれば良いか分からない時は、ひとまず全イベントに対してイベント処理を設定し、イベントハンドラで keysym
を表示することで 、detail
に指定すべき文字列を調べることが可能です。
例えば MacOS で「Command キー」が押された時に keysym
を表示すると “Meta_L” を表示されますので、「Command キー」が押された時のイベント処理を設定するには下記のようにイベントシーケンスを設定すれば良いことになります。
"<KeyPress-Meta_L>"
こんな感じでイベントシーケンスの設定に困った時にも、イベント処理をとりあえず行い、event
のプロパティを表示したりすることで何を設定すれば良いかを調べることができます。
まとめ
このページでは Tkinter で利用可能なイベントの種類や各イベントの発生タイミング・さらにはイベントの詳細を自力で調べる方法について解説しました。
Tkinter のドキュメントはネット上にも少なかったりもしますが、こんな感じで自力で調べてしまえばドキュメントなしでも自力で知識を身につけ、自由自在に GUI アプリを開発していくこともできます!
是非今回紹介した方法やスクリプトを活用して Tkinter のイベントについて調べてみてください!