Is there a way in Python to change a way a function works through clicking a button

Viewed 71

I have wrote this simple program in Python, which consists of 2 buttons (Start and Reset) as well as a canvas for the 00:00 timer, what it does is when you click Start the time counts down from (25 mins) until it reaches 00:00 and changes the label_text from "Work" to "Break" and the count down begins again from (5 mins to 00:00) and change the label_text back to "Work" from "Break", everything works perfectly, however, my problem is: If I click Start more than one time, both count downs work at the same time, what I need is, when I click start, I should not be able to click it again unless I click Reset button.

I can fix it using the button["state"] = DISABLED but it doesn't help, if you know of any other way I would appreciate your help, thank you very much in advance.

Here's my code:

from tkinter import *
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
reps = 0
timer = None

# ---------------------------- TIMER RESET ------------------------------- #
def reset_timer():
    window.after_cancel(timer)
    checkmark_label.config(text="")
    canvas.itemconfig(time_text, text="00:00")
    timer_label.config(text="Timer")
    global reps
    reps = 0


# ---------------------------- 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 reps % 8 == 0:
        count_down(long_break_sec)
        timer_label.config(text="Break", fg=RED)


    elif reps % 2 == 0:
        count_down(short_break_sec)
        timer_label.config(text="Break", fg=PINK)
        window.attributes('-topmost', 1)

    else:
        count_down(work_sec)
        timer_label.config(text="Work", fg=GREEN)
        window.attributes('-topmost', 0)

# ---------------------------- COUNTDOWN MECHANISM ------------------------------- #


def count_down(count):

    count_min =  math.floor(count / 60)
    count_sec = count % 60
    if count_sec == 0:
        count_sec = "00"
    elif count_sec > 0 and count_sec < 10:
        count_sec = f"0{count_sec}"
    canvas.itemconfig(time_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 += "✔"
            checkmark_label.config(text=marks)



# ---------------------------- UI SETUP ------------------------------- #
window = Tk()
window.title("Pomodoro")
window.config(padx=100, pady=50, bg=YELLOW)


canvas = Canvas(width=200, height=224, bg=YELLOW, highlightthickness=0)
tomato_img = PhotoImage(file="tomato.png")
canvas.create_image(100, 112, image=tomato_img)
time_text = canvas.create_text(103, 130, text="00:00", fill="white", font=(FONT_NAME, 35, "bold"))
canvas.grid(column=2, row=2)


# Labels
timer_label = Label(text="Timer",bg=YELLOW, fg=GREEN, font=(FONT_NAME, 50, "bold"))
timer_label.grid(column=2, row=1)
checkmark_label = Label(fg=GREEN)
checkmark_label.grid(column=2, row=4)


# Buttons
start_button = Button(text="Start", bg=GREEN, width=11, height=2, borderwidth=0, command=start_timer)
start_button.grid(column=1, row=3)
reset_button = Button(text="Reset", bg=GREEN, width=11, height=2, borderwidth=0, command=reset_timer)
reset_button.grid(column=3, row=3)


window.mainloop()
1 Answers

I don't know why you had trouble with this, but everything you needed is just track if timer is already counting or not. To make this i have created a global variable called "is_counting" which is False by default. When user presses "start" button it sets this variable to True. If user presses this button again, program will see that timer is already counting and it won't start a new timer. This solution is super simple, but it works, and works well.

Your code with applied fixes:

from tkinter import *
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
reps = 0
timer = None
is_counting = False

# ---------------------------- TIMER RESET ------------------------------- #
def reset_timer():
    global is_counting
    is_counting = False

    window.after_cancel(timer)
    checkmark_label.config(text="")
    canvas.itemconfig(time_text, text="00:00")
    timer_label.config(text="Timer")
    global reps
    reps = 0


# ---------------------------- TIMER MECHANISM ------------------------------- #
def start_timer():
    # Checking if timer already exists. If it is,
    # this function won't do anything
    global is_counting
    if is_counting:
        return
    is_counting = True

    global reps
    reps += 1

    work_sec = WORK_MIN * 60
    short_break_sec = SHORT_BREAK_MIN * 60
    long_break_sec = LONG_BREAK_MIN * 60

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


    elif reps % 2 == 0:
        count_down(short_break_sec)
        timer_label.config(text="Break", fg=PINK)
        window.attributes('-topmost', 1)

    else:
        count_down(work_sec)
        timer_label.config(text="Work", fg=GREEN)
        window.attributes('-topmost', 0)

# ---------------------------- COUNTDOWN MECHANISM ------------------------------- #


def count_down(count):

    count_min =  math.floor(count / 60)
    count_sec = count % 60
    if count_sec == 0:
        count_sec = "00"
    elif count_sec > 0 and count_sec < 10:
        count_sec = f"0{count_sec}"
    canvas.itemconfig(time_text, text=f"{count_min}:{count_sec}")
    if count > 0:
        global timer
        timer = window.after(1000, count_down, count - 1)

    else:
        # Setting is_counting variable to False, because start_timer()
        # won't work when timer is already counting
        global is_counting
        is_counting = False
        start_timer()
        marks = ""
        work_sessions = math.floor(reps/2)
        for _ in range(work_sessions):
            marks += "✔"
            checkmark_label.config(text=marks)



# ---------------------------- UI SETUP ------------------------------- #
window = Tk()
window.title("Pomodoro")
window.config(padx=100, pady=50, bg=YELLOW)


canvas = Canvas(width=200, height=224, bg=YELLOW, highlightthickness=0)
tomato_img = PhotoImage(file="tomato.png")
canvas.create_image(100, 112, image=tomato_img)
time_text = canvas.create_text(103, 130, text="00:00", fill="white", font=(FONT_NAME, 35, "bold"))
canvas.grid(column=2, row=2)


# Labels
timer_label = Label(text="Timer",bg=YELLOW, fg=GREEN, font=(FONT_NAME, 50, "bold"))
timer_label.grid(column=2, row=1)
checkmark_label = Label(fg=GREEN)
checkmark_label.grid(column=2, row=4)


# Buttons
start_button = Button(text="Start", bg=GREEN, width=11, height=2, borderwidth=0, command=start_timer)
start_button.grid(column=1, row=3)
reset_button = Button(text="Reset", bg=GREEN, width=11, height=2, borderwidth=0, command=reset_timer)
reset_button.grid(column=3, row=3)


window.mainloop()
Related