import json
import tkinter as tk
from tkinter import messagebox
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg # To embed the graph in tkinter
class Expense:
def __init__(self, category, amount, spender):
self.category = category
self.amount = amount
self.spender = spender # New attribute to track who spent the money
class MonthlyBudget:
def __init__(self, salary):
self.salary = salary
self.expenses = []
self.balance = salary # Initial balance is the salary
def add_expense(self, category, amount, spender):
""" Add an expense and deduct from the house balance """
if amount > 0:
if amount <= self.balance:
self.expenses.append(Expense(category, amount, spender))
self.balance -= amount # Deduct expense from balance
return f"Added expense: {category} - {amount} by {spender}. Remaining balance:
{self.balance}."
else:
return "Not enough balance for this expense."
else:
return "Expense amount must be positive."
def display_expenses(self):
""" Display a summary of all expenses and balance """
summary = "--- Expense Summary ---\n"
total_expense = 0
for expense in self.expenses:
summary += f"{expense.spender} spent on {expense.category}: {expense.amount}\n"
total_expense += expense.amount
summary += f"\nTotal expenses: {total_expense}\n"
summary += f"Remaining balance: {self.balance}"
return summary
def plot_expenses(self, root):
""" Plot expenses using a pie chart """
if not self.expenses:
messagebox.showinfo("Visualization", "No expenses to display. Add some expenses first.")
return
categories = [expense.category for expense in self.expenses]
amounts = [expense.amount for expense in self.expenses]
# Create a new figure and plot
fig, ax = plt.subplots(figsize=(8, 6))
ax.pie(amounts, labels=categories, autopct='%1.1f%%', startangle=140)
ax.set_title("Expense Distribution")
ax.axis('equal') # Equal aspect ratio ensures the pie chart is circular
# Embed the plot into the tkinter window
canvas = FigureCanvasTkAgg(fig, master=root) # A Tkinter canvas to display the plot
canvas.draw()
canvas.get_tk_widget().grid(row=4, column=0, columnspan=2) # Place the canvas in grid layout
def save_data(self, filename="monthly_budget.json"):
""" Save data to a file """
data = {
"salary": self.salary,
"expenses": [{"category": exp.category, "amount": exp.amount, "spender": exp.spender} for exp
in self.expenses],
"balance": self.balance
with open(filename, "w") as f:
json.dump(data, f, indent=4)
messagebox.showinfo("Save Data", "Budget data saved successfully.")
def load_data(self, filename="monthly_budget.json"):
""" Load data from a file """
try:
with open(filename, "r") as f:
data = json.load(f)
self.salary = data["salary"]
self.balance = data["balance"]
self.expenses = [Expense(exp["category"], exp["amount"], exp["spender"]) for exp in
data["expenses"]]
except FileNotFoundError:
self.salary = 0
self.expenses = []
self.balance = 0
def add_balance(self, amount):
""" Allow user to add money to the balance """
if amount > 0:
self.balance += amount
return f"Balance updated. New balance: {self.balance}"
else:
return "Amount must be positive to add to the balance."
def create_gui():
""" Create the GUI for the expense tracker """
# Initialize budget
budget = MonthlyBudget(0)
budget.load_data()
if budget.salary == 0:
salary = float(input("Enter your monthly salary: "))
budget.salary = salary
budget.balance = salary # Set the house balance to salary initially
def add_expense():
""" Add an expense """
category = category_var.get()
spender = spender_entry.get() # Get the spender's name from the input field
try:
amount = float(amount_entry.get())
if not spender:
messagebox.showerror("Input Error", "Please enter the spender's name.")
return
result = budget.add_expense(category, amount, spender)
messagebox.showinfo("Add Expense", result)
amount_entry.delete(0, tk.END)
spender_entry.delete(0, tk.END)
update_balance_label() # Update balance label after adding an expense
except ValueError:
messagebox.showerror("Input Error", "Please enter a valid amount.")
def show_expenses():
""" Show all expenses """
summary = budget.display_expenses()
messagebox.showinfo("Expense Summary", summary)
def visualize_expenses():
""" Show expenses graphically """
# Clear any previous plot before showing new one
for widget in root.grid_slaves():
if isinstance(widget, tk.Canvas):
widget.grid_forget()
# Show updated graph
budget.plot_expenses(root)
def save_and_exit():
""" Save data and exit """
budget.save_data()
root.destroy()
def add_balance():
""" Add money to the balance """
try:
amount = float(balance_entry.get())
result = budget.add_balance(amount)
messagebox.showinfo("Add Balance", result)
balance_entry.delete(0, tk.END)
update_balance_label() # Update balance label after adding money
except ValueError:
messagebox.showerror("Input Error", "Please enter a valid amount.")
def update_balance_label():
""" Update the balance display label """
balance_label.config(text=f"Current Balance: {budget.balance}")
# Create main window
root = tk.Tk()
root.title("Expense Tracker")
# Labels and Inputs
tk.Label(root, text="Expense Category:").grid(row=0, column=0, padx=10, pady=10)
category_var = tk.StringVar(root)
category_var.set("Groceries") # Default category
categories = ["Tax", "Groceries", "Children's School Fees", "Rent", "Utilities", "Entertainment",
"Savings"]
category_menu = tk.OptionMenu(root, category_var, *categories)
category_menu.grid(row=0, column=1, padx=10, pady=10)
tk.Label(root, text="Amount:").grid(row=1, column=0, padx=10, pady=10)
amount_entry = tk.Entry(root)
amount_entry.grid(row=1, column=1, padx=10, pady=10)
tk.Label(root, text="Spender's Name:").grid(row=2, column=0, padx=10, pady=10)
spender_entry = tk.Entry(root)
spender_entry.grid(row=2, column=1, padx=10, pady=10)
# Display Current Balance
balance_label = tk.Label(root, text=f"Current Balance: {budget.balance}")
balance_label.grid(row=5, column=0, columnspan=2, pady=10)
tk.Label(root, text="Add Balance:").grid(row=6, column=0, padx=10, pady=10)
balance_entry = tk.Entry(root)
balance_entry.grid(row=6, column=1, padx=10, pady=10)
# Buttons
tk.Button(root, text="Add Expense", command=add_expense).grid(row=3, column=0, padx=10,
pady=10)
tk.Button(root, text="Show Expenses", command=show_expenses).grid(row=3, column=1, padx=10,
pady=10)
tk.Button(root, text="Visualize Expenses", command=visualize_expenses).grid(row=4, column=0,
padx=10, pady=10)
tk.Button(root, text="Save and Exit", command=save_and_exit).grid(row=4, column=1, padx=10,
pady=10)
tk.Button(root, text="Add Balance", command=add_balance).grid(row=7, column=0, columnspan=2,
pady=10)
root.mainloop()
if __name__ == "__main__":
create_gui()