LoginSignup
28
28

More than 1 year has passed since last update.

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

Last updated at Posted at 2019-03-04

はじめに

こんにちは。
今回はPythonの勉強と英語の勉強を兼ねて、「英単語ソフト」 を作ってみようと思います。
GUI で作成したいので、tkinter を使って実装していきます。

英単語ソフトメイン画面.png
こちらが完成形になります。

仕様的には、カンマ区切りで書かれているテキストデータである 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ファイルのデータを覚えたい英単語にしてあげれば、自分だけの英単語ソフトを作ることができます!
もし動かなかったりした場合、コメントをください。できるだけ対応します!

28
28
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
28
28