Skip to content

Instantly share code, notes, and snippets.

@pleabargain
Created October 28, 2024 12:13
Show Gist options
  • Save pleabargain/703edfff049974a5c952f939de4e26b9 to your computer and use it in GitHub Desktop.
Save pleabargain/703edfff049974a5c952f939de4e26b9 to your computer and use it in GitHub Desktop.
buy vs rent calculator written in python and tkinter
import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import json
from datetime import datetime
import numpy as np
# Help Documentation
HELP_TEXT = """
Buy vs. Rent Calculator
======================
Description:
-----------
This application helps users make informed decisions between buying and renting property by providing
comprehensive financial analysis. It considers various factors including purchase costs, monthly expenses,
rental costs, and long-term financial implications.
Key Features:
------------
1. Purchase Analysis:
- Calculate mortgage payments based on purchase price, down payment, and interest rate
- Include closing costs and initial investment requirements
- Multiple down payment scenario analysis
2. Monthly Expense Tracking:
- Property-related expenses (taxes, insurance, HOA)
- Living expenses (food, utilities, gas, miscellaneous)
- Maintenance and repair reserves
- PMI calculations for down payments < 20%
3. Rental Cost Analysis:
- Monthly rent calculations
- Rental insurance
- Utility costs
- Total annual rental expenses
4. Comparative Analysis:
- Long-term cost comparison
- Equity building analysis
- Property appreciation calculations
- Break-even point analysis
- Monthly cost differences
5. Data Management:
- Save analysis to JSON file
- Load previous analysis
- Multiple scenario comparisons
Usage Tips:
----------
1. Complete all sections in order: Purchase → Monthly Expenses → Rental → Analysis
2. Use realistic appreciation rates based on local market data
3. Include all monthly living expenses for accurate comparison
4. Consider multiple down payment scenarios
5. Save your analysis for future reference
Note: All monetary values should be entered as numbers without currency symbols or commas.
"""
class HousingCalculatorGUI:
def __init__(self, root):
self.root = root
self.root.title("Buy vs. Rent Calculator")
self.root.geometry("800x900")
# Configure style
style = ttk.Style()
style.configure('Header.TLabel', font=('Helvetica', 12, 'bold'))
# Initialize data dictionary
self.data = {
'analysis_date': datetime.now().strftime('%Y-%m-%d'),
'purchase': {},
'monthly_expenses': {},
'rental': {},
'comparative_analysis': {}
}
# Create notebook for tabs
self.notebook = ttk.Notebook(root)
self.notebook.pack(fill='both', expand=True, padx=10, pady=5)
# Create tabs
self.purchase_tab = ttk.Frame(self.notebook)
self.expenses_tab = ttk.Frame(self.notebook)
self.rental_tab = ttk.Frame(self.notebook)
self.analysis_tab = ttk.Frame(self.notebook)
self.notebook.add(self.purchase_tab, text='Purchase Details')
self.notebook.add(self.expenses_tab, text='Monthly Expenses')
self.notebook.add(self.rental_tab, text='Rental Costs')
self.notebook.add(self.analysis_tab, text='Analysis')
# Initialize variables
self.init_variables()
# Create forms
self.create_purchase_form()
self.create_expenses_form()
self.create_rental_form()
self.create_analysis_form()
# Create menu
self.create_menu()
def init_variables(self):
# Purchase variables
self.purchase_price = tk.StringVar(value="500000")
self.down_payment_percent = tk.StringVar(value="20")
self.interest_rate = tk.StringVar(value="6.5")
self.loan_term = tk.StringVar(value="30")
self.closing_cost_percent = tk.StringVar(value="3")
# Monthly expenses variables
self.property_tax_rate = tk.StringVar(value="1.5")
self.insurance_rate = tk.StringVar(value="0.5")
self.hoa_monthly = tk.StringVar(value="300")
self.utilities_monthly_owner = tk.StringVar(value="200")
# Rental variables
self.monthly_rent = tk.StringVar(value="2500")
self.rental_insurance = tk.StringVar(value="20")
self.utilities_monthly_renter = tk.StringVar(value="200")
# Analysis variables
self.appreciation_rate = tk.StringVar(value="3")
self.analysis_years = tk.StringVar(value="5")
# Add new monthly living expenses
self.food_expenses = tk.StringVar(value="600")
self.gas_expenses = tk.StringVar(value="200")
self.electricity_expenses = tk.StringVar(value="150")
self.misc_expenses = tk.StringVar(value="300")
# Multiple down payment analysis
self.down_payment_1 = tk.StringVar(value="40")
self.down_payment_2 = tk.StringVar(value="45")
self.down_payment_3 = tk.StringVar(value="50")
self.down_payment_4 = tk.StringVar(value="55")
self.down_payment_5 = tk.StringVar(value="60")
def create_labeled_entry(self, parent, label_text, variable, row, column=0, span=2, prefix="", suffix=""):
frame = ttk.Frame(parent)
frame.grid(row=row, column=column, columnspan=span, sticky='w', padx=5, pady=2)
ttk.Label(frame, text=label_text).pack(side='left')
if prefix:
ttk.Label(frame, text=prefix).pack(side='left')
ttk.Entry(frame, textvariable=variable, width=15).pack(side='left')
if suffix:
ttk.Label(frame, text=suffix).pack(side='left')
return frame
def create_purchase_form(self):
ttk.Label(self.purchase_tab, text="Purchase Details", font=('Helvetica', 12, 'bold')).grid(row=0, column=0, pady=10)
self.create_labeled_entry(self.purchase_tab, "Purchase Price:", self.purchase_price, 1, prefix="$")
self.create_labeled_entry(self.purchase_tab, "Down Payment:", self.down_payment_percent, 2, suffix="%")
self.create_labeled_entry(self.purchase_tab, "Interest Rate:", self.interest_rate, 3, suffix="%")
self.create_labeled_entry(self.purchase_tab, "Loan Term:", self.loan_term, 4, suffix="years")
self.create_labeled_entry(self.purchase_tab, "Closing Costs:", self.closing_cost_percent, 5, suffix="%")
ttk.Button(self.purchase_tab, text="Calculate Purchase Costs",
command=self.calculate_purchase_costs).grid(row=6, column=0, pady=20)
self.purchase_result = ttk.Label(self.purchase_tab, text="")
self.purchase_result.grid(row=7, column=0, columnspan=2, sticky='w', padx=5)
def create_expenses_form(self):
ttk.Label(self.expenses_tab, text="Monthly Expenses", font=('Helvetica', 12, 'bold')).grid(row=0, column=0, pady=10)
self.create_labeled_entry(self.expenses_tab, "Property Tax Rate:", self.property_tax_rate, 1, suffix="%")
self.create_labeled_entry(self.expenses_tab, "Insurance Rate:", self.insurance_rate, 2, suffix="%")
self.create_labeled_entry(self.expenses_tab, "HOA Fees:", self.hoa_monthly, 3, prefix="$")
self.create_labeled_entry(self.expenses_tab, "Monthly Utilities:", self.utilities_monthly_owner, 4, prefix="$")
ttk.Button(self.expenses_tab, text="Calculate Monthly Expenses",
command=self.calculate_monthly_expenses).grid(row=5, column=0, pady=20)
self.expenses_result = ttk.Label(self.expenses_tab, text="")
self.expenses_result.grid(row=6, column=0, columnspan=2, sticky='w', padx=5)
self.create_living_expenses_form()
# Add a new method for multiple down payment analysis:
def create_down_payment_analysis_form(self):
frame = ttk.LabelFrame(self.analysis_tab, text="Multiple Down Payment Analysis")
frame.grid(row=5, column=0, columnspan=2, sticky='nsew', padx=5, pady=10)
self.create_labeled_entry(frame, "Down Payment 1:", self.down_payment_1, 0, suffix="%")
self.create_labeled_entry(frame, "Down Payment 2:", self.down_payment_2, 1, suffix="%")
self.create_labeled_entry(frame, "Down Payment 3:", self.down_payment_3, 2, suffix="%")
self.create_labeled_entry(frame, "Down Payment 4:", self.down_payment_4, 3, suffix="%")
self.create_labeled_entry(frame, "Down Payment 5:", self.down_payment_5, 4, suffix="%")
ttk.Button(frame, text="Compare Down Payments",
command=self.analyze_multiple_down_payments).grid(row=5, column=0, pady=10)
# Add method to analyze multiple down payments:
def analyze_multiple_down_payments(self):
try:
if not self.data.get('purchase'):
messagebox.showerror("Error", "Please calculate purchase costs first.")
return
down_payments = [
float(self.down_payment_1.get()),
float(self.down_payment_2.get()),
float(self.down_payment_3.get()),
float(self.down_payment_4.get()),
float(self.down_payment_5.get())
]
analysis_text = "Multiple Down Payment Analysis:\n"
analysis_text += "-" * 50 + "\n\n"
for dp in down_payments:
# Calculate costs with this down payment
purchase_price = float(self.purchase_price.get())
down_payment = purchase_price * (dp / 100)
loan_amount = purchase_price - down_payment
monthly_payment = self.calculate_mortgage_payment(
loan_amount,
float(self.interest_rate.get())/100,
float(self.loan_term.get())
)
# Calculate ROI
total_investment = down_payment + float(self.closing_cost_percent.get())/100 * purchase_price
monthly_expenses = monthly_payment + sum([
float(self.food_expenses.get()),
float(self.gas_expenses.get()),
float(self.electricity_expenses.get()),
float(self.misc_expenses.get())
])
yearly_expenses = monthly_expenses * 12
appreciation = purchase_price * (float(self.appreciation_rate.get())/100)
# First year ROI
first_year_roi = ((appreciation - yearly_expenses) / total_investment) * 100
analysis_text += f"Down Payment: {dp}%\n"
analysis_text += f"Down Payment Amount: ${down_payment:,.2f}\n"
analysis_text += f"Loan Amount: ${loan_amount:,.2f}\n"
analysis_text += f"Monthly Payment: ${monthly_payment:,.2f}\n"
analysis_text += f"Total Monthly Expenses: ${monthly_expenses:,.2f}\n"
analysis_text += f"Total Investment: ${total_investment:,.2f}\n"
analysis_text += f"First Year ROI: {first_year_roi:.2f}%\n"
analysis_text += "-" * 30 + "\n\n"
self.analysis_result.insert(tk.END, "\n" + analysis_text)
except ValueError as e:
messagebox.showerror("Error", "Please enter valid numbers for all fields.")
# Add a new method for creating the living expenses form:
def create_living_expenses_form(self):
frame = ttk.LabelFrame(self.expenses_tab, text="Monthly Living Expenses")
frame.grid(row=7, column=0, columnspan=2, sticky='nsew', padx=5, pady=10)
self.create_labeled_entry(frame, "Food:", self.food_expenses, 0, prefix="$")
self.create_labeled_entry(frame, "Gas:", self.gas_expenses, 1, prefix="$")
self.create_labeled_entry(frame, "Electricity:", self.electricity_expenses, 2, prefix="$")
self.create_labeled_entry(frame, "Miscellaneous:", self.misc_expenses, 3, prefix="$")
def create_rental_form(self):
ttk.Label(self.rental_tab, text="Rental Costs", font=('Helvetica', 12, 'bold')).grid(row=0, column=0, pady=10)
self.create_labeled_entry(self.rental_tab, "Monthly Rent:", self.monthly_rent, 1, prefix="$")
self.create_labeled_entry(self.rental_tab, "Rental Insurance:", self.rental_insurance, 2, prefix="$")
self.create_labeled_entry(self.rental_tab, "Monthly Utilities:", self.utilities_monthly_renter, 3, prefix="$")
ttk.Button(self.rental_tab, text="Calculate Rental Costs",
command=self.calculate_rental_costs).grid(row=4, column=0, pady=20)
self.rental_result = ttk.Label(self.rental_tab, text="")
self.rental_result.grid(row=5, column=0, columnspan=2, sticky='w', padx=5)
def create_analysis_form(self):
ttk.Label(self.analysis_tab, text="Comparative Analysis",
style='Header.TLabel').grid(row=0, column=0, pady=10)
self.create_labeled_entry(self.analysis_tab, "Appreciation Rate:",
self.appreciation_rate, 1, suffix="%")
self.create_labeled_entry(self.analysis_tab, "Analysis Period:",
self.analysis_years, 2, suffix="years")
ttk.Button(self.analysis_tab, text="Run Analysis",
command=self.run_comparative_analysis).grid(row=3, column=0, pady=20)
# Create Text widget with scrollbar
frame = ttk.Frame(self.analysis_tab)
frame.grid(row=4, column=0, columnspan=2, sticky='nsew', padx=5)
# Add scrollbar
scrollbar = ttk.Scrollbar(frame)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
# Create Text widget from tk, not ttk
self.analysis_result = tk.Text(frame, height=20, width=70,
yscrollcommand=scrollbar.set)
self.analysis_result.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
# Configure scrollbar
scrollbar.config(command=self.analysis_result.yview)
# Configure tag for better formatting
self.analysis_result.tag_configure('bold', font=('Helvetica', 10, 'bold'))
self.create_down_payment_analysis_form()
def create_menu(self):
menubar = tk.Menu(self.root)
self.root.config(menu=menubar)
file_menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label="File", menu=file_menu)
file_menu.add_command(label="Save Analysis", command=self.save_to_json)
file_menu.add_command(label="Load Analysis", command=self.load_from_json)
file_menu.add_separator()
file_menu.add_command(label="Exit", command=self.root.quit)
def calculate_mortgage_payment(self, principal, annual_rate, years):
"""Calculate monthly mortgage payment"""
r = annual_rate / 12 # Monthly interest rate
n = years * 12 # Total number of payments
return principal * (r * (1 + r)**n) / ((1 + r)**n - 1)
def calculate_purchase_costs(self):
try:
purchase_price = float(self.purchase_price.get())
down_payment_percent = float(self.down_payment_percent.get())
annual_rate = float(self.interest_rate.get())
loan_years = float(self.loan_term.get())
closing_cost_percent = float(self.closing_cost_percent.get())
down_payment = purchase_price * (down_payment_percent / 100)
loan_amount = purchase_price - down_payment
closing_costs = purchase_price * (closing_cost_percent / 100)
monthly_payment = self.calculate_mortgage_payment(loan_amount, annual_rate/100, loan_years)
self.data['purchase'] = {
'purchase_price': purchase_price,
'down_payment': down_payment,
'loan_amount': loan_amount,
'annual_interest_rate': annual_rate,
'loan_term_years': loan_years,
'closing_costs': closing_costs,
'monthly_mortgage_payment': monthly_payment,
'total_initial_costs': down_payment + closing_costs
}
result_text = f"""
Purchase Summary:
----------------
Down Payment: ${down_payment:,.2f}
Loan Amount: ${loan_amount:,.2f}
Closing Costs: ${closing_costs:,.2f}
Monthly Mortgage Payment: ${monthly_payment:,.2f}
Total Initial Costs: ${(down_payment + closing_costs):,.2f}
"""
self.purchase_result.config(text=result_text)
except ValueError as e:
messagebox.showerror("Error", "Please enter valid numbers for all fields.")
def calculate_monthly_expenses(self):
try:
if not self.data.get('purchase'):
messagebox.showerror("Error", "Please calculate purchase costs first.")
return
purchase_price = self.data['purchase']['purchase_price']
down_payment = self.data['purchase']['down_payment']
property_tax_rate = float(self.property_tax_rate.get())
insurance_rate = float(self.insurance_rate.get())
hoa_monthly = float(self.hoa_monthly.get())
utilities_monthly = float(self.utilities_monthly_owner.get())
# Get monthly living expenses
monthly_living_expenses = sum([
float(self.food_expenses.get()),
float(self.gas_expenses.get()),
float(self.electricity_expenses.get()),
float(self.misc_expenses.get())
])
# Calculate PMI if down payment is less than 20%
pmi = (purchase_price - down_payment) * 0.01 / 12 if down_payment/purchase_price < 0.2 else 0
# Update monthly expenses dictionary to include living expenses
self.data['monthly_expenses'] = {
'mortgage_payment': self.data['purchase']['monthly_mortgage_payment'],
'property_tax': (purchase_price * property_tax_rate/100) / 12,
'insurance': (purchase_price * insurance_rate/100) / 12,
'hoa_fees': hoa_monthly,
'pmi': pmi,
'utilities': utilities_monthly,
'maintenance_reserve': (purchase_price * 0.01) / 12,
'repair_reserve': (purchase_price * 0.005) / 12,
'living_expenses': monthly_living_expenses # Add living expenses
}
# Calculate total including all expenses
total_monthly = sum(self.data['monthly_expenses'].values())
result_text = f"""
Monthly Expenses Summary:
----------------------
Mortgage Payment: ${self.data['monthly_expenses']['mortgage_payment']:,.2f}
Property Tax: ${self.data['monthly_expenses']['property_tax']:,.2f}
Insurance: ${self.data['monthly_expenses']['insurance']:,.2f}
HOA Fees: ${hoa_monthly:,.2f}
PMI: ${pmi:,.2f}
Utilities: ${utilities_monthly:,.2f}
Maintenance Reserve: ${self.data['monthly_expenses']['maintenance_reserve']:,.2f}
Repair Reserve: ${self.data['monthly_expenses']['repair_reserve']:,.2f}
Living Expenses: ${monthly_living_expenses:,.2f}
Total Monthly: ${total_monthly:,.2f}
"""
self.expenses_result.config(text=result_text)
except ValueError as e:
messagebox.showerror("Error", "Please enter valid numbers for all fields.")
def calculate_rental_costs(self):
try:
monthly_rent = float(self.monthly_rent.get())
insurance = float(self.rental_insurance.get())
utilities = float(self.utilities_monthly_renter.get())
total_monthly = monthly_rent + insurance + utilities
self.data['rental'] = {
'monthly_rent': monthly_rent,
'insurance': insurance,
'utilities': utilities,
'total_monthly': total_monthly,
'total_annual': total_monthly * 12
}
result_text = f"""
Rental Costs Summary:
-------------------
Monthly Rent: ${monthly_rent:,.2f}
Insurance: ${insurance:,.2f}
Utilities: ${utilities:,.2f}
Total Monthly: ${total_monthly:,.2f}
Total Annual: ${(total_monthly * 12):,.2f}
"""
self.rental_result.config(text=result_text)
except ValueError as e:
messagebox.showerror("Error", "Please enter valid numbers for all fields.")
def run_comparative_analysis(self):
try:
if not all([self.data.get('purchase'), self.data.get('monthly_expenses'), self.data.get('rental')]):
messagebox.showerror("Error", "Please calculate all costs first.")
return
appreciation_rate = float(self.appreciation_rate.get())
years = float(self.analysis_years.get())
purchase_price = self.data['purchase']['purchase_price']
loan_amount = self.data['purchase']['loan_amount']
annual_rate = self.data['purchase']['annual_interest_rate']
# Calculate equity building through principal payments
monthly_rate = annual_rate / (100 * 12)
loan_months = self.data['purchase']['loan_term_years'] * 12
principal_payment = loan_amount * (monthly_rate * (1 + monthly_rate)**loan_months) / \
((1 + monthly_rate)**loan_months - 1) - loan_amount * monthly_rate
# Add living expenses to monthly costs
monthly_living_expenses = sum([
float(self.food_expenses.get()),
float(self.gas_expenses.get()),
float(self.electricity_expenses.get()),
float(self.misc_expenses.get())
])
buying_total_costs = (sum(self.data['monthly_expenses'].values()) + monthly_living_expenses) * 12 * years
rental_total_costs = (self.data['rental']['total_monthly'] + monthly_living_expenses) * 12 * years
buying_total_costs = sum(self.data['monthly_expenses'].values()) * 12 * years
rental_total_costs = self.data['rental']['total_monthly'] * 12 * years
equity_built = principal_payment * 12 * years
appreciation = purchase_price * (((1 + appreciation_rate/100)**years) - 1)
buying_net = equity_built + appreciation - buying_total_costs
renting_net = -rental_total_costs
self.data['comparative_analysis'] = {
'years_analyzed': years,
'appreciation_rate': appreciation_rate,
'buying': {
'total_costs': buying_total_costs,
'equity_built': equity_built,
'appreciation': appreciation,
'net_position': buying_net
},
'renting': {
'total_costs': rental_total_costs,
'equity_built': 0,
'appreciation': 0,
'net_position': renting_net
},
'net_difference': buying_net - renting_net
}
analysis_text = f"""
Comparative Analysis Summary ({years} Years):
----------------------------------------
BUYING:
Total Costs: ${buying_total_costs:,.2f}
Equity Built: ${equity_built:,.2f}
Property Appreciation: ${appreciation:,.2f}
Net Position: ${buying_net:,.2f}
RENTING:
Total Costs: ${rental_total_costs:,.2f}
Equity Built: $0.00
Property Appreciation: $0.00
Net Position: ${renting_net:,.2f}
COMPARISON:
Net Difference (Buying vs Renting): ${(buying_net - renting_net):,.2f}
Monthly Comparison:
-----------------
Monthly Cost of Buying: ${(sum(self.data['monthly_expenses'].values())):,.2f}
Monthly Cost of Renting: ${self.data['rental']['total_monthly']:,.2f}
Monthly Difference: ${(sum(self.data['monthly_expenses'].values()) - self.data['rental']['total_monthly']):,.2f}
Break-Even Analysis:
------------------
Years to Break Even: {abs(buying_total_costs/(buying_net - renting_net)):,.1f}
Additional Insights:
-----------------
• The buying scenario {' is ' if buying_net > renting_net else ' is not '} financially advantageous over {years} years
• Property appreciation accounts for ${appreciation:,.2f} of the buying benefit
• Monthly ownership costs are ${abs(sum(self.data['monthly_expenses'].values()) - self.data['rental']['total_monthly']):,.2f} {'higher' if sum(self.data['monthly_expenses'].values()) > self.data['rental']['total_monthly'] else 'lower'} than renting
"""
self.analysis_result.delete(1.0, tk.END)
self.analysis_result.insert(tk.END, analysis_text)
except ValueError as e:
messagebox.showerror("Error", "Please enter valid numbers for all fields.")
except ZeroDivisionError:
messagebox.showerror("Error", "Cannot calculate break-even point - costs are equal.")
def save_to_json(self):
try:
filename = tk.filedialog.asksaveasfilename(
defaultextension=".json",
filetypes=[("JSON files", "*.json"), ("All files", "*.*")],
title="Save Analysis As"
)
if filename:
with open(filename, 'w') as f:
json.dump(self.data, f, indent=4)
messagebox.showinfo("Success", "Analysis saved successfully!")
except Exception as e:
messagebox.showerror("Error", f"Error saving file: {str(e)}")
def load_from_json(self):
try:
filename = tk.filedialog.askopenfilename(
filetypes=[("JSON files", "*.json"), ("All files", "*.*")],
title="Load Analysis"
)
if filename:
with open(filename, 'r') as f:
self.data = json.load(f)
self.update_forms_from_data()
messagebox.showinfo("Success", "Analysis loaded successfully!")
except Exception as e:
messagebox.showerror("Error", f"Error loading file: {str(e)}")
def update_forms_from_data(self):
"""Update all form fields from loaded data"""
if 'purchase' in self.data:
self.purchase_price.set(str(self.data['purchase']['purchase_price']))
self.down_payment_percent.set(str(self.data['purchase']['down_payment'] /
self.data['purchase']['purchase_price'] * 100))
self.interest_rate.set(str(self.data['purchase']['annual_interest_rate']))
self.loan_term.set(str(self.data['purchase']['loan_term_years']))
self.calculate_purchase_costs()
if 'monthly_expenses' in self.data:
self.property_tax_rate.set(str(self.data['monthly_expenses']['property_tax'] * 12 /
self.data['purchase']['purchase_price'] * 100))
self.insurance_rate.set(str(self.data['monthly_expenses']['insurance'] * 12 /
self.data['purchase']['purchase_price'] * 100))
self.hoa_monthly.set(str(self.data['monthly_expenses']['hoa_fees']))
self.utilities_monthly_owner.set(str(self.data['monthly_expenses']['utilities']))
self.calculate_monthly_expenses()
if 'rental' in self.data:
self.monthly_rent.set(str(self.data['rental']['monthly_rent']))
self.rental_insurance.set(str(self.data['rental']['insurance']))
self.utilities_monthly_renter.set(str(self.data['rental']['utilities']))
self.calculate_rental_costs()
if 'comparative_analysis' in self.data:
self.appreciation_rate.set(str(self.data['comparative_analysis']['appreciation_rate']))
self.analysis_years.set(str(self.data['comparative_analysis']['years_analyzed']))
self.run_comparative_analysis()
def main():
root = tk.Tk()
app = HousingCalculatorGUI(root)
root.mainloop()
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment