To create to-do list app with pie chart in Tkinter to check number of completed tasks

In this tutorial, we will learn how to create a to-do list app with a pie chart in Tkinter to check the number of completed tasks. I hope you will find this helpful.

let’s understand the code with some simple steps:

Step 1: Importing some useful libraries
import tkinter as tk
from tkinter import messagebox
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt
  • Tkinter is used here to create GUI and provide various tools for windows, buttons, and other interface components.
  • We use the matplotlib library for creating charts and graphs.
Step 2: Creating the main window
newWindow = tk.Tk()
newWindow.title("To-Do List")
newWindow.geometry("590x800+270+200")
newWindow.configure(bg="#0d1525")
  • Tk() creates the main window.
  • title() sets the window’s title.
  • geometry() sets the window size and position.
  • configure() sets the background color to a dark shade.
Step 3: For task completion
def mark_as_done(task_label, done_button):
    task_label.config(fg="gray", font=("Helvetica", 18, "overstrike"))
    done_button.config(state=tk.DISABLED, disabledforeground="green")
    update_task_count()
  • mark_as_done()  function updates the task label by crossing it out.
Step 4: To delete a task
def delete_task(task_frame):
    task_frame.destroy()  
    update_serial_numbers()  
    update_task_count()
  • task_frame.destroy() removes the task’s frame from the window
  • update_serial_numbers() renumbers the tasks after deletion.
  • update_task_count() updates the task statistics.
Step 5: To Add a task
def add_task(task=None):
    task = task_entry.get().strip() if not task else task
    if not task:
        messagebox.showwarning("Empty Task", "Task cannot be empty.")
        return
task_frame = tk.Frame(task_container, bg="#1d2332", pady=5)
    task_number = len(task_container.winfo_children()) + 1
    task_label = tk.Label(task_frame, text=f"{task_number}. {task}", bg="#1d2332", fg="#ffffff", font=("Helvetica", 18))
    
 done_button = tk.Button(task_frame, text="Done", command=lambda: mark_as_done(task_label, done_button), bg="#add8e6", fg="#000000", font=("Helvetica", 12))
    delete_button = tk.Button(task_frame, text="Delete", command=lambda: delete_task(task_frame), bg="#ff6347", fg="#000000", font=("Helvetica", 12))
    
task_label.pack(side=tk.LEFT, padx=10)
    done_button.pack(side=tk.RIGHT, padx=5)
    delete_button.pack(side=tk.RIGHT, padx=5)
    task_frame.pack(fill=tk.X, pady=5)
    
    task_entry.delete(0, tk.END)
    update_serial_numbers()
    update_task_count()
  • task_entry.get() fetches the task text that the user has typed.
  • add_task() function lets a user add a new task.
Step 6: To update task numbers
def update_serial_numbers():
    for index, task_frame in enumerate(task_container.winfo_children()):
        task_label = task_frame.winfo_children()[0]
        task_text = task_label.cget("text").split(". ", 1)[1]
        task_label.config(text=f"{index + 1}. {task_text}")
  • This function updates the number in sequence.
Step 7: to remove all tasks
def delete_all_tasks():
    for widget in task_container.winfo_children():
        widget.destroy()
    update_task_count()
  • This function deletes all tasks at once.
Step 8: to update task statistics
def update_task_count():
    total_tasks = len(task_container.winfo_children())
    done_tasks = sum(1 for task_frame in task_container.winfo_children() if "overstrike" in task_frame.winfo_children()[0].cget("font"))
    remaining_tasks = total_tasks - done_tasks

    total_tasks_label.config(text=f"Total Tasks: {total_tasks}")
    remaining_tasks_label.config(text=f"Remaining Tasks: {remaining_tasks}")
    done_tasks_label.config(text=f"Completed Tasks: {done_tasks}")
    update_pie_chart(total_tasks, remaining_tasks, done_tasks)
  • This function calculates the total completed and remaining tasks by analyzing the task frames.
Step 9: to create a pie chart
def update_pie_chart(total_tasks, remaining_tasks, done_tasks):
    for widget in pie_chart_frame.winfo_children():
        widget.destroy()

    if total_tasks == 0:
        return

    labels = ['Completed Tasks', 'Remaining Tasks']
    sizes = [done_tasks, remaining_tasks]
    colors = ['#4caf50', '#ffeb3b']

    fig, ax = plt.subplots(figsize=(5, 3), dpi=100)
    fig.patch.set_facecolor('#0d1525')

    ax.pie(sizes, colors=colors, autopct='%1.1f%%', startangle=140)
    ax.axis('equal')

    canvas_chart = FigureCanvasTkAgg(fig, master=pie_chart_frame)
    canvas_chart.draw()
    canvas_chart.get_tk_widget().pack()

    plt.close(fig)
  • This function represents the number of completed and remaining tasks through a pie chart.
Step 10: Saving tasks
def save_tasks():
    with open("tasks.txt", "w") as file:
        for task_frame in task_container.winfo_children():
            task_label = task_frame.winfo_children()[0]
            task_text = task_label.cget("text").split(". ", 1)[1]
            task_done = "1" if "overstrike" in task_label.cget("font") else "0"
            file.write(f"{task_text}|{task_done}\n")
    messagebox.showinfo("Save Tasks", "Tasks have been saved successfully.")
  • This function saves the tasks to a text file to reload when the app starts.
Step 11: Loading tasks
def load_tasks():
    try:
        with open("tasks.txt", "r") as file:
            for line in file:
                task_text, task_done = line.strip().split("|")
                add_task(task_text)
                if task_done == "1":
                    task_frame = task_container.winfo_children()[-1]
                    task_label = task_frame.winfo_children()[0]
                    done_button = task_frame.winfo_children()[1]
                    mark_as_done(task_label, done_button)
    except FileNotFoundError:
        pass
  • By using this function, the saved tasks are loaded back into the app when they start.
Step 12: To structure the interface
canvas = tk.Canvas(newWindow, bg="#0d1525")
scrollbar = tk.Scrollbar(newWindow, orient="vertical", command=canvas.yview)
canvas.configure(yscrollcommand=scrollbar.set)

task_container = tk.Frame(canvas, bg="#0d1525")
canvas.create_window((0, 0), window=task_container, anchor="nw")

task_entry = tk.Entry(newWindow, width=35, bg="#1d2332", fg="#ffffff", font=("Helvetica", 22))
task_entry.pack(pady=10)
add_task_button = tk.Button(newWindow, text="Add Task", command=add_task, bg="#add8e6", fg="#000000", font=("Helvetica", 12))
delete_all_button = tk.Button(newWindow, text="Delete All Tasks", command=delete_all_tasks, bg="#ff6347", fg="#000000", font=("Helvetica", 12))

total_tasks_label = tk.Label(newWindow, text="Total Tasks: 0", bg="#0d1525", fg="#ffffff", font=("Helvetica", 14))
remaining_tasks_label = tk.Label(newWindow, text="Remaining Tasks: 0", bg="#0d1525", fg="#ffffff", font=("Helvetica", 14))
done_tasks_label = tk.Label(newWindow, text="Completed Tasks: 0", bg="#0d1525", fg="#ffffff", font=("Helvetica", 14))

pie_chart_frame = tk.Frame(newWindow, bg="#0d1525")
  • Here, we are building the user interface.
Step 13: To run the final application
newWindow.mainloop()
  • This loop keeps the window open and responsive, waiting for events.

Output:

 

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top