项目名称:个人开支管理系统
-
项目简介
开发一个简单的个人开支管理系统,帮助用户记录和管理日常开支。该系统应具备记录开支、查看开支、计算总支出和删除记录等基本功能。
-
项目需求
1. 用户界面
- 提供简易的命令行界面供用户操作。
- 用户可以选择不同的操作:记录开支、查看开支、计算总支出、删除记录和退出程序。
2. 功能模块
a.记录开支
- 用户输入开支金额、类别(如食品、交通、娱乐等)和日期。
- 将记录保存到一个数据结构中(如列表)。
b.查看开支
- 显示所有已记录的开支。
- 每条记录包括金额、类别和日期。
c.计算总支出
- 计算并显示用户的总支出金额。
d.删除记录
- 用户可以按日期或类别删除特定的开支记录。
e.退出程序
- 用户选择退出程序后,系统保存所有开支记录到一个文件中,以便下次启动时读取。
3. 数据存储
使用文本文件保存和读取开支记录,确保数据在程序关闭后不丢失。
-
项目步骤
1. 初始化项目
- 创建一个新的Python项目文件。
- 创建必要的函数和数据结构(如列表、字典等)。
2. 实现功能模块
- 编写记录开支的函数,提示用户输入必要信息,并保存到数据结构中。
- 编写查看开支的函数,遍历数据结构并打印所有记录。
- 编写计算总支出的函数,遍历数据结构并累计总金额。
- 编写删除记录的函数,根据用户输入的条件(日期或类别)删除相应记录。
- 编写文件读写函数,在程序启动时读取文件并加载记录,在程序退出时保存记录到文件。
3. 用户交互界面
- 使用循环结构创建用户交互界面,根据用户选择调用相应的功能模块。
- 提供明确的提示信息和错误处理机制,确保用户输入的有效性。
4. 测试和调试
- 对每个功能模块进行单独测试,确保其正确性。
- 测试整个系统的工作流程,检查各功能模块之间的交互是否正常。
- 处理可能出现的异常情况,如文件读写错误、用户输入错误等。
-
项目扩展
完成基本功能后,可以考虑添加以下扩展功能,完成者将获得更高评分。
- 按月份或类别生成开支报告。
- 支持多用户的开支管理。
- 图形用户界面(GUI)实现,使用如Tkinter等库。
实验器材、设备和平台
- 计算机
- 操作系统:Windows、macOS或Linux
- 编程语言:Python 3.x
- 开发环境:任意Python集成开发环境(IDE),例如PyCharm、VSCode,或文本编辑器如Sublime Text
- 必要的Python库:标准库Tkinter、json、os
接下来,将代码划分成各个模块,解释说明其功能与实现。
部分 1: 导入库,初始化全局变量
import json
import os
from datetime import datetime
import tkinter as tk
from tkinter import messagebox, simpledialog
data_file = "expenses.json"
users = {}
current_user = None
import json
和import os
:用于数据的持久化和文件操作。from datetime import datetime
:日期处理。import tkinter as tk
和from tkinter import messagebox, simpledialog
:用于创建图形用户界面。data_file
:指定存储数据的文件名。users
:存储所有用户及其开支记录的字典。current_user
:当前登录的用户。
部分 2: 数据加载和保存
# 从json文件加载用户数据
def load_data():
global users
if os.path.exists(data_file):
with open(data_file, 'r') as file:
users = json.load(file)
# 将用户数据保存到json文件中
def save_data():
with open(data_file, 'w') as file:
json.dump(users, file)
load_data
函数:从JSON文件加载用户数据。save_data
函数:将用户数据保存到JSON文件。
部分 3: 用户登录
# 用户登录。如若没有则创建用户
def login():
global current_user
username = simpledialog.askstring("登录", "请输入用户名:")
if username:
if username not in users:
users[username] = []
current_user = username
main_menu()
login
函数:提示用户输入用户名。如果用户名不存在,则创建新的用户记录。调用main_menu()
函数显示主菜单。
部分 4: 记录开支
# 将用户输入的信息记录到当前用户的开支列表中,如若日期的格式错误,将记录失败
def record_expense():
money = simpledialog.askfloat("记录开支", "花了多少?:")
if money is None:
return
kinds = simpledialog.askstring("记录开支", "干什么了?(食品?交通?娱乐?):")
if kinds is None:
return
date_str = simpledialog.askstring("记录开支", "啥时候花的?(例:2024-05-26):")
try:
if date_str is None:
return
date = datetime.strptime(date_str, "%Y-%m-%d")
expense = {
"money": money,
"kinds": kinds,
"date": date_str
}
users[current_user].append(expense)
messagebox.showinfo("提示", "记录已保存!")
except Exception as V:
messagebox.showerror("错误", "日期输错了!记录失败!!!")
record_expense
函数:提示用户输入开支信息,并将其记录到当前用户的开支列表中。使用try-except
块捕获日期格式错误。
部分 5: 查看开支
# 用户开支的查看
def cat_expenses():
expenses_str = "\n".join(
[f"金额: {expense['money']}, 类别: {expense['kinds']}, 日期: {expense['date']}" for expense in users[current_user]]
)
if expenses_str:
messagebox.showinfo("查看开支", expenses_str)
else:
messagebox.showinfo("查看开支", "当前无开支记录")
cat_expenses
函数:显示当前用户的所有开支记录,通过消息框 (messagebox.showinfo
) 显示结果。
部分 6: 计算总支出
# 用户总开支的查看
def total_expense():
total = sum(expense['money'] for expense in users[current_user])
messagebox.showinfo("总支出", f"总支出金额: {total}")
total_expense
函数:计算并输出当前用户的总支出金额,通过消息框 (messagebox.showinfo
) 显示结果。
部分 7: 删除记录
# 按照用户指定的条件(日期或类别)删除相应的记录。
def delete_expense():
option = simpledialog.askstring("删除开支", "想怎样删除?(1: 按日期, 2: 按类别):")
if option == '1':
date_str = simpledialog.askstring("删除开支", "删除哪天?(例:2024-05-26):")
if date_str:
users[current_user] = [expense for expense in users[current_user] if expense['date'] != date_str]
messagebox.showinfo("提示", "记录删除成功!")
elif option == '2':
category = simpledialog.askstring("删除开支", "删除哪一类:")
if category:
users[current_user] = [expense for expense in users[current_user] if expense['category'] != category]
messagebox.showinfo("提示", "删除成功!")
else:
messagebox.showerror("错误", "无效删除方式!!!")
delete_expense
函数:按照用户指定的条件(日期或类别)删除相应的开支记录。使用消息框显示操作结果。
部分 8: 生成报告
'''
根据用户选择,按月份或类别生成并显示开支报告。
按月份统计:截取日期字符串的前7位(如"2024-05")。
按类别统计:根据类别分类汇总支出。
'''
def generate_report():
option = simpledialog.askstring("生成报告", "选择生成报告的方式(1: 按月份, 2: 按类别):")
report = {}
if option == '1':
for expense in users[current_user]:
month = expense['date'][:7]
if month not in report:
report[month] = 0
report[month] += expense['money']
elif option == '2':
for expense in users[current_user]:
kinds = expense['kinds']
if kinds not in report:
report[kinds] = 0
report[kinds] += expense['money']
report_str = "\n".join([f"{key}: {report[key]}" for key in report])
messagebox.showinfo("报告", report_str)
generate_report
函数:根据用户选择,按月份或类别生成并显示开支报告。通过消息框 (messagebox.showinfo
) 显示结果。- 按月份统计:截取日期字符串的前7位(如"2024-05")。
- 按类别统计:根据类别分类汇总支出。
部分 9: 主菜单
'''程序的入口,负责加载数据,用户登录,显示操作菜单以及根据用户选择调用相应功能模块。
while循环用来提供持续的用户交互,直到用户选择退出。'''
def main_menu():
# root.withdraw() # 隐藏登录窗口
menu = tk.Tk()
menu.title("个人开支管理系统")
tk.Label(menu, text=f"当前用户: {current_user}", font=("Arial", 30)).pack(pady=30)
tk.Button(menu, text="记录开支", command=record_expense, width=30).pack(pady=30)
tk.Button(menu, text="查看开支", command=cat_expenses, width=30).pack(pady=30)
tk.Button(menu, text="计算总支出", command=total_expense, width=30).pack(pady=30)
tk.Button(menu, text="删除记录", command=delete_expense, width=30).pack(pady=30)
tk.Button(menu, text="生成报告", command=generate_report, width=30).pack(pady=30)
tk.Button(menu, text="退出并保存", command=lambda: [save_data(), menu.destroy(), root.deiconify()], width=30).pack(pady=30)
menu.mainloop()
main_menu
函数:程序的入口,负责加载数据,用户登录,显示操作菜单以及根据用户选择调用相应功能模块。使用tk.Tk
创建主菜单窗口,包含多个按钮,每个按钮绑定一个功能函数。
部分 10: 主窗口和登录界面
# 主窗口和登录界面及函数的调用
root = tk.Tk()
root.title("个人开支管理系统")
tk.Button(root, text="登录", command=login, width=50).pack(pady=50)
root.mainloop()
- 在程序启动时显示登录窗口 (
root
),用户登录后进入主菜单 (main_menu
)。 tk.Button
创建一个登录按钮,点击后调用login
函数。通过root.mainloop()
运行Tkinter事件循环,保持界面响应。
项目完整代码如下:
# 部分库的导入以及全局变量的初始化
import json
import os
from datetime import datetime
import tkinter as tk
from tkinter import messagebox, simpledialog
data_file = "expenses.json"
users = {}
current_user = None
# 从json文件加载用户数据
def load_data():
global users
if os.path.exists(data_file):
with open(data_file, 'r') as file:
users = json.load(file)
# 将用户数据保存到json文件中
def save_data():
with open(data_file, 'w') as file:
json.dump(users, file)
# 用户登录。如若没有则创建用户
def login():
global current_user
username = simpledialog.askstring("登录", "请输入用户名:")
if username:
if username not in users:
users[username] = []
current_user = username
main_menu()
# 将用户输入的信息记录到当前用户的开支列表中,如若日期的格式错误,将记录失败
def record_expense():
money = simpledialog.askfloat("记录开支", "花了多少?:")
if money is None:
return
kinds = simpledialog.askstring("记录开支", "干什么了?(食品?交通?娱乐?):")
if kinds is None:
return
date_str = simpledialog.askstring("记录开支", "啥时候花的?(例:2024-05-26):")
try:
if date_str is None:
return
date = datetime.strptime(date_str, "%Y-%m-%d")
expense = {
"money": money,
"kinds": kinds,
"date": date_str
}
users[current_user].append(expense)
messagebox.showinfo("提示", "记录已保存!")
except Exception as V:
messagebox.showerror("错误", "日期输错了!记录失败!!!")
# 用户开支的查看
def cat_expenses():
expenses_str = "\n".join(
[f"金额: {expense['money']}, 类别: {expense['kinds']}, 日期: {expense['date']}" for expense in
users[current_user]]
)
if expenses_str:
messagebox.showinfo("查看开支", expenses_str)
else:
messagebox.showinfo("查看开支", "当前无开支记录")
# 用户总开支的查看
def total_expense():
total = sum(expense['money'] for expense in users[current_user])
messagebox.showinfo("总支出", f"总支出金额: {total}")
# 按照用户指定的条件(日期或类别)删除相应的记录。
def delete_expense():
option = simpledialog.askstring("删除开支", "想怎样删除?(1: 按日期, 2: 按类别):")
if option == '1':
date_str = simpledialog.askstring("删除开支", "删除哪天?(例:2024-05-26):")
if date_str:
users[current_user] = [expense for expense in users[current_user] if expense['date'] != date_str]
messagebox.showinfo("提示", "记录删除成功!")
elif option == '2':
category = simpledialog.askstring("删除开支", "删除哪一类:")
if category:
users[current_user] = [expense for expense in users[current_user] if expense['category'] != category]
messagebox.showinfo("提示", "删除成功!")
else:
messagebox.showerror("错误", "无效删除方式!!!")
'''
根据用户选择,按月份或类别生成并显示开支报告。
按月份统计:截取日期字符串的前7位(如"2024-05")。
按类别统计:根据类别分类汇总支出。
'''
def generate_report():
option = simpledialog.askstring("生成报告", "选择生成报告的方式(1: 按月份, 2: 按类别):")
report = {}
if option == '1':
for expense in users[current_user]:
month = expense['date'][:7]
if month not in report:
report[month] = 0
report[month] += expense['money']
elif option == '2':
for expense in users[current_user]:
kinds = expense['kinds']
if kinds not in report:
report[kinds] = 0
report[kinds] += expense['money']
report_str = "\n".join([f"{key}: {report[key]}" for key in report])
messagebox.showinfo("报告", report_str)
'''程序的入口,负责加载数据,用户登录,显示操作菜单以及根据用户选择调用相应功能模块。
while循环用来提供持续的用户交互,直到用户选择退出。'''
def main_menu():
# root.withdraw() # 隐藏登录窗口
menu = tk.Tk()
menu.title("个人开支管理系统")
tk.Label(menu, text=f"当前用户: {current_user}", font=("Arial", 30)).pack(pady=30)
tk.Button(menu, text="记录开支", command=record_expense, width=30).pack(pady=30)
tk.Button(menu, text="查看开支", command=cat_expenses, width=30).pack(pady=30)
tk.Button(menu, text="计算总支出", command=total_expense, width=30).pack(pady=30)
tk.Button(menu, text="删除记录", command=delete_expense, width=30).pack(pady=30)
tk.Button(menu, text="生成报告", command=generate_report, width=30).pack(pady=30)
tk.Button(menu, text="退出并保存", command=lambda: [save_data(), menu.destroy(), root.deiconify()], width=30).pack(
pady=30)
menu.mainloop()
# 主窗口和登录界面及函数的调用
root = tk.Tk()
root.title("个人开支管理系统")
tk.Button(root, text="登录", command=login, width=50).pack(pady=50)
root.mainloop()
项目特色
- 用户友好的界面:通过Tkinter提供简洁明了的图形用户界面,用户可以方便地进行开支记录和管理。
- 数据持久性:使用JSON文件保存用户数据,即使程序关闭,也能保留用户的开支记录。
- 详细的统计功能:提供按月份和类别的开支报告,使用户可以清晰了解自己的消费情况。
- 灵活的删除功能:用户可以根据日期或类别删除开支记录,确保数据管理的灵活性。
使用总结
该项目以实际需求出发,实现了个人开支管理的基本功能,并通过Python的Tkinter库提供了良好的用户交互体验。
在开发过程中,涵盖了数据处理、文件操作、异常处理等多种技术,具有一定的实用价值和学习意义。
未来我们可以在此基础上增加更多功能,如图表分析、预算管理、多用户支持等,以进一步提升系统的实用性。