Edited at

【Python】Tkinterによる200行で作るGUIアプリ「英単語ソフト」


はじめに

こんにちは。

今回はPythonの勉強と英語の勉強を兼ねて、「英単語ソフト」を作ってみようと思います。

GUIで作成したいので、tkinterを使って実装していきます。



こちらが完成形になります。

仕様的には、カンマ区切りで書かれているテキストデータであるcsvファイルを読み込み、そこにある英単語をランダムで一つ表示し、4択の中からその意味を選んで、テキストボックスに入力し、判定を行うというものです。

正解なら、次の単語ボタンを押すことで、次の英単語がランダムで一つ表示されます。


環境


  • Windows 10 home

  • Python 3.7.1


英単語ソフトの制作


ウィンドウの作成

前回の記事の雛形を基本に作っていきます。


import tkinter as tk

class Application(tk.Frame):
def __init__(self,master):
super().__init__(master)
self.pack()

self.master.geometry("380x200")
self.master.title("英単語ソフト")

def main():
win = tk.Tk()
app = Application(master = win)
app.mainloop()

if __name__ == "__main__":

main()

まずこのプログラムでウィンドウを作っていきます。

ウィンドウサイズは380×200。

タイトルは英単語ソフトにしています。


csvファイルの読み込み


def WordInput(self):
f = open("word.csv","r",encoding = "utf-8-sig")

self.wordlist = list(csv.reader(f))

f.close()

word.csvを読み込みます。


部品の配置


def widget(self):

self.txt1 = tk.Entry(self.master, width = 33)
self.txt1.place(x = 50, y = 30)

self.txt1.insert(0,self.wordlist[self.num][0])

self.txt2 = tk.Entry(self.master, width = 33)
self.txt2.place(x = 50, y = 90)

self.BtnJudge = tk.Button(self.master, text = "判定", command = self.ClickJudge, width = 10)
self.BtnJudge.place(x = 110, y = 148)

self.BtnNext = tk.Button(self.master, text = "次の単語", command = self.Next, width = 10)
self.BtnNext.place(x = 215, y = 148)

self.select4()

テキストボックス、ボタン、4択を配置していきます。


4択の表示


def select4(self):

rdNum = rd.randint(0,3)
lbl_x = 280
lbl_y = 15

self.Rdlist()

for i in range(4):

if i == 0:
if i == rdNum:
self.lbl1 = tk.Label(self.master, text = str(i+1) + " . " + self.wordlist[self.num][1])
self.lbl1.place(x = lbl_x, y = lbl_y + i * 30)
else:
self.lbl1 = tk.Label(self.master, text = str(i+1) + " . " + self.wordlist[self.rdlist[i]][1])
self.lbl1.place(x = lbl_x, y = lbl_y + i * 30)

if i == 1:
if i == rdNum:
self.lbl2 = tk.Label(self.master, text = str(i+1) + " . " + self.wordlist[self.num][1])
self.lbl2.place(x = lbl_x, y = lbl_y + i * 30)
else:
self.lbl2 = tk.Label(self.master, text = str(i+1) + " . " + self.wordlist[self.rdlist[i]][1])
self.lbl2.place(x = lbl_x, y = lbl_y + i * 30)

if i == 2:
if i == rdNum:
self.lbl3 = tk.Label(self.master, text = str(i+1) + " . " + self.wordlist[self.num][1])
self.lbl3.place(x = lbl_x, y = lbl_y + i * 30)
else:
self.lbl3 = tk.Label(self.master, text = str(i+1) + " . " + self.wordlist[self.rdlist[i]][1])
self.lbl3.place(x = lbl_x, y = lbl_y + i * 30)

if i == 3:
if i == rdNum:
self.lbl4 = tk.Label(self.master, text = str(i+1) + " . " + self.wordlist[self.num][1])
self.lbl4.place(x = lbl_x, y = lbl_y + i * 30)
else:
self.lbl4 = tk.Label(self.master, text = str(i+1) + " . " + self.wordlist[self.rdlist[i]][1])
self.lbl4.place(x = lbl_x, y = lbl_y + i * 30)

