微信关注,获取更多

跟着AI学Python 优化通讯管理系统-第一版

# === 通讯录图形界面版 ===

import tkinter as tk
from tkinter import messagebox
import os
import json

# --- 以下是从 lesson10 复用的核心类,完全不变 ---

DIR = os.path.dirname(os.path.abspath(__file__))
DATA_FILE = os.path.join(DIR, "contacts.json")

class Contact:
    def __init__(self, name, phone, email="", group="默认"):
        self.name = name
        self.phone = phone
        self.email = email
        self.group = group

    def __str__(self):
        return f"{self.name} | {self.phone} | {self.email} | {self.group}"


class ContactBook:
    def __init__(self):
        self.contacts = []
        self.load()

    def add(self, contact):
        for c in self.contacts:
            if c.name == contact.name:
                return False          # 返回False表示已存在
        self.contacts.append(contact)
        self.save()
        return True                   # 返回True表示添加成功

    def delete(self, name):
        for c in self.contacts:
            if c.name == name:
                self.contacts.remove(c)
                self.save()
                return True
        return False

    def search(self, keyword):
        keyword = keyword.lower()
        results = []
        for c in self.contacts:
            if (keyword in c.name.lower() or
                keyword in c.phone or
                keyword in c.email.lower()):
                results.append(c)
        return results

    def show_all(self):
        return self.contacts

    def save(self):
        try:
            data = []
            for c in self.contacts:
                data.append({
                    "name": c.name,
                    "phone": c.phone,
                    "email": c.email,
                    "group": c.group
                })
            with open(DATA_FILE, "w", encoding="utf-8") as f:
                json.dump(data, f, ensure_ascii=False, indent=2)
        except Exception as e:
            print(f"保存失败:{e}")

    def load(self):
        try:
            if os.path.exists(DATA_FILE):
                with open(DATA_FILE, "r", encoding="utf-8") as f:
                    data = json.load(f)
                    for item in data:
                        c = Contact(
                            item["name"],
                            item["phone"],
                            item.get("email", ""),
                            item.get("group", "默认")
                        )
                        self.contacts.append(c)
        except FileNotFoundError:
            self.contacts = []
        except json.JSONDecodeError:
            self.contacts = []


# --- 以上是核心类,不变 ---
# --- 以下是图形界面部分 ---

book = ContactBook()

window = tk.Tk()
window.title("通讯录管理系统")
window.geometry("500x500")

# ===== 左侧:联系人列表 =====
left_frame = tk.Frame(window)
left_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=10, pady=10)

tk.Label(left_frame, text="联系人列表", font=("微软雅黑", 12, "bold")).pack()

listbox = tk.Listbox(left_frame, font=("微软雅黑", 11), width=25, height=18)
listbox.pack(fill=tk.BOTH, expand=True, pady=5)

# 刷新列表的函数
def refresh_list(keyword=""):
    listbox.delete(0, tk.END)
    if keyword:
        contacts = book.search(keyword)
    else:
        contacts = book.show_all()
    for c in contacts:
        listbox.insert(tk.END, f"{c.name}  {c.phone}")

# 程序启动时加载联系人
refresh_list()

# 点击列表时,把选中的联系人填入右侧输入框
def on_list_click(event):
    selection = listbox.curselection()
    if selection:
        index = selection[0]
        if keyword_entry.get().strip():
            contacts = book.search(keyword_entry.get().strip())
        else:
            contacts = book.show_all()
        if index < len(contacts):
            c = contacts[index]
            entry_name.delete(0, tk.END)
            entry_name.insert(0, c.name)
            entry_phone.delete(0, tk.END)
            entry_phone.insert(0, c.phone)
            entry_email.delete(0, tk.END)
            entry_email.insert(0, c.email)
            entry_group.delete(0, tk.END)
            entry_group.insert(0, c.group)

listbox.bind("<<ListboxSelect>>", on_list_click)

# ===== 右侧:输入和操作区 =====
right_frame = tk.Frame(window)
right_frame.pack(side=tk.RIGHT, fill=tk.Y, padx=10, pady=10)

# 输入框区域
tk.Label(right_frame, text="姓名:", font=("微软雅黑", 10)).pack(anchor=tk.W)
entry_name = tk.Entry(right_frame, font=("微软雅黑", 11), width=18)
entry_name.pack(pady=(0, 5))

tk.Label(right_frame, text="电话:", font=("微软雅黑", 10)).pack(anchor=tk.W)
entry_phone = tk.Entry(right_frame, font=("微软雅黑", 11), width=18)
entry_phone.pack(pady=(0, 5))

