受講生(U氏)からのお題を通してtkinterのButtonに関する知識を深めよう。
仕様
○10個の宝箱が表示されている。(どれか一つが当たり)
○画像をクリックすると当たりとハズレによって画像が切り替わりそれと同時に画面上部のメッセージも変わる。
画面上部のメッセージは最初。
[宝探しゲーム!箱の中身はなんだろうな?]
外れたとき
[はずれ!別の宝箱を開けてみよう]
当たったとき
[あたり!おめでとう!]
と表示する
ポイント
10個のボタンをどのように作成するか?そして当たりとハズレの宝箱をどのように設定するか?その当たりがコーディングのポイントとなる
準備
○まずは任意の場所(デスクトップなど)に今回のアプリ用のtreasureフォルダを作成する。
○次に以下の画像素材をダウンロード&解凍して4枚の画像treasureフォルダの直下に配置する
作成
では順番に作成していこう。treasureフォルダ内にtreasure.pyを作成し以下のようにコーディングする。
import tkinter as tk
import random
root=tk.Tk()
cvs=tk.Canvas(width=900,height=600)
cvs.pack()
bg=tk.PhotoImage(file='bg.png')
cvs.create_image(450,300,image=bg)
msg=tk.Label(
text='宝探しゲーム!箱の中身はなんだろうな?',
bg='red',
fg='white'
)
msg.place(x=50,y=30)
root.mainloop()
画像の大きさに合わせてキャンバスを作成し、画像を描画している。
ラベルを作成し、placeで画面左上に配置している。
ボタンの配置
いよいよボタンを配置していこう。以下のように追記する
import tkinter as tk
import random
def bt_click(e):
pass
root=tk.Tk()
cvs=tk.Canvas(width=900,height=600)
cvs.pack()
bg=tk.PhotoImage(file='bg.png')
cvs.create_image(450,300,image=bg)
msg=tk.Label(
text='宝探しゲーム!箱の中身はなんだろうな?',
bg='red',
fg='white'
)
msg.place(x=50,y=30)
t_images=[None]*3
for i in range(len(t_images)):
t_images[i]=tk.PhotoImage(file='tre'+str(i)+'.png')
lucky=random.randint(0,9)
buttons=[None]*10
for i in range(10):
b_name='hit' if lucky == i else str(i)
buttons[i]=tk.Button(image=t_images[0],name=b_name)
buttons[i].place(y=263,x=100+i*70)
buttons[i].bind('<ButtonPress>',bt_click)
root.mainloop()
10個のボタンをループで作成して、リストに詰めている。
その際にボタンそれぞれにname属性で別々の名前を設定している。
ボタンプレスイベントにbt_clickを登録したのでボタンを押した際にbt_clickが動くことになる。
ここまでで以下のように表示されれば成功だ。
押したときの挙動の作成
それでは実際に押したときの挙動を作成していこう。以下のように追記する。
(もともとあったpassを消す。)
import tkinter as tk
import random
def bt_click(e):
if 'hit' in str(e.widget):
e.widget['image']=t_images[2]
msg['text']='あたり!おめでとう!'
else:
e.widget['image']=t_images[1]
#e.widget.destroy()
msg['text']='はずれ!別の宝箱を開けてみよう'
root=tk.Tk()
cvs=tk.Canvas(width=900,height=600)
cvs.pack()
bg=tk.PhotoImage(file='bg.png')
cvs.create_image(450,300,image=bg)
msg=tk.Label(
text='宝探しゲーム!箱の中身はなんだろうな?',
bg='red',
fg='white'
)
msg.place(x=50,y=30)
t_images=[None]*3
for i in range(len(t_images)):
t_images[i]=tk.PhotoImage(file='tre'+str(i)+'.png')
lucky=random.randint(0,9)
buttons=[None]*10
for i in range(10):
b_name='hit' if lucky == i else str(i)
buttons[i]=tk.Button(image=t_images[0],name=b_name)
buttons[i].place(y=263,x=100+i*70)
buttons[i].bind('<ButtonPress>',bt_click)
root.mainloop()
bindで関数を登録したので引数を設定するとその発生したイベント情報を取得できる。
def bt_click(e):
e.widgetとするとクリックされたウィジッドの情報を参照できる。
今回str(e.widget)とすると.hitや.1のようにname属性を取得できるのでこの情報からどのボタンを押されたのかを識別すればよさそうだ。
if 'hit' in str(e.widget):
文字列にhitが含まれているかどうかは
‘hit’ in 文字列
判定することができる。こうすることで10個あるボタンのうち当たりの箱を選択したときだけ背景画像を当たり画像にすることができる。
クロージャ
参考までにクロージャという仕組みを使っても同じことを実装できる
import tkinter as tk
import random
def outer(button,i,lucky):
def inner():
if i==lucky:
button['image']=t_images[2]
else:
button['image']=t_images[1]
return inner
root=tk.Tk()
cvs=tk.Canvas(width=900,height=600)
cvs.pack()
bg=tk.PhotoImage(file='bg.png')
cvs.create_image(450,300,image=bg)
t_images=[None]*3
for i in range(len(t_images)):
t_images[i]=tk.PhotoImage(file='tre'+str(i)+'.png')
lucky=random.randint(0,9)
buttons=[None]*10
for i in range(10):
buttons[i]=tk.Button(image=t_images[0])
buttons[i].place(y=263,x=100+i*70)
func=outer(buttons[i],i,lucky)
buttons[i].config(command=func)
tk.mainloop()
クロージャの解説はこのサイトがとても丁寧に解説してくれている。参考にしてみるとよいだろう。
完成
今回は複数のボタンの設置とボタン画像の変更。ボタンに対するイベント登録などの理解が深まった。
コメント