def Rdlist(self):
self.rdlist = list(range(len(self.wordlist)))
rd.shuffle(self.rdlist)
self.rdlist.remove(self.wordlist.index(self.wordlist[self.num]))

def select4_destroy(self):
self.lbl1.destroy()
self.lbl2.destroy()
self.lbl3.destroy()
self.lbl4.destroy()

ここの部分が一番ややこしいところになります。

問題の英単語の正答の意味を4択の中に表示し、それ以外の意味は、読み込んだcsvファイルから正答以外の意味をランダムで3つ表示します。また、正答の意味の位置もランダムで決まります。


判定


def Judge(self):
if self.txt2.get() == self.wordlist[self.num][1]:
self.marupro()
else:
self.batsupro()

def ClickJudge(self):
self.Judge()

def EnterJudge(self, event):
self.Judge()

def marupro(self):
self.canvas.delete("batsu1")
self.canvas.delete("batsu2")
self.judgeNum = 1
#print("正解")
self.canvas.create_oval(10,10,43,43,outline = "red", width = 5, tag = "maru")

def batsupro(self):
#print("不正解")
self.canvas.create_line(10,10,43,43,fill = "black", width = 5, tag = "batsu1")
self.canvas.create_line(10,43,43,10,fill = "black", width = 5, tag = "batsu2")
self.txt2.delete(0,tk.END)

判定のプログラムになります。

ここで、正解か不正解を判別し、正解なら、キャンバスに〇を表示し、不正解ならキャンバスに×を表示します。


次の問題への処理


def Next(self):
if self.judgeNum == 1:
self.canvas.delete("maru")

self.num = rd.randint(1,len(self.wordlist) - 1)

self.txt1.delete(0,tk.END)
self.txt2.delete(0,tk.END)
self.txt1.insert(0,self.wordlist[self.num][0])

self.select4_destroy()
self.select4()

self.judgeNum = -1

正解なら、次の問題が表示されますが、不正解なら、次の問題への処理をできないようにしています。変数judgeNumでその部分の制御をしています。


完成のプログラム

大まかな部分の説明はしましたが、その他細かな部分のコードを含めた完成のプログラムが以下になります。


word.py

import tkinter as tk

import random as rd
import csv

class Application(tk.Frame):
def __init__(self, master):
super().__init__(master)
self.pack()

self.master.geometry("380x200")
self.master.title("英単語ソフト")

self.canvas = tk.Canvas(self.master, bg = "white", width = 50, height = 50)
self.canvas.place(x = 30,y = 135)

self.WordInput()
self.SetVar()
self.widget()

self.master.bind("<Return>", self.EnterJudge)

def SetVar(self):
self.judgeNum = -1
self.num = rd.randint(0,len(self.wordlist) - 1)

def WordInput(self):
f = open("word.csv","r",encoding = "utf-8-sig")

self.wordlist = list(csv.reader(f))

f.close()

#部品の配置↓

def widget(self):

self.txt1 = tk.Entry(self.master, width = 33)
self.txt1.place(x = 50, y = 30)

self.txt1.insert(0,self.wordlist[self.num][0])

self.txt2 = tk.Entry(self.master, width = 33)
self.txt2.place(x = 50, y = 90)

self.BtnJudge = tk.Button(self.master, text = "判定", command = self.ClickJudge, width = 10)
self.BtnJudge.place(x = 110, y = 148)

self.BtnNext = tk.Button(self.master, text = "次の単語", command = self.Next, width = 10)
self.BtnNext.place(x = 215, y = 148)

self.select4()#4択

#部品の配置↑

#4択の表示↓
def select4(self):

rdNum = rd.randint(0,3)
lbl_x = 280
lbl_y = 15

self.Rdlist()

for i in range(4):

