Create a To-Do list In python using tkinter module

To-Do List Application

This is a simple To-Do List application built using Python’s Tkinter library, PIL (Pillow) for image processing, and Matplotlib for visualizing task completion using a pie chart. The application allows users to manage tasks, mark them as completed, and visualize task statistics.

Features

Add Tasks: Enter a task in the input field and click “Add Task” to add it to the list.
Mark as Done : Mark tasks as completed. Completed tasks are displayed in gray with a strikethrough.
Delete Tasks : Remove individual tasks or delete all tasks at once.
Save Tasks : Save the current list of tasks to a file.
Load Tasks : Load tasks from a previously saved file.
Task Statistics : Display the total number of tasks, remaining tasks, and completed tasks.
Pie Chart : Visualize the proportion of completed vs. remaining tasks using a pie chart.

import tkinter as tk
from tkinter import messagebox
from PIL import Image, ImageTk
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

newWindow = tk.Tk()
newWindow.title("To-Do List")
newWindow.geometry("800x600+270+200")
newWindow.configure(bg="#1a1a2e")

# Global font styles
font_large = ("Helvetica", 22, "bold")
font_medium = ("Helvetica", 18)
font_small = ("Helvetica", 12)

def resize_image(image_path, size, background_color=(13, 21, 37)):
    with Image.open(image_path) as img:
        bg = Image.new('RGBA', img.size, background_color + (255,))
        bg.paste(img, (0, 0), img)
        img = bg.resize(size, Image.LANCZOS)
        return ImageTk.PhotoImage(img)

done_icon = resize_image("ToDoList\\correct.png", (20, 20), background_color=(13, 21, 37))
delete_icon = resize_image("ToDoList\\bin.png", (20, 20), background_color=(13, 21, 37))

def mark_as_done(task_label, done_button):
    task_label.config(fg="gray", font=(font_medium[0], font_medium[1], "overstrike"))
    done_button.config(image=done_icon, state=tk.DISABLED, disabledforeground="green")
    update_task_count()

def delete_task(task_frame):
    task_frame.destroy()
    update_serial_numbers()
    update_task_count()

def add_task(task=None):
    if not task:
        task = task_entry.get()
    if task:
        task_frame = tk.Frame(task_container, bg="#162447", pady=5)
        task_number = len(task_container.winfo_children()) + 1
        task_label = tk.Label(task_frame, text=f"{task_number}. {task}", bg="#162447", fg="#e0e0e0", font=font_medium)
        task_label.pack(side=tk.LEFT, padx=10)
        done_button = tk.Button(task_frame, image=done_icon, command=lambda: mark_as_done(task_label, done_button), bg="#00b894", fg="#ffffff", font=font_small)
        done_button.pack(side=tk.RIGHT, padx=5)
        delete_button = tk.Button(task_frame, image=delete_icon, command=lambda: delete_task(task_frame), bg="#d63031", fg="#ffffff", font=font_small)
        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()
        canvas.update_idletasks()
        canvas.configure(scrollregion=canvas.bbox("all"))

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")
        if ". " in task_text:
            task_text = task_text.split(". ", 1)[1]
        task_label.config(text=f"{index + 1}. {task_text}")

def delete_all_tasks():
    for widget in task_container.winfo_children():
        widget.destroy()
    update_task_count()

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)

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 = ['#66bb6a', '#ef5350']
    explode = (0.05, 0)
    fig, ax = plt.subplots(figsize=(5, 3), dpi=100)
    fig.patch.set_facecolor('#1a1a2e')
    ax.set_facecolor('#1a1a2e')
    wedges, texts, autotexts = ax.pie(sizes, explode=explode, colors=colors, autopct='%1.1f%%',
                                     startangle=140, textprops=dict(color="w"))
    for text in texts:
        text.set_color('white')
        text.set_fontsize(12)
    for autotext in autotexts:
        autotext.set_color('white')
        autotext.set_fontsize(10)
    ax.axis('equal')
    ax.legend(wedges, labels, title="Tasks", loc="center left", bbox_to_anchor=(1, 0, 0.5, 1), fontsize=10, title_fontsize='13', facecolor='#1a1a2e', edgecolor='white')
    canvas_chart = FigureCanvasTkAgg(fig, master=pie_chart_frame)
    canvas_chart.draw()
    canvas_chart.get_tk_widget().pack()
    plt.close(fig)

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.")

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)
        update_task_count()
    except FileNotFoundError:
        pass

left_frame = tk.Frame(newWindow, bg="#1a1a2e")
left_frame.pack(side=tk.LEFT, fill=tk.BOTH, padx=10, pady=10, expand=True)

right_frame = tk.Frame(newWindow, bg="#1a1a2e")
right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, padx=10, pady=10, expand=True)

task_entry = tk.Entry(left_frame, width=35, bg="#162447", fg="#ffffff", font=font_large)
task_entry.pack(pady=10)

add_task_button = tk.Button(left_frame, text="Add Task", command=add_task, bg="#00a8cc", fg="#ffffff", font=font_small)
add_task_button.pack(pady=5)

delete_all_button = tk.Button(left_frame, text="Delete All Tasks", command=delete_all_tasks, bg="#d63031", fg="#ffffff", font=font_small)
delete_all_button.pack(pady=5)

save_button = tk.Button(left_frame, text="Save Tasks", command=save_tasks, bg="#4caf50", fg="#ffffff", font=font_small)
save_button.pack(pady=5)

load_button = tk.Button(left_frame, text="Load Tasks", command=load_tasks, bg="#ffc107", fg="#ffffff", font=font_small)
load_button.pack(pady=5)

total_tasks_label = tk.Label(left_frame, text="Total Tasks: 0", bg="#1a1a2e", fg="#00a8cc", font=font_medium)
total_tasks_label.pack(pady=2)

remaining_tasks_label = tk.Label(left_frame, text="Remaining Tasks: 0", bg="#1a1a2e", fg="#00cec9", font=font_medium)
remaining_tasks_label.pack(pady=2)

done_tasks_label = tk.Label(left_frame, text="Completed Tasks: 0", bg="#1a1a2e", fg="#00b894", font=font_medium)
done_tasks_label.pack(pady=2)

pie_chart_frame = tk.Frame(left_frame, bg="#1a1a2e")
pie_chart_frame.pack(pady=20, fill=tk.BOTH, expand=True)

canvas = tk.Canvas(right_frame, bg="#1a1a2e")
canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

scrollbar = tk.Scrollbar(right_frame, orient="vertical", command=canvas.yview)
scrollbar.pack(side=tk.RIGHT, fill="y")

canvas.configure(yscrollcommand=scrollbar.set)
canvas.bind('<Configure>', lambda e: canvas.configure(scrollregion=canvas.bbox("all")))

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

newWindow.mainloop()

Output :-

Leave a Comment

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

Scroll to Top