From 5b694a84a2d4e5869fdb8679a5bd60666f95548c Mon Sep 17 00:00:00 2001
From: unknown <3047705226@qq.com>
Date: Sun, 2 Jun 2024 01:50:45 +0800
Subject: [PATCH] *
---
.idea/.gitignore | 3 +
.idea/.name | 1 +
.../inspectionProfiles/profiles_settings.xml | 6 +
.idea/misc.xml | 7 +
.idea/modules.xml | 8 +
.idea/通讯录管理系统.iml | 10 +
contacts.csv | 3 +
data.db | 0
main.py | 335 ++++++++++++++++++
9 files changed, 373 insertions(+)
create mode 100644 .idea/.gitignore
create mode 100644 .idea/.name
create mode 100644 .idea/inspectionProfiles/profiles_settings.xml
create mode 100644 .idea/misc.xml
create mode 100644 .idea/modules.xml
create mode 100644 .idea/通讯录管理系统.iml
create mode 100644 contacts.csv
create mode 100644 data.db
create mode 100644 main.py
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..359bb53
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# 默认忽略的文件
+/shelf/
+/workspace.xml
diff --git a/.idea/.name b/.idea/.name
new file mode 100644
index 0000000..11a5d8e
--- /dev/null
+++ b/.idea/.name
@@ -0,0 +1 @@
+main.py
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..f758a2e
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..0710496
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/通讯录管理系统.iml b/.idea/通讯录管理系统.iml
new file mode 100644
index 0000000..74d515a
--- /dev/null
+++ b/.idea/通讯录管理系统.iml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/contacts.csv b/contacts.csv
new file mode 100644
index 0000000..2974ae0
--- /dev/null
+++ b/contacts.csv
@@ -0,0 +1,3 @@
+小欧,1111,株洲,株洲
+小于,1212,北京,北京
+1,1,,
diff --git a/data.db b/data.db
new file mode 100644
index 0000000..e69de29
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..7a67c8f
--- /dev/null
+++ b/main.py
@@ -0,0 +1,335 @@
+
+from tkinter import *
+from tkinter import font
+from tkinter import messagebox
+from os import path
+from os import remove
+
+
+# 添加、编辑联系人弹出框类
+class PopupWindow(object):
+ # 初始化构造及添加组件到弹出框
+ def __init__(self, master, main_window, title, contact=None):
+ self.main_window = main_window
+ top = self.top = Toplevel(master)
+ top.title(title)
+ top.resizable(False, False)
+ w = 280
+ h = 320
+ top.geometry('%dx%d+%d+%d' % (w, h, (ws - w) / 2, (hs - h) / 2))
+ top.bind('', lambda event: top.destroy())
+
+ m_font = font.Font(size=16)
+ l = Label(top, text="姓名:", font=m_font)
+ l.pack(side=TOP, pady=5)
+ self.e1 = Entry(top)
+ self.e1.pack(side=TOP, padx=16, ipady=3, fill=X)
+ self.e1.focus()
+ if contact is not None:
+ self.e1.insert(0, contact.name)
+
+ l2 = Label(top, text="电话号码:", font=m_font)
+ l2.pack(side=TOP, pady=5)
+ self.e2 = Entry(top)
+ self.e2.pack(side=TOP, padx=16, ipady=3, fill=X)
+ if contact is not None:
+ self.e2.insert(0, contact.phone_number)
+
+ l2 = Label(top, text="工作单位:", font=m_font)
+ l2.pack(side=TOP, pady=5)
+ self.e3 = Entry(top)
+ self.e3.pack(side=TOP, padx=16, ipady=3, fill=X)
+ if contact is not None:
+ self.e3.insert(0, contact.work_place)
+
+ l2 = Label(top, text="地址:", font=m_font)
+ l2.pack(side=TOP, pady=5)
+ self.e4 = Entry(top)
+ self.e4.pack(side=TOP, padx=16, ipady=3, fill=X)
+ if contact is not None:
+ self.e4.insert(0, contact.address)
+
+ if contact is None:
+ b2 = Button(top, text='添加', width=12, command=lambda: self.add_click(None))
+ self.e4.bind('', self.add_click)
+ else:
+ b2 = Button(top, text='编辑', width=12, command=lambda: self.edit_click(None))
+ self.e4.bind('', self.edit_click)
+ b2.pack(side=LEFT, pady=10, padx=20)
+ b3 = Button(top, text='取消', width=12, command=lambda: top.destroy())
+ b3.pack(side=RIGHT, pady=10, padx=20)
+
+ top.grab_set()
+
+ # 点击编辑联系人按钮
+ def edit_click(self, event):
+ e1_name = self.e1.get()
+ if not e1_name:
+ messagebox.showinfo("出错了", '名字不能为空!')
+ return
+ e2_name = self.e2.get()
+ if not e2_name:
+ messagebox.showinfo("出错了", '电话号码不能为空!')
+ return
+ e3_name = self.e3.get()
+ e4_name = self.e4.get()
+ self.main_window.edit_value(e1_name, e2_name, e3_name, e4_name)
+ self.top.destroy()
+
+ # 点击添加联系人按钮
+ def add_click(self, event):
+ e1_name = self.e1.get()
+ if not e1_name:
+ messagebox.showinfo("出错了", '名字不能为空!')
+ return
+ e2_name = self.e2.get()
+ if not e2_name:
+ messagebox.showinfo("出错了", '电话号码不能为空!')
+ return
+ e3_name = self.e3.get()
+ e4_name = self.e4.get()
+ self.main_window.add_value(e1_name, e2_name, e3_name, e4_name)
+ self.top.destroy()
+
+
+# 主界面类
+class MainWindow(object):
+ # 默认初始化构造
+ def __init__(self, root):
+ self.contacts = []
+ self.root = root
+ self.add_btn_widget()
+ self.add_search_widget()
+ self.add_listbox_widget()
+ self.add_statusbar_widget()
+ self.read_save_contacts()
+ self.sel_item = 0
+
+ # 添加操作按钮
+ def add_btn_widget(self):
+ frame = Frame(self.root)
+ frame.pack(pady=8)
+ self.addBtn = Button(frame, text='添加联系人', width=15, command=lambda: self.popup("添加联系人"))
+ self.addBtn.pack(padx=5, fill=X, side=LEFT)
+ self.delAllBtn = Button(frame, text='删除所有联系人', width=15, command=self.del_all_contacts)
+ self.delAllBtn.pack(padx=5, fill=X, side=LEFT)
+ self.saveAllBtn = Button(frame, text='保存所有联系人', width=15, command=self.save_all_contacts)
+ self.saveAllBtn.pack(padx=5, fill=X, side=LEFT)
+
+ # 添加搜索框
+ def add_search_widget(self):
+ frame = Frame(self.root)
+ frame.pack(pady=8)
+ entry1 = self.input_view = Entry(frame, width=34)
+ entry1.insert(0, '输入部分姓名或电话号码按回车查询')
+ entry1.bind("", self.click_input)
+ entry1.bind("", self.focusout_input)
+ entry1.bind('', self.search_contact)
+ entry1.bind('', self.cancel_search)
+ entry1.pack(ipady=3, padx=5, side=LEFT)
+ entry1.selection_range(0, len(entry1.get()))
+ entry1.focus()
+ command4 = self.search_btn = Button(frame, text='清空输入', width=15, command=lambda: self.cancel_search(None))
+ command4["state"] = "disabled"
+ command4.pack(padx=5, side=LEFT)
+
+ # 点击输入框清空内容
+ def click_input(self, event):
+ if self.input_view.get() == '输入部分姓名或电话号码按回车查询':
+ self.input_view.delete(0, END)
+
+ # 输入框失去焦点时
+ def focusout_input(self, event):
+ if len(self.input_view.get()) == 0:
+ self.input_view.insert(0, '输入部分姓名或电话号码按回车查询')
+
+ # 添加列表及滚动条
+ def add_listbox_widget(self):
+ frame = Frame(self.root)
+ frame.pack(pady=8)
+ bolded = font.Font(size=20)
+ self.lb = Listbox(frame, font=bolded, height=14, width=25, borderwidth=0)
+ scrollbar = Scrollbar(frame, orient=VERTICAL)
+ scrollbar.config(command=self.lb.yview)
+ scrollbar.pack(side=RIGHT, fill=Y)
+ self.lb.config(yscrollcommand=scrollbar.set, activestyle='none')
+ scrollbar2 = Scrollbar(frame, orient=HORIZONTAL)
+ scrollbar2.config(command=self.lb.xview)
+ scrollbar2.pack(side=BOTTOM, fill=X)
+ self.lb.config(xscrollcommand=scrollbar2.set, activestyle='none')
+ self.lb.pack(fill=BOTH)
+ self.lb.bind('', self.dbclick)
+ self.lb.bind('', self.rclick_popup)
+
+ # 添加界面底部联系人数
+ def add_statusbar_widget(self):
+ frame = Frame(self.root)
+ frame.pack(pady=8, side=LEFT)
+ self.label = Label(frame, text='>系统现有 0 位联系人<')
+ self.label.pack()
+
+ # 右键菜单
+ def rclick_popup(self, event):
+ a_menu = Menu(self.root, tearoff=0)
+ a_menu.add_command(label='编辑选中的联系人', command=self.edit_contact)
+ a_menu.add_command(label='删除选中的联系人', command=self.del_contact)
+ a_menu.post(event.x_root, event.y_root)
+
+ # 右键编辑选中的联系人
+ def edit_contact(self):
+ selection = self.lb.curselection()
+ if len(selection) == 0:
+ messagebox.showerror("出错了", '请先左键选中待操作的联系人!')
+ return
+ self.sel_item = selection[0]
+ self.right_clidk_reset()
+ contact = self.contacts[self.sel_item]
+ self.popup("编辑联系人", contact=contact)
+
+ # 右键删除选中的联系人
+ def del_contact(self):
+ selection = self.lb.curselection()
+ if len(selection) == 0:
+ messagebox.showerror("出错了", '请先左键选中待操作的联系人!')
+ return
+ self.right_clidk_reset()
+ answer = messagebox.askyesno("提示", "您确定要删除此联系人吗?")
+ if answer:
+ self.lb.delete(self.sel_item, self.sel_item)
+ self.contacts.pop(self.sel_item)
+ self.label.config(text='系统现有 %d 位联系人' % len(self.contacts))
+ messagebox.showinfo('提示', '联系人从列表删除成功!\n若需要保存操作结果,请点击“保存所有联系人”')
+
+ # 若是搜索后右键,则操作重置列表
+ def right_clidk_reset(self, is_dbclick=False):
+ b_text = self.search_btn["state"]
+ if b_text == "normal":
+ ic = -1
+ item = self.lb.selection_get()
+ if not is_dbclick:
+ self.cancel_search(None)
+ for ct in self.contacts:
+ ic += 1
+ if (ct.name in item) and (ct.phone_number in item):
+ break
+ self.sel_item = ic
+ self.lb.selection_set(ic, ic)
+
+ # 双击联系人条目
+ def dbclick(self, event):
+ selection = self.lb.curselection()
+ self.sel_item = selection[0]
+ self.right_clidk_reset(is_dbclick=True)
+ contact = self.contacts[self.sel_item]
+ wp = contact.work_place if len(contact.work_place) != 0 else '空'
+ ad = contact.address if len(contact.address) != 0 else '空'
+ msg = '姓名:%s\n电话:%s\n工作单位:%s\n地址:%s' % (contact.name, contact.phone_number, wp, ad)
+ messagebox.showinfo("详细信息", msg)
+
+ # 添加、编辑联系人弹窗
+ def popup(self, title, contact=None):
+ self.cancel_search(None)
+ self.w = PopupWindow(self.root, self, title, contact)
+ self.addBtn["state"] = "disabled"
+ self.root.wait_window(self.w.top)
+ self.addBtn["state"] = "normal"
+
+ # 删除所有联系人
+ def del_all_contacts(self):
+ self.cancel_search(None)
+ answer = messagebox.askyesno("提示", "您确定要删除所有联系人吗?")
+ if answer:
+ self.contacts.clear()
+ self.lb.delete(0, END)
+ remove("contacts.csv")
+ self.label.config(text='系统现有 %d 位联系人' % len(self.contacts))
+
+ # 保存联系人到文件
+ def save_all_contacts(self):
+ self.cancel_search(None)
+ f = open("contacts.csv", "w", encoding='utf-8')
+ for contact in self.contacts:
+ str = '%s,%s,%s,%s\n' % (contact.name, contact.phone_number, contact.work_place, contact.address)
+ f.write(str)
+ f.close()
+ messagebox.showinfo('提示', '保存 %d 位联系人到文件成功!' % len(self.contacts))
+
+ # 读取保存在文件的联系人
+ def read_save_contacts(self):
+ if not path.exists('contacts.csv'):
+ return
+ f = open("contacts.csv", "r", encoding='utf-8')
+ for line in f:
+ array = line.strip().split(',')
+ contact = Contact(array[0], array[1], array[2], array[3])
+ self.contacts.append(contact)
+ self.lb.insert(END, '%s Tel:%s' % (contact.name, contact.phone_number))
+ self.label.config(text='系统现有 %d 位联系人' % len(self.contacts))
+ f.close()
+
+ # 添加联系人回调
+ def add_value(self, name, phone_number, work_place, address):
+ contact = Contact(name, phone_number, work_place, address)
+ self.contacts.append(contact)
+ self.lb.insert(END, '%s Tel:%s' % (name, phone_number))
+ self.label.config(text='系统现有 %d 位联系人' % len(self.contacts))
+
+ # 编辑联系回调
+ def edit_value(self, name, phone_number, work_place, address):
+ contact = self.contacts[self.sel_item]
+ contact.name = name
+ contact.phone_number = phone_number
+ contact.work_place = work_place
+ contact.address = address
+ self.lb.delete(0, END)
+ for contact in self.contacts:
+ self.lb.insert(END, '%s Tel:%s' % (contact.name, contact.phone_number))
+ self.label.config(text='系统现有 %d 位联系人' % len(self.contacts))
+
+ # 搜索联系人方法
+ def search_contact(self, event):
+ self.search_btn["state"] = "normal"
+ self.lb.delete(0, END)
+ key = self.input_view.get().strip()
+ ci = 0
+ for contact in self.contacts:
+ if (key in contact.name) or (key in contact.phone_number):
+ self.lb.insert(END, '%s Tel:%s' % (contact.name, contact.phone_number))
+ ci += 1
+ self.label.config(text='查询到 %d 位联系人' % ci)
+
+ # 取消搜索
+ def cancel_search(self, event):
+ b_state = self.search_btn["state"]
+ if b_state == "normal":
+ self.search_btn["state"] = "disabled"
+ self.lb.delete(0, END)
+ self.input_view.delete(0, END)
+ self.input_view.insert(0, '输入部分姓名或电话号码按回车查询')
+ for contact in self.contacts:
+ self.lb.insert(END, '%s Tel:%s' % (contact.name, contact.phone_number))
+ self.label.config(text='系统现有 %d 位联系人' % len(self.contacts))
+ self.input_view.selection_range(0, len(self.input_view.get()))
+
+
+# 联系人类对象
+class Contact:
+ def __init__(self, name, phone_number, work_place, address):
+ self.name = name
+ self.phone_number = phone_number
+ self.work_place = work_place
+ self.address = address
+
+
+# 程序启动入口
+if __name__ == "__main__":
+ root = Tk()
+ root.wm_resizable(False, False)
+ root.title('通讯录管理系统')
+ w = 380
+ h = 560
+ ws = root.winfo_screenwidth()
+ hs = root.winfo_screenheight()
+ root.geometry('%dx%d+%d+%d' % (w, h, (ws - w) / 2, (hs - h) / 2))
+ m = MainWindow(root)
+ root.mainloop()
\ No newline at end of file