if i == 0:
if i == rdNum:
self.lbl1 = tk.Label(self.master, text = str(i+1) + " . " + self.wordlist[self.num][1])
self.lbl1.place(x = lbl_x, y = lbl_y + i * 30)
else:
self.lbl1 = tk.Label(self.master, text = str(i+1) + " . " + self.wordlist[self.rdlist[i]][1])
self.lbl1.place(x = lbl_x, y = lbl_y + i * 30)

if i == 1:
if i == rdNum:
self.lbl2 = tk.Label(self.master, text = str(i+1) + " . " + self.wordlist[self.num][1])
self.lbl2.place(x = lbl_x, y = lbl_y + i * 30)
else:
self.lbl2 = tk.Label(self.master, text = str(i+1) + " . " + self.wordlist[self.rdlist[i]][1])
self.lbl2.place(x = lbl_x, y = lbl_y + i * 30)

if i == 2:
if i == rdNum:
self.lbl3 = tk.Label(self.master, text = str(i+1) + " . " + self.wordlist[self.num][1])
self.lbl3.place(x = lbl_x, y = lbl_y + i * 30)
else:
self.lbl3 = tk.Label(self.master, text = str(i+1) + " . " + self.wordlist[self.rdlist[i]][1])
self.lbl3.place(x = lbl_x, y = lbl_y + i * 30)

if i == 3:
if i == rdNum:
self.lbl4 = tk.Label(self.master, text = str(i+1) + " . " + self.wordlist[self.num][1])
self.lbl4.place(x = lbl_x, y = lbl_y + i * 30)
else:
self.lbl4 = tk.Label(self.master, text = str(i+1) + " . " + self.wordlist[self.rdlist[i]][1])
self.lbl4.place(x = lbl_x, y = lbl_y + i * 30)

def Rdlist(self):
self.rdlist = list(range(len(self.wordlist)))
rd.shuffle(self.rdlist)
self.rdlist.remove(self.wordlist.index(self.wordlist[self.num]))

def select4_destroy(self):
self.lbl1.destroy()
self.lbl2.destroy()
self.lbl3.destroy()
self.lbl4.destroy()

#4択の表示↑

#判定↓

def Judge(self):
if self.txt2.get() == self.wordlist[self.num][1]:
self.marupro()
else:
self.batsupro()

def ClickJudge(self):
self.Judge()

def EnterJudge(self, event):
self.Judge()

def marupro(self):
self.canvas.delete("batsu1")
self.canvas.delete("batsu2")
self.judgeNum = 1
#print("正解")
self.canvas.create_oval(10,10,43,43,outline = "red", width = 5, tag = "maru")

def batsupro(self):
#print("不正解")
self.canvas.create_line(10,10,43,43,fill = "black", width = 5, tag = "batsu1")
self.canvas.create_line(10,43,43,10,fill = "black", width = 5, tag = "batsu2")
self.txt2.delete(0,tk.END)

#判定↑

def Next(self):
if self.judgeNum == 1:
self.canvas.delete("maru")

self.num = rd.randint(1,len(self.wordlist) - 1)

self.txt1.delete(0,tk.END)
self.txt2.delete(0,tk.END)
self.txt1.insert(0,self.wordlist[self.num][0])

self.select4_destroy()
self.select4()

self.judgeNum = -1

def main():
win = tk.Tk()
app = Application(master = win)
app.mainloop()

if __name__ == "__main__":

main()


これでプログラムは完成になります。

また、同じフォルダにカンマ区切りのcsvファイル(ファイル名はword.csv)を置けば、しっかりと動作すると思います。


word.csv

例)

battery(名),電池
stage(名),段階
tube(名),管
power(名),電力
ocean(名),海洋
crystal(名),結晶
wire(名),針金
wire(他),配線する
style(名),様式
・・・


終わりに

csvファイルのデータを覚えたい英単語にしてあげれば、自分だけの英単語ソフトを作ることができます!

もし動かなかったりした場合、コメントをください。できるだけ対応します!