人际关系管理系统:基于Python的地址簿应用
概述
本文介绍了一个功能全面的地址簿管理系统,支持农历/公历转换、联系人管理、生日提醒等功能。该系统基于Python的Tkinter库开发,结合SQLite数据库存储数据,并提供了直观的用户界面。
系统功能
人员管理:添加、编辑、删除联系人信息
农历/公历转换:支持公历与农历日期互转
生日管理:计算生日倒计时和年龄信息
联系方式管理:存储多种联系方式
数据统计:展示联系人年龄分布和生日信息
系统架构

核心模块实现
1. 农历/公历转换工具
class Tools:
def solar_to_lunar(self, year: int, month: int, day: int):
"""
公历转农历
:param year: 公历年
:param month: 公历月
:param day: 公历日
:return: 字典,包含农历日期、天干地支、生肖等信息
"""
try:
solar_date = datetime.date(year, month, day)
lunar_date = LunarDate.fromSolarDate(year, month, day)
ganzhi_year = self.get_ganzhi(lunar_date.year)
ganzhi_month = self.get_ganzhi(lunar_date.month)
ganzhi_day = self.get_ganzhi(lunar_date.day)
zodiac = self.get_zodiac(lunar_date.year)
return {
"公历日期": solar_date.strftime("%Y-%m-%d"),
"农历日期": f"{lunar_date.year}-{str(lunar_date.month).zfill(2)}-{str(lunar_date.day).zfill(2)}",
"天干地支年": ganzhi_year,
"天干地支月": ganzhi_month,
"天干地支日": ganzhi_day,
"生肖": zodiac
}
except Exception as e:
return {"error": f"转换失败: {str(e)}"}
def lunar_to_solar(self, lunar_year: int, lunar_month: int, lunar_day: int):
"""
农历转公历
:param lunar_year: 农历年
:param lunar_month: 农历月
:param lunar_day: 农历日
:return: 公历日期对象
"""
try:
lunar_date = LunarDate(lunar_year, lunar_month, lunar_day, True)
solar_date = lunar_date.toSolarDate()
return {
"农历日期": f"{lunar_year}-{str(lunar_month).zfill(2)}-{str(lunar_day).zfill(2)}",
"公历日期": solar_date.strftime("%Y-%m-%d"),
"星期": self.get_weekday(solar_date)
}
except Exception as e:
# 尝试非闰月转换
lunar_date = LunarDate(lunar_year, lunar_month, lunar_day, False)
solar_date = lunar_date.toSolarDate()
return {
"农历日期": f"{lunar_year}-{str(lunar_month).zfill(2)}-{str(lunar_day).zfill(2)}",
"公历日期": solar_date.strftime("%Y-%m-%d"),
"星期": self.get_weekday(solar_date)
}2. 数据库管理
class Database:
def __init__(self):
self.dc = SqLite("address_book.db")
self.create_table()
def create_table(self):
# 创建人员表
self.dc.user_defined_sql("CREATE TABLE IF NOT EXISTS person (\n"
"md5_str TEXT PRIMARY KEY,\n"
"name TEXT NOT NULL,\n"
"age INTEGER NOT NULL,\n"
"gender TEXT NOT NULL,\n"
"address TEXT,\n"
"birthday_type TEXT,\n"
"solar_time TEXT,\n"
"lunar_time TEXT,\n"
"birthday_week TEXT,\n"
"lunar_year TEXT,\n"
"lunar_month TEXT,\n"
"lunar_day TEXT,\n"
"twelve_animals TEXT,\n"
"create_time TEXT DEFAULT (datetime('now', 'localtime'))\n"
");")
# 创建联系方式表
self.dc.user_defined_sql("CREATE TABLE IF NOT EXISTS contacts (\n"
"id INTEGER PRIMARY KEY AUTOINCREMENT,\n"
"person_md5 TEXT NOT NULL,\n"
"contact_type TEXT NOT NULL,\n"
"contact_value TEXT NOT NULL,\n"
"create_time TEXT DEFAULT (datetime('now', 'localtime'))\n"
")")
def add_person(self, name, age, gender, address, birthday_type, solar_time, lunar_time, birthday_week, lunar_year,
lunar_month, lunar_day, twelve_animals, md5_str):
# 添加人员信息
self.dc.insert("person",
["name", "age", "gender", "address", "birthday_type", "solar_time", "lunar_time",
"birthday_week", "lunar_year", "lunar_month", "lunar_day", "twelve_animals", "md5_str"],
[name, age, gender, address, birthday_type, solar_time, lunar_time, birthday_week, lunar_year,
lunar_month, lunar_day, twelve_animals, md5_str])
self.dc.commit()
def get_all_person(self):
# 获取所有人员信息
dt = self.dc.user_defined_sql("select * from person")
result = []
for person in dt:
if person[5] == '农历':
birthday = person[7]
else:
birthday = person[6]
result.append({
"md5_str": person[0],
"name": person[1],
"age": person[2],
"gender": person[3],
"address": person[4],
"birthday_type": person[5],
"solar_time": person[6],
"lunar_time": person[7],
"week": person[8],
"lunar_year": person[9],
"lunar_month": person[10],
"lunar_day": person[11],
"twelve_animals": person[12],
"birthday": birthday,
})
return result3. 生日计算功能
def get_alive_time(self, birthday: str, is_solar: bool):
# 计算年龄(年、月、总天数)
date = datetime.datetime.today()
birthday = datetime.datetime.strptime(birthday, "%Y-%m-%d")
if not is_solar:
birthday = self.lunar_to_solar(birthday.year, birthday.month, birthday.day).get("公历日期")
birthday = datetime.datetime.strptime(birthday, "%Y-%m-%d")
all_day = int(str(date - birthday).split("days")[0])
day = date.day - birthday.day
year = date.year - birthday.year
month = year * 12 + (date.month - birthday.month)
if day < 0:
month -= 1
if date.month - birthday.month < 0:
year -= 1
return year, month, all_day
def get_birthday_days(self, birthday: str, is_solar: bool):
# 计算距离下一个生日的天数
date = datetime.datetime.today()
new_year = date.year
new_month = date.month
new_day = date.day
birthday_month = int(birthday.split("-")[1])
birthday_day = int(birthday.split("-")[2])
if not is_solar:
birthday = self.lunar_to_solar(new_year, birthday_month, birthday_day).get("公历日期")
birthday_month = int(birthday.split("-")[1])
birthday_day = int(birthday.split("-")[2])
if birthday_month < new_month:
new_birthday = datetime.datetime.strptime(f"{new_year + 1}-{birthday_month}-{birthday_day}", "%Y-%m-%d")
day = new_birthday - date
elif birthday_month == new_month:
if birthday_day < new_day:
new_birthday = datetime.datetime.strptime(f"{new_year + 1}-{birthday_month}-{birthday_day}", "%Y-%m-%d")
day = new_birthday - date
elif birthday_day == new_day:
day = 0
else:
new_birthday = datetime.datetime.strptime(f"{new_year}-{birthday_month}-{birthday_day}", "%Y-%m-%d")
day = new_birthday - date
else:
new_birthday = datetime.datetime.strptime(f"{new_year}-{birthday_month}-{birthday_day}", "%Y-%m-%d")
day = new_birthday - date
return int(str(day).split("day")[0]) + 1用户界面设计
主界面结构
class AddressBook:
def __init__(self, root):
self.root = root
self.root.title("人际关系管理系统")
self.root.geometry("1200x800")
self.root.minsize(1000, 700)
# 主框架
self.main_frame = ttk.Frame(root)
self.main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
# 标签页
self.notebook = ttk.Notebook(self.main_frame)
self.notebook.pack(fill=tk.BOTH, expand=True)
# 创建标签页
self.create_person_tab()
self.create_view_tab()
self.create_birthday_tab()
# 状态栏
self.status_var = tk.StringVar()
self.status_bar = ttk.Label(root, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W)
self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)
self.status_var.set("就绪")
# 加载数据
self.load_person_list()人员管理标签页
def create_person_tab(self):
# 人员管理标签页
self.person_tab = ttk.Frame(self.notebook)
self.notebook.add(self.person_tab, text="人员管理")
# 左侧表单
form_frame = ttk.LabelFrame(self.person_tab, text="人员信息", padding=10)
form_frame.pack(side=tk.LEFT, fill=tk.Y, padx=5, pady=5)
# 姓名、性别、住址输入框
ttk.Label(form_frame, text="姓名:").grid(row=0, column=0, sticky=tk.W, pady=5)
self.name_var = tk.StringVar()
ttk.Entry(form_frame, textvariable=self.name_var, width=25).grid(row=0, column=1, pady=5)
ttk.Label(form_frame, text="性别:").grid(row=1, column=0, sticky=tk.W, pady=5)
self.gender_var = tk.StringVar()
gender_combo = ttk.Combobox(form_frame, textvariable=self.gender_var, values=["男", "女", "其他"], width=22)
gender_combo.grid(row=1, column=1, pady=5)
gender_combo.set("男")
ttk.Label(form_frame, text="住址:").grid(row=3, column=0, sticky=tk.W, pady=5)
self.address_var = tk.StringVar()
ttk.Entry(form_frame, textvariable=self.address_var, width=25).grid(row=3, column=1, pady=5)
# 生日信息
birthday_frame = ttk.LabelFrame(form_frame, text="生日信息", padding=10)
birthday_frame.grid(row=4, column=0, columnspan=2, sticky=tk.W + tk.E, pady=5)
ttk.Label(birthday_frame, text="生日类型:").grid(row=0, column=0, sticky=tk.W, padx=5, pady=5)
self.birthday_type_var = tk.StringVar(value="公历")
self.birthday_type_combobox = ttk.Combobox(birthday_frame, textvariable=self.birthday_type_var,
values=["公历", "农历"], width=8, state="readonly")
self.birthday_type_combobox.grid(row=0, column=1, sticky=tk.W, padx=5, pady=5)
ttk.Label(birthday_frame, text="生日日期:").grid(row=0, column=2, sticky=tk.W, padx=5, pady=5)
self.birthday_var = tk.StringVar()
self.birthday_entry = ttk.Entry(birthday_frame, textvariable=self.birthday_var, width=15)
self.birthday_entry.grid(row=0, column=3, sticky=tk.W, padx=5, pady=5)
# 联系方式
contact_frame = ttk.LabelFrame(form_frame, text="联系方式", padding=10)
contact_frame.grid(row=5, column=0, columnspan=2, sticky=tk.W + tk.E, pady=5)
self.contact_tree = ttk.Treeview(contact_frame, columns=("类型", "值"), show="headings", height=5)
self.contact_tree.heading("类型", text="类型")
self.contact_tree.heading("值", text="值")
self.contact_tree.column("类型", width=80)
self.contact_tree.column("值", width=180)
self.contact_tree.pack(side=tk.TOP, fill=tk.X)
# 操作按钮
btn_frame = ttk.Frame(contact_frame)
btn_frame.pack(fill=tk.X, pady=5)
ttk.Button(btn_frame, text="添加", command=self.add_contact).pack(side=tk.LEFT, padx=2)
ttk.Button(btn_frame, text="编辑", command=self.update_contact).pack(side=tk.LEFT, padx=2)
ttk.Button(btn_frame, text="删除", command=self.delete_contact).pack(side=tk.LEFT, padx=2)
# 右侧人员列表
list_frame = ttk.LabelFrame(self.person_tab, text="人员列表", padding=10)
list_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=5, pady=5)
columns = ("姓名", "性别", "年龄", "住址")
self.person_tree = ttk.Treeview(list_frame, columns=columns, show="headings")
for col in columns:
self.person_tree.heading(col, text=col)
self.person_tree.column(col, width=120)
self.person_tree.column("住址", width=200)
scrollbar = ttk.Scrollbar(list_frame, orient=tk.VERTICAL, command=self.person_tree.yview)
self.person_tree.configure(yscrollcommand=scrollbar.set)
self.person_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
self.person_tree.bind("<<TreeviewSelect>>", self.on_person_select)生日管理标签页
def create_birthday_tab(self):
# 生日管理标签页
self.birthday_tab = ttk.Frame(self.notebook)
self.notebook.add(self.birthday_tab, text="生日管理")
# 生日列表
list_frame = ttk.LabelFrame(self.birthday_tab, text="生日列表", padding=10)
list_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
# 生日信息列
columns = ("姓名", "年龄", "生日类型", "公历生日", "农历生日", "公历距离", "农历距离", "出生天数", "出生月数",
"天干地支年", "天干地支月", "天干地支日", "生肖")
self.birthday_tree = ttk.Treeview(list_frame, columns=columns, show="headings")
# 设置列宽
col_widths = {
"姓名": 50,
"年龄": 50,
"生日类型": 70,
"公历生日": 70,
"农历生日": 70,
"公历距离": 70,
"农历距离": 70,
"出生天数": 70,
"出生月数": 70,
"天干地支年": 70,
"天干地支月": 70,
"天干地支日": 70,
"生肖": 50,
}
for col in columns:
self.birthday_tree.heading(col, text=col)
self.birthday_tree.column(col, width=col_widths.get(col, 100))
scrollbar = ttk.Scrollbar(list_frame, orient=tk.VERTICAL, command=self.birthday_tree.yview)
self.birthday_tree.configure(yscrollcommand=scrollbar.set)
self.birthday_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
# 刷新按钮
control_frame = ttk.Frame(self.birthday_tab)
control_frame.pack(fill=tk.X, padx=10, pady=10)
ttk.Button(control_frame, text="刷新", command=self.load_birthdays).pack(side=tk.RIGHT, padx=5)
# 加载生日数据
self.load_birthdays()使用场景
1. 添加新联系人
在"人员管理"标签页填写姓名、性别、住址
选择生日类型(公历/农历)
输入生日日期(YYYY-MM-DD格式)
添加联系方式(电话、邮箱等)
点击"新建"按钮保存
2. 查看生日信息
切换到"生日管理"标签页
查看所有联系人的生日信息
关注"公历距离"和"农历距离"列,了解距离下一个生日的天数
使用"刷新"按钮更新数据
3. 编辑联系人信息
在人员列表中选择要编辑的联系人
修改表单中的信息
点击"更新"按钮保存更改
系统特点
农历支持:完整支持农历日期转换和计算
生日提醒:自动计算距离生日的天数
年龄计算:精确计算年龄(年、月、天)
生肖天干地支:自动计算生肖和天干地支信息
数据持久化:使用SQLite数据库存储数据
响应式设计:界面适应不同屏幕尺寸
技术亮点
农历计算:使用
lunardate库进行精确的农历日期计算唯一标识:使用MD5哈希为每个联系人生成唯一标识
数据完整性:数据库设计确保数据关联性和完整性
错误处理:全面的异常捕获和用户友好的错误提示
界面优化:使用Treeview组件高效展示表格数据
总结
这个地址簿管理系统集成了传统农历计算与现代联系人管理功能,特别适合需要管理大量联系人并关注农历生日的用户。系统通过以下方式提升用户体验:
直观的界面:清晰的标签页设计和表单布局
高效的数据管理:数据库操作优化确保快速响应
实用的功能:生日提醒、年龄计算等实用功能
文化特色:生肖、天干地支等传统文化元素集成
跨平台支持:基于Python开发,可在多平台运行
下载
通讯录V1.1.0.0
描述:
能够记录人员信息以及生日等信息计算
下载:
- 感谢你赐予我前进的力量

