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 :-