2017年4月12日水曜日

Tkinter でGUI音遊びソフト作り(3) - バインドとループ

Tkinter で「ドラッグ可能図形」と「周期的に動く図形」を作っていきます。


1. バインディング

まずはドラッグ可能図形を作ります。そのためにはTkinterのバインディングというものを勉強しなければなりませんでした。バインディングとは、簡単にいえばあるイベントに対してある関数を紐づけることだといえます。次のようなメソッド*1で表します。
c0.tag_bind(id, 'event', function)
ここで、c0はバインドしたい図形を描いたキャンバス、idはバインドしたい図形のIDです。idの部分には「タグ」という図形の識別コードも使えます(後述)。eventにはいくつか種類があり、一定の文字列を入力することで様々なイベントと対応させてくれます。例えば
  • <Button-1>:左クリックしたとき
  • <Button1-Motion>:左クリックしながらドラッグしたとき
  • <ButtonRelease-1>:左クリックして離したとき
に、第3引数の関数あるいはメソッドを実行するよう設定できます。今回はドラッグしたら動く図形を作りたいので以下のようにします。
c0.tag_bind(id, '<Button1-Motion>', move)
move という関数は以下のように書きます。
def move(event):
    x = event.x
    y = event.y
    if x > 0 and x < 300 and y > 0 and y < 280:
        c0.coords('current', x - 10,y - 10,x + 10,y + 10)
正確にはわかっていませんが、バインド時は引数に自動で各種変数を持つeventが入るようです。上記のようにすることで、x、yにイベント発生時のマウスポインタの位置が代入できます。if文と300や280などの数値はキャンバスサイズです。これはなくてもよいのですが、あるとキャンバスの大きさを越えた範囲での図形の移動が制限できます。if文内では、マウスポインタの位置に図形を再描画しています。再描画はcoords()メソッドで行います。今回は円を動かしているので、円を内接する四角形の頂点の座標を左上x、左上y、右下x、右下yの順番で入れればいいですね。半径10の円の場合はこのようになります。
ここで、再描画する図形ですが、idでもいいのですがタグを使って指定しています。タグはいつでも自由につけられる図形の名前のようなもので、複数の図形を一気に操作したいときなどに便利です。'current'タグは Tkinter の定める特殊なタグで、マウスポインタのある位置の図形につくタグです。
マウスポインタについていく関数を図形にバインディングすることで、ドラッグ可能な図形を作ることができました。

2. ループ

次に、周期的に動く図形を作ります。さきほど、coords()というメソッドが登場しましたが、基本的に図形が動くときはこのcoords()を用います。今回はある円周軌道上を回る図形を作りたいので、三角関数で位置を計算して再描画を行えばいいですね。Tkinterでは、ループはafter()メソッドで作ります
root.after(10, func)
rootの部分には前回の記事で tk.Tk() をして開いたときに代入した任意の変数名が入ります。前回はhogeにしてたっけな……。第一引数には何msごとに実行するか、第二引数にはどの関数を実行するかを入れます。
def draw_orbit():
    x = 150 + r[i] * math.sin(math.radians(deg))
    y = 140 - r[i] * math.cos(math.radians(deg))
    c0.coords(id, x - 10, y - 10, x + 10, y + 10)
    if deg > 359:
        deg = 0
    else:
        deg += 3.6 / rate
        deg = round(deg, 1)
    
def show_orbit():
    draw_orbit()
    root.after(10, show_orbit)
こんな感じで書いて、main関数内でshow_orbit()関数を実行すればとりあえず動きました(実際にはもっと進んだコードからいろいろ消してるだけなのでこれをコピペして動くかはわかりませんが)。

以上でTkinter でGUI音遊びソフト作り(1)に貼った動画のような画面を作るやり方は終わりです。意外と簡単なのでびっくりしました。次は音をどのように出すかを考えます。楽器作りでは Raspberry Pi 標準ソフトの Sonic Pi に音出しを頼っていましたが、今回はこの Orbit 単体で音を出したいので、Python 上で音を出すやり方を模索します(ググる)。

*1:前回までの記事でメソッドと関数の混同が見られます。まだ完全には理解できていませんが以降なるべく正しく使おうと思います。

0 件のコメント:

コメントを投稿