import tkinter as tk
from tkinter import ttk, messagebox, simpledialog
import json
import os
import re
class Contact:
"""联系人类"""
def __init__(self, name, phone, email="", address="", region="", company="", title=""):
self.name = name
self.phone = phone
self.email = email
self.address = address
self.region = region
self.company = company
self.title = title
def to_dict(self):
"""将联系人对象转换为字典"""
return {
'name': self.name,
'phone': self.phone,
'email': self.email,
'address': self.address,
'region': self.region,
'company': self.company,
'title': self.title
}
@classmethod
def from_dict(cls, data):
"""从字典创建联系人对象"""
return cls(
data['name'],
data['phone'],
data.get('email', ''),
data.get('address', ''),
data.get('region', ''),
data.get('company', ''),
data.get('title', '')
)
def __str__(self):
return (f"姓名: {self.name}, 电话: {self.phone}, 邮箱: {self.email}, "
f"地址: {self.address}, 地区: {self.region}, 单位: {self.company}, 职务: {self.title}")
class AddressBook:
"""通讯录类"""
def __init__(self, filename="address_book.json"):
self.filename = filename
self.contacts = []
self.load_contacts()
def validate_phone(self, phone):
"""验证电话号码格式"""
# 简单的电话号码验证:只包含数字、空格、括号和连字符
pattern = r'^[\d\s\(\)\-]+$'
return re.match(pattern, phone) is not None
def validate_email(self, email):
"""验证邮箱格式"""
if not email: # 邮箱可选,空值通过验证
return True
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
return re.match(pattern, email) is not None
def add_contact(self, name, phone, email="", address="", region="", company="", title=""):
"""添加联系人"""
# 验证电话号码格式
if not self.validate_phone(phone):
messagebox.showerror("错误", "电话号码格式不正确!")
return False
# 验证邮箱格式
if not self.validate_email(email):
messagebox.showerror("错误", "邮箱格式不正确!")
return False
# 检查电话是否已存在
for contact in self.contacts:
if contact.phone == phone:
messagebox.showerror("错误", f"电话 {phone} 已存在!")
return False
new_contact = Contact(name, phone, email, address, region, company, title)
self.contacts.append(new_contact)
self.save_contacts()
messagebox.showinfo("成功", f"联系人 {name} 添加成功!")
return True
def delete_contact(self, identifier):
"""删除联系人,可通过姓名或电话标识"""
for i, contact in enumerate(self.contacts):
if contact.name == identifier or contact.phone == identifier:
removed = self.contacts.pop(i)
self.save_contacts()
messagebox.showinfo("成功", f"联系人 {removed.name} 删除成功!")
return True
messagebox.showerror("错误", f"未找到联系人: {identifier}")
return False
def search_contact(self, identifier):
"""查找联系人,可通过姓名、电话、地区、单位等标识"""
results = []
for contact in self.contacts:
if (identifier.lower() in contact.name.lower() or
identifier in contact.phone or
identifier.lower() in contact.region.lower() or
identifier.lower() in contact.company.lower() or
identifier.lower() in contact.title.lower()):
results.append(contact)
return results
def update_contact(self, identifier, name=None, phone=None, email=None,
address=None, region=None, company=None, title=None):
"""更新联系人信息"""
for contact in self.contacts:
if contact.name == identifier or contact.phone == identifier:
# 验证新电话号码格式
if phone and not self.validate_phone(phone):
messagebox.showerror("错误", "电话号码格式不正确!")
return False
# 验证新邮箱格式
if email and not self.validate_email(email):
messagebox.showerror("错误", "邮箱格式不正确!")
return False
if name:
contact.name = name
if phone:
# 检查新电话是否已存在(排除当前联系人)
if phone != contact.phone and any(c.phone == phone for c in self.contacts):
messagebox.showerror("错误", f"电话 {phone} 已存在!")
return False
contact.phone = phone
if email:
contact.email = email
if address:
contact.address = address
if region:
contact.region = region
if company:
contact.company = company
if title:
contact.title = title
self.save_contacts()
messagebox.showinfo("成功", "联系人信息更新成功!")
return True
messagebox.showerror("错误", f"未找到联系人: {identifier}")
return False
def display_all_contacts(self):
"""显示所有联系人"""
return self.contacts
def display_contact_details(self, identifier):
"""显示联系人的详细信息"""
results = self.search_contact(identifier)
if not results:
messagebox.showinfo("提示", f"未找到联系人: {identifier}")
return []
return results
def get_contacts_by_region(self, region):
"""按地区筛选联系人"""
return [contact for contact in self.contacts if region.lower() in contact.region.lower()]
def get_contacts_by_company(self, company):
"""按单位筛选联系人"""
return [contact for contact in self.contacts if company.lower() in contact.company.lower()]
def get_contacts_by_title(self, title):
"""按职务筛选联系人"""
return [contact for contact in self.contacts if title.lower() in contact.title.lower()]
def save_contacts(self):
"""保存通讯录到文件"""
data = [contact.to_dict() for contact in self.contacts]
with open(self.filename, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
def load_contacts(self):
"""从文件加载通讯录"""
if os.path.exists(self.filename):
try:
with open(self.filename, 'r', encoding='utf-8') as f:
data = json.load(f)
self.contacts = [Contact.from_dict(item) for item in data]
except (json.JSONDecodeError, KeyError):
messagebox.showwarning("警告", "通讯录文件损坏,将创建新的通讯录")
self.contacts = []
class ContactFormDialog(simpledialog.Dialog):
"""添加/编辑联系人的对话框"""
def __init__(self, parent, title, contact=None):
self.contact = contact
super().__init__(parent, title)
def body(self, master):
"""创建对话框主体"""
# 设置样式
style = ttk.Style()
style.configure("Form.TLabel", font=("微软雅黑", 10), foreground="#333333")
style.configure("Form.TEntry", font=("微软雅黑", 10))
ttk.Label(master, text="姓名:", style="Form.TLabel").grid(row=0, column=0, sticky="w", padx=15, pady=10)
ttk.Label(master, text="电话:", style="Form.TLabel").grid(row=1, column=0, sticky="w", padx=15, pady=10)
ttk.Label(master, text="邮箱:", style="Form.TLabel").grid(row=2, column=0, sticky="w", padx=15, pady=10)
ttk.Label(master, text="地址:", style="Form.TLabel").grid(row=3, column=0, sticky="w", padx=15, pady=10)
ttk.Label(master, text="地区:", style="Form.TLabel").grid(row=4, column=0, sticky="w", padx=15, pady=10)
ttk.Label(master, text="单位:", style="Form.TLabel").grid(row=5, column=0, sticky="w", padx=15, pady=10)
ttk.Label(master, text="职务:", style="Form.TLabel").grid(row=6, column=0, sticky="w", padx=15, pady=10)
self.name_var = tk.StringVar()
self.phone_var = tk.StringVar()
self.email_var = tk.StringVar()
self.address_var = tk.StringVar()
self.region_var = tk.StringVar()
self.company_var = tk.StringVar()
self.title_var = tk.StringVar()
# 如果正在编辑现有联系人,填充字段
if self.contact:
self.name_var.set(self.contact.name)
self.phone_var.set(self.contact.phone)
self.email_var.set(self.contact.email)
self.address_var.set(self.contact.address)
self.region_var.set(self.contact.region)
self.company_var.set(self.contact.company)
self.title_var.set(self.contact.title)
self.name_entry = ttk.Entry(master, textvariable=self.name_var, width=30, style="Form.TEntry")
self.phone_entry = ttk.Entry(master, textvariable=self.phone_var, width=30, style="Form.TEntry")
self.email_entry = ttk.Entry(master, textvariable=self.email_var, width=30, style="Form.TEntry")
self.address_entry = ttk.Entry(master, textvariable=self.address_var, width=30, style="Form.TEntry")
self.region_entry = ttk.Entry(master, textvariable=self.region_var, width=30, style="Form.TEntry")
self.company_entry = ttk.Entry(master, textvariable=self.company_var, width=30, style="Form.TEntry")
self.title_entry = ttk.Entry(master, textvariable=self.title_var, width=30, style="Form.TEntry")
self.name_entry.grid(row=0, column=1, padx=15, pady=10)
self.phone_entry.grid(row=1, column=1, padx=15, pady=10)
self.email_entry.grid(row=2, column=1, padx=15, pady=10)
self.address_entry.grid(row=3, column=1, padx=15, pady=10)
self.region_entry.grid(row=4, column=1, padx=15, pady=10)
self.company_entry.grid(row=5, column=1, padx=15, pady=10)
self.title_entry.grid(row=6, column=1, padx=15, pady=10)
return self.name_entry # 初始焦点
def apply(self):
"""应用更改"""
self.result = (
self.name_var.get().strip(),
self.phone_var.get().strip(),
self.email_var.get().strip(),
self.address_var.get().strip(),
self.region_var.get().strip(),
self.company_var.get().strip(),
self.title_var.get().strip()
)
class ScrollableFrame(ttk.Frame):
"""可滚动的框架"""
def __init__(self, container, *args, **kwargs):
super().__init__(container, *args, **kwargs)
# 创建Canvas和滚动条
self.canvas = tk.Canvas(self, highlightthickness=0, bg='#f8f9fa')
scrollbar = ttk.Scrollbar(self, orient="vertical", command=self.canvas.yview)
self.scrollable_frame = ttk.Frame(self.canvas)
self.scrollable_frame.bind(
"<Configure>",
lambda e: self.canvas.configure(scrollregion=self.canvas.bbox("all"))
)
self.canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
self.canvas.configure(yscrollcommand=scrollbar.set)
self.canvas.pack(side="left", fill="both", expand=True)
scrollbar.pack(side="right", fill="y")
# 绑定鼠标滚轮事件
self.canvas.bind("<Enter>", self._bind_mousewheel)
self.canvas.bind("<Leave>", self._unbind_mousewheel)
def _bind_mousewheel(self, event):
self.canvas.bind_all("<MouseWheel>", self._on_mousewheel)
def _unbind_mousewheel(self, event):
self.canvas.unbind_all("<MouseWheel>")
def _on_mousewheel(self, event):
self.canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")
class ContactDetailWindow:
"""联系人详情窗口"""
def __init__(self, parent, contact):
self.contact = contact
self.window = tk.Toplevel(parent)
self.window.title(f"联系人详情 - {contact.name}")
self.window.geometry("550x450")
self.window.resizable(True, True)
self.window.transient(parent)
self.window.configure(bg='#f8f9fa')
# 设置窗口位置(居中显示)
self.window.update_idletasks()
x = parent.winfo_x() + (parent.winfo_width() - self.window.winfo_reqwidth()) // 2
y = parent.winfo_y() + (parent.winfo_height() - self.window.winfo_reqheight()) // 2
self.window.geometry(f"+{x}+{y}")
# 延迟设置grab_set,确保窗口已经完全初始化
self.window.after(100, self._set_grab)
self.create_widgets()
def _set_grab(self):
"""延迟设置窗口焦点捕获"""
try:
self.window.grab_set()
except tk.TclError:
# 如果设置失败,忽略错误
pass
def create_widgets(self):
"""创建详情窗口组件"""
# 主框架
main_frame = ttk.Frame(self.window, padding=10)
main_frame.pack(fill=tk.BOTH, expand=True)
# 标题
title_frame = ttk.Frame(main_frame)
title_frame.pack(fill=tk.X, pady=(0, 10))
# 使用图标和标题
title_icon = ttk.Label(title_frame, text="👤", font=("微软雅黑", 16))
title_icon.pack(side=tk.LEFT, padx=(0, 10))
title_label = ttk.Label(title_frame, text=self.contact.name,
font=("微软雅黑", 18, "bold"),
foreground="#2c3e50")
title_label.pack(side=tk.LEFT)
# 创建可滚动的详情框架
scrollable_frame = ScrollableFrame(main_frame)
scrollable_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
# 详情内容框架
detail_frame = ttk.Frame(scrollable_frame.scrollable_frame, padding=20)
detail_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
# 创建详情字段
fields = [
("📞 电话", self.contact.phone, "#3498db"),
("📧 邮箱", self.contact.email if self.contact.email else "未填写", "#e74c3c"),
("🏠 地址", self.contact.address if self.contact.address else "未填写", "#9b59b6"),
("🌍 地区", self.contact.region if self.contact.region else "未填写", "#2ecc71"),
("🏢 单位", self.contact.company if self.contact.company else "未填写", "#f39c12"),
("💼 职务", self.contact.title if self.contact.title else "未填写", "#1abc9c")
]
# 使用卡片式布局
for i, (label, value, color) in enumerate(fields):
# 创建卡片框架
card_frame = ttk.Frame(detail_frame, relief="solid", borderwidth=1)
card_frame.pack(fill=tk.X, pady=8, padx=5)
card_frame.configure(style="Card.TFrame")
# 标签
lbl = ttk.Label(card_frame, text=label, font=("微软雅黑", 11, "bold"),
foreground=color)
lbl.pack(anchor="w", padx=15, pady=(10, 5))
# 值
val_lbl = ttk.Label(card_frame, text=value, font=("微软雅黑", 10),
foreground="#2c3e50", wraplength=450, justify="left")
val_lbl.pack(anchor="w", padx=15, pady=(0, 10))
# 按钮框架
button_frame = ttk.Frame(main_frame)
button_frame.pack(fill=tk.X, pady=(10, 0))
# 关闭按钮
close_btn = ttk.Button(button_frame, text="关闭",
command=self.window.destroy,
style="Accent.TButton")
close_btn.pack(side=tk.RIGHT, padx=5)
class AddressBookGUI:
"""通讯录GUI界面"""
def __init__(self, root):
self.root = root
self.root.title("电子通讯录管理系统")
self.root.geometry("1000x700")
self.root.configure(bg='#f8f9fa')
# 设置应用图标(如果有的话)
try:
self.root.iconbitmap("address_book.ico")
except:
pass
# 创建通讯录实例
self.address_book = AddressBook()
# 设置样式
self.setup_styles()
# 创建界面
self.create_widgets()
# 刷新联系人列表
self.refresh_contact_list()
def setup_styles(self):
"""设置界面样式"""
style = ttk.Style()
# 尝试设置现代化主题
try:
style.theme_use('clam')
except:
pass
# 配置自定义样式
style.configure("Title.TLabel",
font=("微软雅黑", 20, "bold"),
background='#f8f9fa',
foreground='#2c3e50')
style.configure("Subtitle.TLabel",
font=("微软雅黑", 11),
background='#f8f9fa',
foreground='#7f8c8d')
style.configure("Custom.TButton",
font=("微软雅黑", 10),
padding=(12, 8),
background='#ecf0f1',
foreground='#2c3e50',
borderwidth=0,
focuscolor='none')
style.configure("Accent.TButton",
font=("微软雅黑", 10, "bold"),
background='#3498db',
foreground='white',
padding=(12, 8),
borderwidth=0,
focuscolor='none')
style.configure("Search.TButton",
font=("微软雅黑", 9),
padding=(10, 6),
borderwidth=0)
style.configure("Treeview",
font=("微软雅黑", 10),
rowheight=30,
background='white',
fieldbackground='white',
borderwidth=0)
style.configure("Treeview.Heading",
font=("微软雅黑", 11, "bold"),
background='#34495e',
foreground='white',
borderwidth=0,
relief='flat')
style.map("Treeview",
background=[('selected', '#3498db')],
foreground=[('selected', 'white')])
style.map("Accent.TButton",
background=[('active', '#2980b9')])
style.map("Custom.TButton",
background=[('active', '#d5dbdb')])
style.configure("Card.TFrame",
background='white',
relief='flat',
borderwidth=1)
style.configure("Search.TEntry",
font=("微软雅黑", 10),
padding=(10, 8))
def create_widgets(self):
"""创建界面组件"""
# 标题区域
header_frame = ttk.Frame(self.root, style="Title.TFrame")
header_frame.pack(fill=tk.X, padx=0, pady=0)
header_frame.configure(style="Header.TFrame")
# 渐变背景(模拟)
title_container = ttk.Frame(header_frame, style="Title.TFrame")
title_container.pack(fill=tk.X, padx=0, pady=0, ipady=20)
title_label = ttk.Label(title_container, text="📒 电子通讯录管理系统", style="Title.TLabel")
title_label.pack(pady=5)
subtitle_label = ttk.Label(title_container, text="高效管理您的联系人信息", style="Subtitle.TLabel")
subtitle_label.pack(pady=(0, 10))
# 搜索和操作区域
action_frame = ttk.Frame(self.root, style="Card.TFrame")
action_frame.pack(fill=tk.X, padx=20, pady=15)
# 搜索框
search_container = ttk.Frame(action_frame)
search_container.pack(fill=tk.X, padx=15, pady=15)
ttk.Label(search_container, text="搜索联系人:", font=("微软雅黑", 10, "bold"),
foreground="#2c3e50").pack(side=tk.LEFT, padx=(0, 10))
self.search_var = tk.StringVar()
self.search_entry = ttk.Entry(search_container, textvariable=self.search_var,
width=30, font=("微软雅黑", 10), style="Search.TEntry")
self.search_entry.pack(side=tk.LEFT, padx=(0, 10))
self.search_entry.bind("<Return>", self.on_search)
ttk.Button(search_container, text="搜索", command=self.on_search, style="Search.TButton").pack(side=tk.LEFT,
padx=(0, 10))
ttk.Button(search_container, text="显示全部", command=self.refresh_contact_list, style="Search.TButton").pack(
side=tk.LEFT)
# 主要操作按钮
button_container = ttk.Frame(action_frame)
button_container.pack(fill=tk.X, padx=15, pady=(0, 15))
ttk.Button(button_container, text="➕ 添加联系人", command=self.add_contact, style="Accent.TButton").pack(
side=tk.LEFT, padx=(0, 10))
ttk.Button(button_container, text="✏️ 编辑联系人", command=self.edit_contact, style="Custom.TButton").pack(
side=tk.LEFT, padx=(0, 10))
ttk.Button(button_container, text="🗑️ 删除联系人", command=self.delete_contact, style="Custom.TButton").pack(
side=tk.LEFT, padx=(0, 10))
ttk.Button(button_container, text="👁️ 查看详情", command=self.view_details, style="Custom.TButton").pack(
side=tk.LEFT, padx=(0, 10))
# 筛选按钮区域
filter_frame = ttk.LabelFrame(button_container, text="筛选", padding=8)
filter_frame.pack(side=tk.RIGHT)
ttk.Button(filter_frame, text="🌍 按地区", command=self.filter_by_region, style="Search.TButton").pack(
side=tk.LEFT, padx=(0, 5))
ttk.Button(filter_frame, text="🏢 按单位", command=self.filter_by_company, style="Search.TButton").pack(
side=tk.LEFT, padx=(0, 5))
ttk.Button(filter_frame, text="💼 按职务", command=self.filter_by_title, style="Search.TButton").pack(
side=tk.LEFT)
# 联系人列表框架
list_frame = ttk.LabelFrame(self.root, text="联系人列表", padding=15)
list_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=(0, 15))
columns = ("姓名", "电话", "邮箱", "地区", "单位", "职务")
self.contact_tree = ttk.Treeview(list_frame, columns=columns, show="headings", height=15)
# 设置列标题和宽度
column_widths = {"姓名": 120, "电话": 140, "邮箱": 180, "地区": 120, "单位": 150, "职务": 120}
for col in columns:
self.contact_tree.heading(col, text=col)
self.contact_tree.column(col, width=column_widths[col])
# 添加滚动条
scrollbar = ttk.Scrollbar(list_frame, orient=tk.VERTICAL, command=self.contact_tree.yview)
self.contact_tree.configure(yscrollcommand=scrollbar.set)
self.contact_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
# 绑定双击事件
self.contact_tree.bind("<Double-1>", self.on_double_click)
# 状态栏
self.status_frame = ttk.Frame(self.root, relief=tk.SUNKEN)
self.status_frame.pack(fill=tk.X, side=tk.BOTTOM)
self.status_label = ttk.Label(self.status_frame, text=f"共有 {len(self.address_book.contacts)} 个联系人",
font=("微软雅黑", 9), foreground="#7f8c8d")
self.status_label.pack(side=tk.LEFT, padx=10, pady=5)
def refresh_contact_list(self, contacts=None):
"""刷新联系人列表"""
# 清空现有列表
for item in self.contact_tree.get_children():
self.contact_tree.delete(item)
# 获取联系人列表
if contacts is None:
contacts = self.address_book.display_all_contacts()
# 填充列表
for contact in contacts:
self.contact_tree.insert("", tk.END, values=(
contact.name,
contact.phone,
contact.email,
contact.region,
contact.company,
contact.title
))
# 更新状态栏
self.status_label.config(
text=f"共有 {len(self.address_book.contacts)} 个联系人 | 当前显示 {len(contacts)} 个联系人")
def on_search(self, event=None):
"""搜索联系人"""
keyword = self.search_var.get().strip()
if not keyword:
messagebox.showwarning("警告", "请输入搜索关键词")
return
results = self.address_book.search_contact(keyword)
if results:
self.refresh_contact_list(results)
messagebox.showinfo("搜索结果", f"找到 {len(results)} 个匹配的联系人")
else:
messagebox.showinfo("搜索结果", "未找到匹配的联系人")
def add_contact(self):
"""添加联系人"""
dialog = ContactFormDialog(self.root, "添加联系人")
if dialog.result:
name, phone, email, address, region, company, title = dialog.result
if not name or not phone:
messagebox.showwarning("警告", "姓名和电话为必填项")
return
if self.address_book.add_contact(name, phone, email, address, region, company, title):
self.refresh_contact_list()
def edit_contact(self):
"""编辑联系人"""
selection = self.contact_tree.selection()
if not selection:
messagebox.showwarning("警告", "请先选择一个联系人")
return
# 获取选中的联系人信息
item = selection[0]
values = self.contact_tree.item(item, "values")
name = values[0]
# 查找联系人对象
contact = None
for c in self.address_book.contacts:
if c.name == name:
contact = c
break
if not contact:
messagebox.showerror("错误", "未找到选中的联系人")
return
# 打开编辑对话框
dialog = ContactFormDialog(self.root, "编辑联系人", contact)
if dialog.result:
new_name, new_phone, new_email, new_address, new_region, new_company, new_title = dialog.result
if not new_name or not new_phone:
messagebox.showwarning("警告", "姓名和电话为必填项")
return
if self.address_book.update_contact(
name, new_name, new_phone, new_email, new_address, new_region, new_company, new_title
):
self.refresh_contact_list()
def delete_contact(self):
"""删除联系人"""
selection = self.contact_tree.selection()
if not selection:
messagebox.showwarning("警告", "请先选择一个联系人")
return
# 获取选中的联系人信息
item = selection[0]
values = self.contact_tree.item(item, "values")
name = values[0]
# 确认删除
if messagebox.askyesno("确认删除", f"确定要删除联系人 {name} 吗?"):
if self.address_book.delete_contact(name):
self.refresh_contact_list()
def view_details(self):
"""查看联系人详情"""
selection = self.contact_tree.selection()
if not selection:
messagebox.showwarning("警告", "请先选择一个联系人")
return
# 获取选中的联系人信息
item = selection[0]
values = self.contact_tree.item(item, "values")
name = values[0]
# 查找联系人对象
contact = None
for c in self.address_book.contacts:
if c.name == name:
contact = c
break
if not contact:
messagebox.showerror("错误", "未找到选中的联系人")
return
# 使用新的详情窗口类
ContactDetailWindow(self.root, contact)
def on_double_click(self, event):
"""双击联系人查看详情"""
self.view_details()
def filter_by_region(self):
"""按地区筛选联系人"""
region = simpledialog.askstring("按地区筛选", "请输入地区:")
if region:
results = self.address_book.get_contacts_by_region(region)
if results:
self.refresh_contact_list(results)
messagebox.showinfo("筛选结果", f"在 {region} 地区找到 {len(results)} 个联系人")
else:
messagebox.showinfo("筛选结果", f"在 {region} 地区没有找到联系人")
def filter_by_company(self):
"""按单位筛选联系人"""
company = simpledialog.askstring("按单位筛选", "请输入单位:")
if company:
results = self.address_book.get_contacts_by_company(company)
if results:
self.refresh_contact_list(results)
messagebox.showinfo("筛选结果", f"在 {company} 单位找到 {len(results)} 个联系人")
else:
messagebox.showinfo("筛选结果", f"在 {company} 单位没有找到联系人")
def filter_by_title(self):
"""按职务筛选联系人"""
title = simpledialog.askstring("按职务筛选", "请输入职务:")
if title:
results = self.address_book.get_contacts_by_title(title)
if results:
self.refresh_contact_list(results)
messagebox.showinfo("筛选结果", f"职务为 {title} 的联系人有 {len(results)} 个")
else:
messagebox.showinfo("筛选结果", f"没有找到职务为 {title} 的联系人")
def main():
"""主函数"""
root = tk.Tk()
app = AddressBookGUI(root)
root.mainloop()
if __name__ == "__main__":
main()
最新发布