# === 通讯录图形界面版 ===
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 优化通讯管理系统-第一版

百花谷博客
微信关注,获取更多