This is a 100 Days challenge to learn a new language (Python). 100 Days of Code - The Complete Python Pro Bootcamp
I will post some notes to motivate myself to finish this challenge.
Goal
1. Using Tkinter to build a GUI
a. Using canvas to mix images and texts
b. Binding functions to buttons
c. Utilizing grid layout for the better look
d. Lean how to update Tkinter elements
2. Deal with csv file through pandas
a. Support reading and writting
b. Studying some parameters when transform DataFrame to other DataType
DataFrame.to_dict(orient="records")
3. Using after and after_cancel to manage events
4. Try to use Error Handling as we learned on Day 30
Requirements
1. Build a flash card app which read data from csv file.
2. After 3 seconds, app should flip the card to see the translated word.
3. Next word should be shown after both buttons got clicked.
4. Once users click 'mark' button (or I knew button), then we should not let users see this word anymore.
5. Save the progress to csv file and read data from it from the next play.
Project - Flash Card
Ex:
import tkinter as tk
import pandas as pd
import random
import os
BACKGROUND_COLOR = "#B1DDC6"
FONT = "Ariel"
ALL_WORDS_CSV_FILE = "data/1000 words (en-to-zh-tw).csv"
WORDS_TO_LEARN_CSV_FILE = "data/words_to_learn.csv"
# Variables
words_dic = {}
selected_word = {}
filp_timer = ""
# Read a comma-separated values (csv) file into DataFrame.
# NOTE:
# Using Exception handling here for practice only becuse it is easy
# to be abused
# It is better to find a proper way
# (such as adding some if-else condition)
try:
words_to_learn_data_frame = pd.read_csv(WORDS_TO_LEARN_CSV_FILE)
except FileNotFoundError:
# If we cannot find the historical data,
# then we read data from raw csv
all_words_data_frame = pd.read_csv(ALL_WORDS_CSV_FILE)
words_dic = all_words_data_frame.to_dict(orient="records")
else:
words_dic = words_to_learn_data_frame.to_dict(orient="records")
def game_over():
"""Show game over message, and remvoe the historical data"""
# Clear title and word text
canvas.delete(title_text)
canvas.delete(word_text)
# Add game over message
canvas.create_text(
400,
170,
text="You have learned all words",
fill="black",
font=(FONT, 40, "bold"),
)
# Remove 'words_to_learn.csv'
if os.path.exists(WORDS_TO_LEARN_CSV_FILE):
os.remove(WORDS_TO_LEARN_CSV_FILE)
def right_btn_clicked():
"""Need to remove the current word from the list and
dump the updated list to csv file, then generate the next word"""
# Remove the previous word since users knew it
global selected_word
if selected_word:
words_dic.remove(selected_word)
# Reset it
selected_word = {}
# Export current words collection to csv
words_to_learn_data_frame = pd.DataFrame.from_dict(words_dic)
words_to_learn_data_frame.to_csv(
"data/words_to_learn.csv",
index=False
)
next_word()
def next_word():
"""Randomly select a word and show it in card"""
# cancel previous timer if needed
global filp_timer
if not filp_timer == "":
root.after_cancel(filp_timer)
# Game Over - No more words to learn
if len(words_dic) == 0:
game_over()
return
# Change the canvas image to front_image
canvas.itemconfig(canvas_image, image=front_image)
# Randomly select a word and save it to the
# global variable selected_word
global selected_word
selected_word = random.choice(words_dic)
# Change title and word
canvas.itemconfig(title_text, fill="black", text="English")
canvas.itemconfig(word_text, fill="black",
text=selected_word.get("English"))
# Update global variable filter_timer
filp_timer = root.after(3000, flip_card)
def flip_card():
"""Show Chinese Word"""
# Change the canvas image to back_image
canvas.itemconfig(canvas_image, image=back_image)
# Change title and word
canvas.itemconfig(title_text, fill="white", text="Chinese")
canvas.itemconfig(
word_text, fill="white",
text=selected_word.get("Traditional Chinese")
)
# Init Tkinter
root = tk.Tk()
root.title("Flash Card")
root.config(padx=50, pady=50, background=BACKGROUND_COLOR)
# Init canvas
canvas = tk.Canvas(
width=800, height=526, background=BACKGROUND_COLOR,
highlightthickness=0
)
# Add card_front image and set it to the center of the canvas
front_image = tk.PhotoImage(file="images/card_front.png")
back_image = tk.PhotoImage(file="images/card_back.png")
canvas_image = canvas.create_image(400, 263, image=front_image)
# Add Title Text, and set it to the middle and a bit up of the canvas
title_text = canvas.create_text(
400, 150, text="", fill="black", font=(FONT, 40, "italic")
)
# Add Word Text, and set it to the middle and a bit down of the canvas
word_text = canvas.create_text(400, 253, text="", fill="black",
font=(FONT, 60, "bold"))
canvas.grid(column=0, row=0, columnspan=2)
# Wrong Btn
wrong_image = tk.PhotoImage(file="images/wrong.png")
wrong_btn = tk.Button(image=wrong_image, command=next_word)
wrong_btn.config(background=BACKGROUND_COLOR,
activebackground=BACKGROUND_COLOR)
wrong_btn.grid(sticky="ew", column=0, row=1)
# Right Btn
right_image = tk.PhotoImage(file="images/right.png")
right_btn = tk.Button(image=right_image, command=right_btn_clicked)
right_btn.config(background=BACKGROUND_COLOR,
activebackground=BACKGROUND_COLOR)
right_btn.grid(sticky="ew", column=1, row=1)
# Get the first Word Card
next_word()
# Start the Event Loop
root.mainloop()