Creating a Pomodoro GUI App using Tkinter in Python

Ayush Dixit
Nerd For Tech
Published in
5 min readOct 31, 2021

The Pomodoro technique is an efficient system of time management. Where instead of multitasking a person focuses on a particular task at the given moment.

Objective of the GUI

We focus on the task for 25 straight minutes and then after take a 5 minute break. A time sprint of 30 Minutes which is termed as a single Pomodoro. After 4 such Pomodoros the user takes a longer break of 20 minutes.

Steps to build the GUI

  1. Importing the tkinter and math library
  2. Defining global constants
  3. Setting up the UI
  4. Framing the Countdown Mechanism
  5. Framing the Timer Mechanism
  6. Setting the Timer Reset logic

Step 1 : Importing the tkinter and math library

from tkinter import *
import math

Step 2 : Defining global constants

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

Here we have hardcoded the hex value of colours for easy reference later in applying them to the GUI.

Step 3 : UI Setup

window = Tk()
window.title("Pomodoro")
window.config(padx=100, pady=50, bg=YELLOW)
title_label = Label(text="Timer", fg=GREEN, bg=YELLOW, font=(FONT_NAME, 50))
title_label.grid(column=1, row=0)
# Need to check the background colour of the canvas as well
canvas = Canvas(width=200, height=224, bg=YELLOW, highlightthickness=0)
# highlightthicknes is used for making the highlight disappear
tomato_img = PhotoImage(file="tomato.png")
canvas.create_image(100, 112, image=tomato_img)
timer_text = canvas.create_text(100, 130, text="00:00", fill="white", font=(FONT_NAME, 35, "bold"))
canvas.grid(column=1, row=1)
# x and y values are half of the width and the height
start_button = Button(text="Start", highlightthickness=0, command=start_timer)
start_button.grid(column=0, row=2)
reset_button = Button(text="Reset", highlightthickness=0, command = reset_timer)
reset_button.grid(column=2, row=2)

check_marks = Label(text="✓", fg=GREEN, bg=YELLOW)
check_marks.grid(column=1, row=3)

We would be using the Tk class for defining the window and also giving it a paddding of 100, 50 pixels.

We would be using the grid layout for placing the buttons and labels.

The “highlightthickness” does away with the border outline of the canvas. Try skipping it and you would know what i am talking about.

fg = is used to define the foreground colour while bg is used to define the background colour.

Step 4 : Countdown Mechanism


def count_down(count):
count_min = math.floor(count / 60)
count_sec = count % 60
# Dynamic typing allows for changing the data type of a variable
# Just by assigning it to a different kind of value
if count_sec < 10:
count_sec = f"0{count_sec}"
canvas.itemconfig(timer_text, text=f"{count_min}:{count_sec}")
if count > 0:
global timer
timer = window.after(1000, count_down, count - 1)
else:
start_timer()
marks = ""
work_sessions = math.floor(reps/2)
for _ in range(work_sessions):
marks += "✓"
check_marks.config(text=marks)

The logic simply is to input both minutes and seconds in the “00:00” format. For this to be done we can simply pass on seconds and count the number of minutes by dividing it by 60 and rounding it off by using the floor method of python.

A bug which may happen here is after the seconds reach below 10 the GUI displays something of the sorts of “0:8” assuming it was 8 seconds at the time.

To avoid this we use the if condition and use the concept of dynamic typing that is changing the datatype of “count_sec” to string.

if count > 0:
global timer
timer = window.after(1000, count_down, count - 1)
else:
start_timer()
marks = ""
work_sessions = math.floor(reps/2)
for _ in range(work_sessions):
marks += "✓"
check_marks.config(text=marks)

The “after” method is used to add a delay after which a particular window updates itself. After each repetition of the pomodoro we also add in a checkmark. This is passed on in the empty string “marks”.

Step 5 : Framing the Timer Mechanism

def start_timer():
global reps
reps += 1
work_sec = WORK_MIN * 60
short_break_sec = SHORT_BREAK_MIN * 60
long_break_sec = LONG_BREAK_MIN * 60
# If it's the 8th rep
if reps % 8 == 0:
count_down(long_break_sec)
title_label.config(text="Break", fg=RED)
# If it's the 2nd/4th/6th rep
elif reps % 2 == 0:
count_down(short_break_sec)
title_label.config(text="Break", fg=PINK)
# If it's the 1st/3rd/5th/7th rep
else:
count_down(work_sec)
title_label.config(text="Work", fg=GREEN)

The way we are governing the timing section of work and break is by simply giving a counter global variable called reps.

For every 8th iteration we go for a long break of 20 mins.

if reps % 8 == 0:
count_down(long_break_sec)
title_label.config(text="Break", fg=RED)

Similarly, for every 2nd/4th/6th repetition we go for a short break of 5 mins.

# If it's the 2nd/4th/6th rep
elif reps % 2 == 0:
count_down(short_break_sec)
title_label.config(text="Break", fg=PINK)

Else we work!

else:
count_down(work_sec)
title_label.config(text="Work", fg=GREEN)

Step 6 : Setting the Timer Reset logic

def reset_timer():
window.after_cancel(timer)
canvas.itemconfig(timer_text, text="00:00")
title_label.config(text="Timer")
check_marks.config(text="")
global reps
reps = 0

The timer reset logic is simple enough in the event of the timer button being clicked th GUI should reset itself. To display the time on the canvas or on the tomoto we use “itemconfig” method and than for label we use “config” method.

Also, don’t forget to give, at the end of the code to stop the canvas from disappearing .

mainloop() tells Python to run the Tkinter event loop. This method listens for events, such as button clicks or keypresses, and blocks any code that comes after it from running until the window it’s called on is closed. Go ahead and close the window you’ve created, and you’ll see a new prompt displayed in the shell.:

window.mainloop()

You can find the complete code here.

Summary

We successfully developed the Pomodoro GUI using Tkinter Library and in the process we learnt about the tkinter module, method such as canvas, config etcetera, and most importantly dynamic typing.

I hope this was a great learning experience for anyone who takes the pain of reading and implmenting it :) .

Did you like my efforts? If Yes, please follow me to get my latest posts and updates or better still, buy me a coffee!☕

--

--

Ayush Dixit
Nerd For Tech

Hi, I’m a postgraduate from IIT-Indore(M.Tech). Specialization in Comm. Signal Processing and Machine Learning/AI. Presently working as an Engineer in Qualcomm.