tkinterでリアルタイム処理を実装する

after()でリアルタイム処理を行う

Pythonのリアルタイム処理はafter()を使う。下記コードはウィンドウのラベルに秒数が刻々と表示される。

import tkinter as tk

tmr = 0 # 経過時間を記録する変数
def counter():
    global tmr # 関数内の変数tmrをグローバル変数のtmrとして扱う宣言
    tmr = tmr + 1
    label["text"] = tmr
    root.after(1000, counter) # 1秒毎にcounter()を実行

root = tk.Tk()
root.title("リアルタイム処理で秒数をカウント")
root.geometry("400x300")
label = tk.Label(font=("Ubunt Mono", 160))
label.pack()
counter() # 最初のcounter()を実行しリアルタイム処理を始める
root.mainloop()

15行目でリアルタイム処理を実行するループ用関数counter()を呼び出す。counter()内でafter()を呼び出している。第一引数に待機時間、第二引数に実行する処理。待機時間はミリセコンド秒(1秒の1000分の1)で指定。上記コードでは1000ミリセコンド、つまり1秒後にcounter()即ち自分自身を呼び出す。

[書式]
after(ミリセコンド秒, 実行する関数名)

プログラムが終了するまで延々秒数をカウントし続ける。

 

キー入力

Pythonでイベントを受け取るにはbind()を使う。下記コードはキーイベントを取得し、ラベルにキーに割り当てられた値を表示している。

import tkinter as tk

key = 0
def key_down(e):
    global key
    key = e.keycode # 引数eはイベント情報が格納されており、keycodeから押されたキー情報を取得、代入
    label["text"] = "押したキー:" + str(key) # ラベルに押されたキーの値を書き込む

root = tk.Tk()
root.title("tkinterで入力を取得")
root.geometry("400x300")
label = tk.Label(font=("Ubunt Mono", 24))
label.pack()
root.bind("<KeyPress>", key_down) # 第一引数に<KeyPress>を指定し、キーが押下時のハンドラを登録
root.mainloop()

15行目でbind()でイベントを設定している。第一引数にイベントの種類、第二引数にイベントハンドラを登録。

関数key_down()の引数eはイベント情報が格納されている。名前は必ずしもeである必要はないが、大抵はeまたはevent。変数eから.keycodeでキー情報を取得可能。

[書式]
bind("<イベント>", イベント発生時に実行する関数)
代表的なイベント 内容
<KeyPress>あるいは<Key> キーダウン
<KeyRelease> キーアップ
<Motion> マウスポインターの移動
<ButtonPress>あるいは<Button> マウスボタンのクリック
<Button-1> マウスの左ボタンのクリック
<Button-2> マウスの中央ボタンのクリック
<Button-3> マウスの右ボタンのクリック

実行しキーを押した結果。

 

キャラクターをキー入力で動かしてみる

クライアント領域に画像を表示し、方向キーで上下左右に動かす。

import tkinter as tk

key = ""
def key_down(e):
    global key
    key = e.keysym # 引数eはイベント情報が格納されており、keysymから押されたキー情報を取得、代入

def key_up(e): # キーが離された時点でキー情報をリセットする
    global key
    key = ""

cx = 200 # 自機のX座標
cy = 200 # 自機のY座標
def main_proc(): # リアルタイム処理を実行する関数
    global cx, cy
    if key == "Left":
        cx = cx - 20
    if key == "Right":
        cx = cx + 20
    if key == "Up":
        cy = cy -20
    if key == "Down":
        cy = cy + 20
    canvas.coords("MYCHR", cx, cy) # 自機画像の描画位置を移動
    root.after(100, main_proc) # 100ミリセコンド後、もう一時自分自身を呼び出す

root = tk.Tk()
root.title("tkinterでキャラクター移動")
root.bind("<KeyPress>", key_down)
root.bind("<KeyRelease>", key_up)
canvas = tk.Canvas(width=800, height=600)
canvas.pack()
img = tk.PhotoImage(file="drone_car.png") # 自機画像の読み込み
canvas.create_image(cx, cy, image=img, tag="MYCHR") # キャンバスに画像を描画
main_proc()
root.mainloop()

14行目のリアルタイム処理用関数main_proc()では、押された方向キーに応じてXもしくはY座標を20ピクセル増減。

画像を描画している34行目、それに対応する24行目で”MYCHR”というタグを指定。タグとはキャンバスに描画する図形や画像に指定でき、そのオブジェクトを示す一意の名前。タグは自由に名付け可能。

 

マウスイベントを受け取る

ウィンドウ上(クライアント領域)でマウス操作時のイベントを受け取る。下記コードはマウスの動き、ボタンクリックの有無を動的に判定する。

import tkinter as tk

mouse_x = 0
mouse_y = 0
mouse_c = "Off"

def mouse_move(e): # マウスが動いた時に実行
    global mouse_x, mouse_y
    mouse_x = e.x # 現在のマウスカーソルのX、Y座標に代入
    mouse_y = e.y

def mouse_press(e): # マウスボタンがクリックされた時に実行
    global mouse_c
    mouse_c = "On"

def mouse_release(e): # マウスボタンが離された時に実行
    global mouse_c
    mouse_c = "Off"

def mouse_proc(): # リアルタイム処理関数
    fnt = ("Ubuntu Mono", 20) # フォント情報を定義
    txt = "X座標{}, Y座標{}, クリック状態{}".format(mouse_x, mouse_y, mouse_c) # 表示する文字列を整形し代入
    canvas.delete("INFOTEXT") # 繰り返し処理の最初に文字列をクリア
    canvas.create_text(300, 30, text=txt, fill="black", font=fnt, tag="INFOTEXT") # キャンバスに文字列を描画
    root.after(100, mouse_proc)

root = tk.Tk()
root.title("tkinterでマウス入力を受け取る")
root.resizable(False, False)
root.bind("<Motion>", mouse_move) # マウスがクライアント領域上で動いた時に呼ぶ関数を指定
root.bind("<ButtonPress>", mouse_press) # マウスボタンがクリックされた時に呼ぶ関数を指定
root.bind("<ButtonRelease>", mouse_release) # 押されていたマウスボタンが離された時に呼ぶ関数を指定
canvas = tk.Canvas(root, width=600, height=400)
canvas.pack()
mouse_proc()
root.mainloop()

現在のマウスカーソルのX、Y座標をリアルタイムで表示・更新し続ける。ボタンクリック時はOn、離されるとOffと表示。画像にカーソルが映っていないがウィンドウ右下辺りに存在。

22行目の表示する文字列の整形では、左の{}に右のformat()の引数が並び順で置き換えられる。

[書式]
"{}, {}, ...".format(中身を表示したい変数, "指定したい文字列", ...)

コメント

タイトルとURLをコピーしました