tk.Label(right_frame, text="邮箱:", font=("微软雅黑", 10)).pack(anchor=tk.W)
entry_email = tk.Entry(right_frame, font=("微软雅黑", 11), width=18)
entry_email.pack(pady=(0, 5))

tk.Label(right_frame, text="分组:", font=("微软雅黑", 10)).pack(anchor=tk.W)
entry_group = tk.Entry(right_frame, font=("微软雅黑", 11), width=18)
entry_group.insert(0, "默认")
entry_group.pack(pady=(0, 10))

# 按钮操作
def add_contact(event=None):
    name = entry_name.get().strip()
    phone = entry_phone.get().strip()
    email = entry_email.get().strip()
    group = entry_group.get().strip() or "默认"
    if not name or not phone:
        messagebox.showwarning("提示", "姓名和电话不能为空!")
        return
    if not phone.isdigit():
        messagebox.showwarning("提示", "电话必须是数字!")
        return
    c = Contact(name, phone, email, group)
    if book.add(c):
        messagebox.showinfo("成功", f"已添加:{name}")
        clear_inputs()
        refresh_list()
    else:
        messagebox.showwarning("提示", f"{name} 已存在!")

def del_contact():
    selection = listbox.curselection()
    if not selection:
        messagebox.showwarning("提示", "请先选择一个联系人!")
        return
    index = selection[0]
    if keyword_entry.get().strip():
        contacts = book.search(keyword_entry.get().strip())
    else:
        contacts = book.show_all()
    if index < len(contacts):
        name = contacts[index].name
        if messagebox.askyesno("确认", f"确定删除 {name} 吗?"):
            book.delete(name)
            clear_inputs()
            refresh_list()

def update_contact():
    selection = listbox.curselection()
    if not selection:
        messagebox.showwarning("提示", "请先选择一个联系人!")
        return
    index = selection[0]
    if keyword_entry.get().strip():
        contacts = book.search(keyword_entry.get().strip())
    else:
        contacts = book.show_all()
    if index < len(contacts):
        old_name = contacts[index].name
        new_phone = entry_phone.get().strip()
        new_email = entry_email.get().strip()
        new_group = entry_group.get().strip() or "默认"
        if not new_phone:
            messagebox.showwarning("提示", "电话不能为空!")
            return
        # 删除旧的,添加新的
        book.delete(old_name)
        c = Contact(old_name, new_phone, new_email, new_group)
        book.add(c)
        messagebox.showinfo("成功", f"已修改 {old_name} 的信息")
        clear_inputs()
        refresh_list()

def search_contact(event=None):
    refresh_list(keyword_entry.get().strip())

def clear_inputs():
    entry_name.delete(0, tk.END)
    entry_phone.delete(0, tk.END)
    entry_email.delete(0, tk.END)
    entry_group.delete(0, tk.END)
    entry_group.insert(0, "默认")

# 搜索框
tk.Label(right_frame, text="搜索:", font=("微软雅黑", 10)).pack(anchor=tk.W)
keyword_entry = tk.Entry(right_frame, font=("微软雅黑", 11), width=18)
keyword_entry.pack(pady=(0, 5))
keyword_entry.bind("<Return>", search_contact)

tk.Button(right_frame, text="搜索", font=("微软雅黑", 10), command=search_contact, width=6).pack(pady=(0, 10))

# 操作按钮
btn_frame = tk.Frame(right_frame)
btn_frame.pack()

tk.Button(btn_frame, text="添加", font=("微软雅黑", 10), command=add_contact, width=6).grid(row=0, column=0, padx=3, pady=3)
tk.Button(btn_frame, text="删除", font=("微软雅黑", 10), command=del_contact, width=6).grid(row=0, column=1, padx=3, pady=3)
tk.Button(btn_frame, text="修改", font=("微软雅黑", 10), command=update_contact, width=6).grid(row=1, column=0, padx=3, pady=3)
tk.Button(btn_frame, text="清空", font=("微软雅黑", 10), command=clear_inputs, width=6).grid(row=1, column=1, padx=3, pady=3)

# 关闭窗口时保存数据
def on_close():
    book.save()
    window.destroy()

window.protocol("WM_DELETE_WINDOW", on_close)

window.mainloop()
对比 终端版 图形版
核心类 Contact + ContactBook 完全复用
菜单 print + input 按钮和列表框
添加 input输入 → book.add() Entry输入 → book.add()
删除 input输入 → book.delete() 选中列表项 → book.delete()
修改 input输入 → 改属性 选中列表项 → 填入输入框 → 改属性
搜索 input输入 → book.search() 搜索框 → book.search()
提示 print文字 messagebox弹窗

 

未经允许不得转载:百花谷博客 » 跟着AI学Python 优化通讯管理系统-第一版

评论

2+5=

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