受講生(F氏)からのお題。tkinterを使って英単語学習アプリを作成してみよう。
仕様
1.起動すると一問目が表示され、ユーザーは答えを入力します
2.入力後、[答える]ボタンを押すと次の問題と先程答えた問題の成否も表示します
3.10問目を答えると10問中いくつ正解したかが表示されます
ウィンドウサイズはwidth=400,height=500です。 画像が大きいと思いますが、
img = tk.PhotoImage(“ああああ.png”)
img = img.subsample(2)
のようにすると良い感じのサイズになると思います
実行例
起動時
「ぞう」の英単語を入力し、「答える」を押す
○結果が下部に表示され、次の問題が出題される。(入力欄は空になっている)
この結果の文字は1.5秒後に自動的に消える
○間違った答えを入力すると…
○下部に正しい答えが表示される(これも1.5秒後に自動的に消える)
○以下を問題数(10問)繰り返すと最後に結果が表示され最初に戻る
ポイント
適度な難易度なので学習素材として良問だ。10問の問題をどのように扱うかがポイントとなるだろう。表示の演出の細部はとりあえずは置いておいて基本的な流れが実装できるか試してみてもらいたい。
準備
○まずは任意の場所(デスクトップなど)に今回のアプリ用のanimalフォルダを作成する。
○次に以下の画像素材をダウンロード&解凍して10枚の画像animalフォルダの直下に配置する
animals.zip
レッツ チャレンジ!
ではやってみよう!基本的な流れを実装できるだろうか!?
解答例
import tkinter as tk
animal=None
index=0
correct=0
root=tk.Tk()
root.geometry('400x500')
class Animal:
def __init__(self,ja,en,img):
self.ja=ja
self.en=en
self.img=img
animals=[
Animal('ぞう','elephant',tk.PhotoImage(file='elephant.png').subsample(2)),
Animal('しろくま','polarbear',tk.PhotoImage(file='polarbear.png').subsample(2)),
Animal('くじら','whale',tk.PhotoImage(file='whale.png').subsample(2)),
Animal('ペンギン','penguin',tk.PhotoImage(file='penguin.png').subsample(2)),
Animal('ライオン','lion',tk.PhotoImage(file='lion.png').subsample(2)),
Animal('カンガルー','kangaroo',tk.PhotoImage(file='kangaroo.png').subsample(2)),
Animal('ひと','human',tk.PhotoImage(file='human.png').subsample(2)),
Animal('いぬ','dog',tk.PhotoImage(file='dog.png').subsample(2)),
Animal('ねこ','cat',tk.PhotoImage(file='cat.png').subsample(2)),
Animal('あり','ant',tk.PhotoImage(file='ant.png').subsample(2)),
]
def clear_result():
l_result['text']=''
def btn_click():
global animal,correct,index
user_ans=entry.get()
if user_ans.lower()==animal.en:
correct+=1
msg='正解!'
else:
msg=f'不正解{animal.ja}の答えは{animal.en}'
if index==len(animals)-1:
msg+=f'\n{len(animals)}中{correct}問正解でした!'
index=-1
correct=0
l_result['text']=msg
root.after(1500,clear_result)
index+=1
animal=animals[index]
l_ja['text']=animal.ja
cvs.delete('ANI')
cvs.create_image(100,100,image=animal.img,tag="ANI")
entry.delete(0,tk.END)
fnt=('Arial',30)
animal=animals[index]
l_ja=tk.Label(text=animal.ja,font=fnt)
l_ja.pack(pady=(20,10))
entry=tk.Entry(font=('Arial',20))
entry.pack()
cvs=tk.Canvas(width=200,height=200)
cvs.pack(pady=20)
cvs.create_image(100,100,image=animal.img,tag="ANI")
btn=tk.Button(text='答える',font=fnt,command=btn_click)
btn.pack()
l_result=tk.Label(text='',font=('Arial',16))
l_result.pack(pady=(10,0))
root.mainloop()
ポイント解説
○今回はAnimalクラスを作成して、和名と英名と画像を管理した。
○root.after(1500,処理)を使って1.5秒後に文字を消している
別解
クラスにメソッドも持たせた例。ソースコードも長くなっているし、それほど見通しが改善してるわけでもないので微妙だが、クラスの練習としては有りだろう。
import tkinter as tk
animal=None
index=0
correct=0
root=tk.Tk()
root.geometry('400x500')
class Animal:
def __init__(self,ja,en,img):
self.ja=ja
self.en=en
self.img=img
def show_quiz(self):
l_ja['text']=animal.ja
cvs.delete('ANI')
cvs.create_image(100,100,image=self.img,tag="ANI")
animals=[
Animal('ぞう','elephant',tk.PhotoImage(file='elephant.png').subsample(2)),
Animal('しろくま','polarbear',tk.PhotoImage(file='polarbear.png').subsample(2)),
Animal('くじら','whale',tk.PhotoImage(file='whale.png').subsample(2)),
Animal('ペンギン','penguin',tk.PhotoImage(file='penguin.png').subsample(2)),
Animal('ライオン','lion',tk.PhotoImage(file='lion.png').subsample(2)),
Animal('カンガルー','kangaroo',tk.PhotoImage(file='kangaroo.png').subsample(2)),
Animal('ひと','human',tk.PhotoImage(file='human.png').subsample(2)),
Animal('いぬ','dog',tk.PhotoImage(file='dog.png').subsample(2)),
Animal('ねこ','cat',tk.PhotoImage(file='cat.png').subsample(2)),
Animal('あり','ant',tk.PhotoImage(file='ant.png').subsample(2)),
]
def clear_result():
l_result['text']=''
def init_quiz():
global animal,correct,index
index=0
correct=0
clear_result()
animal=animals[index]
animal.show_quiz()
def btn_click():
global animal,correct,index
is_last=index==len(animals)-1
user_ans=entry.get()
if user_ans.lower()==animal.en:
correct+=1
msg='正解!'
else:
msg=f'不正解{animal.ja}の答えは{animal.en}'
if is_last:
msg+=f'\n{len(animals)}中{correct}問正解でした!'
l_result['text']=msg
entry.delete(0,tk.END)
if is_last:
root.after(1500,init_quiz)
else:
root.after(1500,clear_result)
index+=1
animal=animals[index]
animal.show_quiz()
fnt=('Arial',30)
l_ja=tk.Label(font=fnt)
l_ja.pack(pady=(20,10))
entry=tk.Entry(font=('Arial',20))
entry.pack()
cvs=tk.Canvas(width=200,height=200)
cvs.pack(pady=20)
btn=tk.Button(text='答える',font=fnt,command=btn_click)
btn.pack()
l_result=tk.Label(text='',font=('Arial',16))
l_result.pack(pady=(10,0))
init_quiz()
root.mainloop()
完成
イラストの可愛さもあって楽しいアプリだ。作っている最中に登場する動物の英単語は完璧に覚えられた。Pythonでできたら他の言語でもやってみるとよいだろう。
発展
ボタン操作に加えてスペースキーでも次の問題が表示されるように変更。
詳細なコメントも付け加えているので参考にしてもらいたい。
import tkinter as tk
#今着目しているAnimalインスタンス
animal=None
#animalsリストのindex
index=0
#正解数
correct=0
root=tk.Tk()
root.geometry('400x500')
#Animalクラス
class Animal:
def __init__(self,ja,en,img):
self.ja=ja
self.en=en
self.img=img
#animalsリスト(subsample(整数)は画像を1/整数に縮小zoomは拡大)
animals=[
Animal('ぞう','elephant',tk.PhotoImage(file='elephant.png').subsample(2)),
Animal('しろくま','polarbear',tk.PhotoImage(file='polarbear.png').subsample(2)),
Animal('くじら','whale',tk.PhotoImage(file='whale.png').subsample(2)),
Animal('ペンギン','penguin',tk.PhotoImage(file='penguin.png').subsample(2)),
Animal('ライオン','lion',tk.PhotoImage(file='lion.png').subsample(2)),
Animal('カンガルー','kangaroo',tk.PhotoImage(file='kangaroo.png').subsample(2)),
Animal('ひと','human',tk.PhotoImage(file='human.png').subsample(2)),
Animal('いぬ','dog',tk.PhotoImage(file='dog.png').subsample(2)),
Animal('ねこ','cat',tk.PhotoImage(file='cat.png').subsample(2)),
Animal('あり','ant',tk.PhotoImage(file='ant.png').subsample(2)),
]
#結果表示を消す関数
def clear_result():
l_result['text']=''
#ボタンを押したときの処理
def btn_click(e=None):
global animal,correct,index
#入力欄に入っている値を取得
user_ans=entry.get().strip()
#答えが正しかったら
if user_ans.lower()==animal.en:
correct+=1
msg='正解!'
else:
msg=f'不正解{animal.ja}の答えは{animal.en}'
#最後の問題だったら
if index==len(animals)-1:
#結果表示
msg+=f'\n{len(animals)}中{correct}問正解でした!'
index = -1
correct=0
#ラベルにメッセージを表示
l_result['text']=msg
#1500m秒後にclear_resultを実行
root.after(1500,clear_result)
index+=1
#リストから次のanimalインスタンスを取り出す
animal=animals[index]
#問題文表示
l_ja['text']=animal.ja
#古い画像を削除
cvs.delete('ANI')
#新しい画像を表示
cvs.create_image(100,100,image=animal.img,tag="ANI")
#入力欄を空にする
entry.delete(0,tk.END)
fnt=('Arial',30)
#リストから動物を取り出す
animal=animals[index]
#問題表示
l_ja=tk.Label(text=animal.ja,font=fnt)
#ラベルを画面に配置(上が20下が10のpadding)
l_ja.pack(pady=(20,10))
#入力フォームの作成
entry=tk.Entry(font=('Arial',20))
#入力フォームを配置
entry.pack()
#キャンバスの作成
cvs=tk.Canvas(width=200,height=200)
#キャンバスの配置
cvs.pack(pady=20)
#画像の作成
cvs.create_image(100,100,image=animal.img,tag="ANI")
#ボタンの作成
btn=tk.Button(text='答える',font=fnt,command=btn_click)
#ボタンの配置
btn.pack()
root.bind("<space>",btn_click)
#結果表示ラベルの作成
l_result=tk.Label(text='',font=('Arial',16))
#結果表示ラベルの配置
l_result.pack(pady=(10,0))
#tkinterアプリを動かすときのおきまり
root.mainloop()
コメント