Friday, May 13, 2022

Python - Project - Pomodoro (Day 28)

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



Use Tkinter to build a Pomodoro GUI program.


How to add images to Tkinter?



We can use canvas as a wrapper to wrap the components such as image, line, or text.


Ex: 
import tkinter as tk

# Init
root = tk.Tk()
root.title("Exp")

# Init Canvas
canvas = tk.Canvas(width=200, height=224)
tomato_img = tk.PhotoImage(file="tomato.png")
# Create an image to canvas
canvas.create_image(
    100,
    112,
    image=tomato_img,
)
canvas.pack()

# Start the Event Loop
root.mainloop()


How to schedule/cancel a task on Tkinter? 


after()
* It calls the callback function once after a delay milliseconds.

after_cancel()
* It can stop the particular scheduled task.

Ex:
import tkinter as tk

# Global Variables
scheduled_job_identifier = None


def update_label():
    """Update Lable"""
    label.config(text="Label has been updated!!", fg="blue")


def schedule():
    """Start a scheduled job with 5 seconds delay"""
    global scheduled_job_identifier
    # Update label after 5 seconds delay
    scheduled_job_identifier = root.after(5000, update_label)


def cancel():
    """Cancel the scheduled job"""
    # Terminate the scheduled job
    root.after_cancel(scheduled_job_identifier)


# Init
root = tk.Tk()
root.title("Exp")
root.minsize(width=300, height=100)

# Init Label
label = tk.Label(text="Hello World", fg="red")
label.pack()

# Init Buttons
btn_schedule = tk.Button(
    text="Schedule a task to change label text after 5 seconds",
command=schedule
)
btn_schedule.pack()
btn_cancel = tk.Button(text="cancel", command=cancel)
btn_cancel.pack()

# Start the Event Loop
root.mainloop()


Dynamic Typing


Dynamic typing means that the type of the variable is determined only during runtime.

Ex: 
value = 1
print(type(value))

value = "Hello World"
print(type(value))
Result:

<class 'int'> <class 'str'>



Project - Pomodoro




Ex:
import tkinter as tk
import math

# Constants
PINK = "#e2979c"
RED = "#e7305b"
GREEN = "#9bdeac"
YELLOW = "#f7f5dd"
FONT_NAME = "Courier"
WORK_MIN = 25
SHORT_BREAK_MIN = 5
LONG_BREAK_MIN = 20

# Global Variables
timer = None

# step 1: Work
# step 2: Short Break
# step 3: Work
# step 4: Short Break
# step 5: Work
# step 6: Short Break
# step 7: Work
# step 8: Long Break
step = 0


def reset_timer():
    """Reset App"""
    ## Cancel timer
    root.after_cancel(timer)

    ## Reset Title
    title_label.config(text="Timer")

    ## Reset countdown text
    canvas.itemconfig(count_down_text, text="00:00")

    ## Reset Marks
    marks_label.config(text="")

    ## Reset steps
    global step
    step = 0


def start_timer():
    """Trigger Count Down function"""
    global step
    step += 1

    if step % 8 == 0:
        # Long Break
        count_down(LONG_BREAK_MIN * 60)
        title_label.config(text="Break", fg=RED)
    elif step % 2 == 0:
        # Short Break
        count_down(SHORT_BREAK_MIN * 60)
        title_label.config(text="Break", fg=PINK)
    else:
        # Work
        count_down(WORK_MIN * 60)
        title_label.config(text="Work", fg=GREEN)


def get_count_down_text(counter):
    """Format count down secongs to readable text"""
    counter_min = math.floor(counter / 60)
    counter_second = counter % 60

    # Dynamic Typing
    if counter_second < 10:
        counter_second = "0" + str(counter_second)

    return f"{counter_min}:{counter_second}"


def count_down(counter):
    """Trigger root after function"""

    canvas.itemconfig(count_down_text, text=get_count_down_text(counter))

    if counter > 0:
        global timer
        timer = root.after(1000, count_down, counter - 1)
    else:
        # Go to next step
        start_timer()

        # Update marks label
        marks = ""
        for _ in range(math.floor(step / 2)):
            marks = marks + "✓"
        marks_label.config(text=marks)


# Init
root = tk.Tk()
root.title("Pomodoro")
root.configure(padx=100, pady=50, bg=YELLOW)

# Init Title Lable
title_label = tk.Label(
    text="Timer", background=YELLOW, foreground=GREEN,
font=(FONT_NAME, 30, "bold")
)
title_label.grid(column=1, row=0)

# Init Canvas
canvas = tk.Canvas(width=200, height=224, background=YELLOW,
highlightthickness=0)
tomato_img = tk.PhotoImage(file="tomato.png")
canvas.create_image(
    100,
    112,
    image=tomato_img,
)
count_down_text = canvas.create_text(
    100, 130, text="00:00", fill="white", font=(FONT_NAME, 35, "bold")
)
canvas.grid(column=1, row=1)

# Init Buttons
start_btn = tk.Button(text="Start", command=start_timer)
start_btn.grid(column=0, row=2)
reset_btn = tk.Button(text="Reset", command=reset_timer)
reset_btn.grid(column=2, row=2)

# Init Marks Label
marks_label = tk.Label(
    text="", background=YELLOW, foreground=GREEN,
font=(FONT_NAME, 10, "bold")
)
marks_label.grid(column=1, row=3)

# Start the Event Loop
root.mainloop()

No comments:

Post a Comment