概述

本文介绍了一个功能全面的地址簿管理系统,支持农历/公历转换、联系人管理、生日提醒等功能。该系统基于Python的Tkinter库开发,结合SQLite数据库存储数据,并提供了直观的用户界面。

系统功能

  1. 人员管理:添加、编辑、删除联系人信息

  2. 农历/公历转换:支持公历与农历日期互转

  3. 生日管理:计算生日倒计时和年龄信息

  4. 联系方式管理:存储多种联系方式

  5. 数据统计:展示联系人年龄分布和生日信息

系统架构

核心模块实现

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 result

3. 生日计算功能

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. 添加新联系人

  1. 在"人员管理"标签页填写姓名、性别、住址

  2. 选择生日类型(公历/农历)

  3. 输入生日日期(YYYY-MM-DD格式)

  4. 添加联系方式(电话、邮箱等)

  5. 点击"新建"按钮保存

2. 查看生日信息

  1. 切换到"生日管理"标签页

  2. 查看所有联系人的生日信息

  3. 关注"公历距离"和"农历距离"列,了解距离下一个生日的天数

  4. 使用"刷新"按钮更新数据

3. 编辑联系人信息

  1. 在人员列表中选择要编辑的联系人

  2. 修改表单中的信息

  3. 点击"更新"按钮保存更改

系统特点

  1. 农历支持:完整支持农历日期转换和计算

  2. 生日提醒:自动计算距离生日的天数

  3. 年龄计算:精确计算年龄(年、月、天)

  4. 生肖天干地支:自动计算生肖和天干地支信息

  5. 数据持久化:使用SQLite数据库存储数据

  6. 响应式设计:界面适应不同屏幕尺寸

技术亮点

  1. 农历计算:使用lunardate库进行精确的农历日期计算

  2. 唯一标识:使用MD5哈希为每个联系人生成唯一标识

  3. 数据完整性:数据库设计确保数据关联性和完整性

  4. 错误处理:全面的异常捕获和用户友好的错误提示

  5. 界面优化:使用Treeview组件高效展示表格数据

总结

这个地址簿管理系统集成了传统农历计算与现代联系人管理功能,特别适合需要管理大量联系人并关注农历生日的用户。系统通过以下方式提升用户体验:

  1. 直观的界面:清晰的标签页设计和表单布局

  2. 高效的数据管理:数据库操作优化确保快速响应

  3. 实用的功能:生日提醒、年龄计算等实用功能

  4. 文化特色:生肖、天干地支等传统文化元素集成

  5. 跨平台支持:基于Python开发,可在多平台运行

下载

  1. 通讯录V1.1.0.0

    1. 描述:

      1. 能够记录人员信息以及生日等信息计算

    2. 下载:

      1. 通讯录.exe