簡(jiǎn)介
這是一個(gè)用 Python 開發(fā)的可視化的名片管理系統(tǒng),主要實(shí)現(xiàn)名片的添加、刪除、修改三大功能。效果圖如下所示

首頁(yè)

添加頁(yè)面
思路分析
界面實(shí)現(xiàn):使用 Tkinter 庫(kù)進(jìn)行 GUI 界面設(shè)計(jì)開發(fā)。tkinter 是 python 內(nèi)置的一套用于開發(fā) GUI 程序的包。
數(shù)據(jù)存儲(chǔ):1.0版本的數(shù)據(jù)在內(nèi)存中以列表形式存儲(chǔ),序列化到本地時(shí)使用文件存儲(chǔ)方案
# 所有數(shù)據(jù)集合
self.all_items = []
代碼結(jié)構(gòu):項(xiàng)目有三個(gè)窗口,分別是主界面、添加界面,修改界面,每一個(gè)界面使用一個(gè)類進(jìn)行組織,并提供一個(gè) show 方法,用于顯示窗口,因?yàn)樘砑雍托薷慕缑婵梢怨?,所以只需定義兩個(gè)界面類即可。
- 主界面:MainFrame
-
添加/修改界面:InputFrame
代碼結(jié)構(gòu)如下所示
類結(jié)構(gòu)
程序啟動(dòng)時(shí),新建主界面的實(shí)例對(duì)象,然后調(diào)用 show 方法即可運(yùn)行程序。
image.png
開發(fā)環(huán)境
- 開發(fā)工具:Pycharm
- 輔助包:tkinter
代碼實(shí)現(xiàn)
from tkinter import *
from tkinter import messagebox
# 定義一個(gè)主窗口界面類,其父類為 object
class MainFrame(object):
# 初始化主窗口
def __init__(self):
# 初始化所有數(shù)據(jù)集合列表
self.all_items = []
# 使用Tk()函數(shù)創(chuàng)建頂級(jí)窗口(主窗口)
self.root = Tk()
# 窗口自定義名稱為“名片管理系統(tǒng)”
self.root.title("名片管理系統(tǒng)")
# 設(shè)置主窗口大小
self.root.wm_minsize(width=400, height=300)
# 定義 show 方法:顯示主窗口布局
def show(self):
# 顯示頂部區(qū)域信息
self.addTopFrame()
# 初始化信息列表區(qū)域
self.initContent()
# 從本地文件加載以存儲(chǔ)的信息
self.loadData()
# 顯示出所有的名片信息
self.showAllItem()
# 開啟主界面,進(jìn)入主循環(huán)
self.root.mainloop()
# 定義 showAllItem 方法,顯示所有列表信息
def showAllItem(self):
# 遍歷循環(huán)所有的列表信息
for data in self.all_items:
# 添加信息到列表界面
self.showItem(data)
# 定義 save_2_file 方法,將已經(jīng)添加的名片信息存儲(chǔ)到本地文件中
def save_2_file(self):
# 打開文件
f = open("contacts.data", "w")
# 將已經(jīng)添加的信息以字符串形式寫入次文件
f.write(str(self.all_items))
# 關(guān)閉文件
f.close()
# 定義一個(gè)loadData方法,加載本地存儲(chǔ)文件中的所有數(shù)據(jù)
def loadData(self):
# 通過"try...except"異常點(diǎn)檢驗(yàn)方法,檢查存儲(chǔ)名片信息的本地文件的存在性
try:
# 打開存儲(chǔ)名片信息的本地文件
f = open("contacts.data")
# 讀取本地文件中的所有數(shù)據(jù)
self.all_items = eval(f.read())
"""eval 相關(guān)知識(shí)點(diǎn)以及用法
功能:將字符串str當(dāng)成有效的表達(dá)式來求值并返回計(jì)算結(jié)果。
語(yǔ)法: eval(source[, globals[, locals]]) -> value
參數(shù):source:一個(gè)Python表達(dá)式或函數(shù)compile()返回的代碼對(duì)象
globals:可選。必須是dictionary
locals:可選。任意map對(duì)象"""
f.close()
except Exception:
pass
# 添加主窗口布局需要的控件
def addTopFrame(self):
# 添加一個(gè)框架將首頁(yè)的題目和添加按鈕都放在一起
topFrame = Frame(self.root)
# 在次框架中添加一個(gè)標(biāo)簽,其題目:名片信息
titlelable = Label(topFrame, text="名片信息")
# 顯示框架,并設(shè)定向左排列,x和y軸的寬度均為5個(gè)像素
titlelable.pack(side=LEFT, padx=5, pady=6)
# 定義一個(gè)添加按鈕,其中command點(diǎn)擊事件通過lambda函數(shù)實(shí)現(xiàn):調(diào)用showInputFrame
addButton = Button(topFrame, text="添加", command=lambda : self.showInputFrame("添加",None))
# 顯示按鈕,并設(shè)定向左排列,x和y軸的寬度均為默認(rèn)像素
addButton.pack(side=RIGHT)
# 設(shè)置此框架的背景顏色為藍(lán)色
topFrame.config(bg="#3f51b5")
# 橫向填充
topFrame.pack(fill=X)
# 顯示添加頁(yè)面
def showInputFrame(self,title,dict):
# 定義 inputFrame 實(shí)例,即創(chuàng)建一個(gè)添加界面
self.inputFrame = InputFrame(self,title,dict)
# 顯示添加界面
self.inputFrame.show()
# 顯示列表信息
def initContent(self):
# 初始化列表框架
self.item_container = Frame(self.root)
# 將這一框架整體整合
self.item_container.pack()
# 添加名片信息
def addItem(self, dict):
# 添加新信息到 all_items 列表
self.all_items.append(dict)
# 顯示名片信息
self.showItem(dict)
# 將信息保存到本地文件夾
self.save_2_file()
# 修改信息
def updateItem(self, origin_data,new_data):
# 獲取原始數(shù)據(jù)列表的索引
index = self.all_items.index(origin_data)
# 將需要修改的內(nèi)容從數(shù)據(jù)列表中移除
self.all_items.remove(origin_data)
# 添加修改后的名片信息到數(shù)據(jù)列表
self.all_items.insert(index,new_data)
# 將修改后的信息保存到本地文件夾
self.save_2_file()
# 為了讓修改后的信息整體生效,先將主界面上的所有信息都刪除
self.remove_allItem()
# 然后在主界面上重新顯示所有信息
self.showAllItem()
# 清空主界面上的每一行數(shù)據(jù):
def remove_allItem(self):
# 通過for循環(huán)將主界面上的名片信息都逐一刪除
for child_item in self.item_container.winfo_children():
child_item.destroy()
# 在主界面上顯示一行信息
def showItem(self, dict):
# 初始化主框架
item_frame = Frame(self.item_container)
# 添加姓名信息標(biāo)簽
name_label = Label(item_frame, text=dict['name'])
name_label.pack(side=LEFT, padx=5, pady=5)
# 添加性別信息標(biāo)簽
sex_label = Label(item_frame, text=dict['sex'])
sex_label.pack(side=LEFT)
# 添加手機(jī)號(hào)信息標(biāo)簽
mob_label = Label(item_frame, text=dict['mobile'])
mob_label.pack(side=LEFT)
# 添加刪除按鈕
delete_button = Button(item_frame, text="刪除", command=lambda: self.delete_item(dict,item_frame))
# delete_button = Button(f2, text="刪除", command=lambda dict : self.all_items.remove(dict))
delete_button.pack(side=LEFT)
# 添加修改按鈕
update_button = Button(item_frame, text="修改",command=lambda : self.showInputFrame("修改",dict))
update_button.pack(side=LEFT)
# 將整個(gè)框架整體封裝
item_frame.pack()
# 刪除信息
def delete_item(self, data,item_frame):
# 從數(shù)據(jù)列表中刪除數(shù)據(jù)
self.all_items.remove(data)
# 將刪除后的信息存儲(chǔ)到本地文件
self.save_2_file()
# 在主界面中將刪除的這條信息移除
item_frame.pack_forget()
# 定義了一個(gè)添加界面類,其父類為 object
class InputFrame(object):
def __init__(self, mainFrame,title,dict):
self.mainFrame = mainFrame
self.data = dict
# 初始化添加窗口
self.inputRootFrame = Tk()
# 設(shè)置這一窗口的題目
self.inputRootFrame.title(title)
# 設(shè)置窗口大小
self.inputRootFrame.wm_minsize(width=200, height=250)
def show(self):
# 添加界面的展示信息
self.addInputFrame()
# 由于添加和編輯用了同一個(gè)界面,所以根據(jù)界面不同,按鈕的文本需要改變
if self.data == None:
self.addButtonFrame('保存')
else:
self.addButtonFrame('確定修改')
self.inputRootFrame.mainloop()
# 添加界面布局信息展示
def addInputFrame(self):
# 初始化姓名框架以及界面
fmname = Frame(self.inputRootFrame)
# 添加姓名標(biāo)簽
self.namelable = Label(fmname, text="姓名:")
# 設(shè)置姓名標(biāo)簽的位置以及大小
self.namelable.pack(side=LEFT, padx=5, pady=10)
# 添加姓名輸入框
self.nameInput = Entry(fmname, width=50, textvariable=StringVar())
# 設(shè)置姓名輸入框的位置
self.nameInput.pack(side=LEFT)
# 將以前的姓名自動(dòng)填寫進(jìn)來,便于用戶核對(duì)方便修改
if self.data != None:
self.nameInput.insert(0, self.data['name'])
self.nameInput['state'] = DISABLED
fmname.pack()
# 初始化性別框架以及信息
fmSex = Frame(self.inputRootFrame)
# 添加性別標(biāo)簽
self.sexlable = Label(fmSex, text="性別:")
# 設(shè)置性別標(biāo)簽的位置
self.sexlable.pack(side=LEFT, padx=5, pady=10)
# 添加性別輸入框
self.sexInput = Entry(fmSex, width=50, textvariable=StringVar())
# 設(shè)置性別輸入框的位置
self.sexInput.pack(side=LEFT)
# 將以前的性別自動(dòng)填寫進(jìn)來,便于用戶核對(duì)方便修改
if self.data != None:
self.sexInput.insert(0, self.data['sex'])
fmSex.pack()
# 初始化手機(jī)號(hào)的框架以及顯示內(nèi)容
fmMob = Frame(self.inputRootFrame)
# 添加手機(jī)號(hào)標(biāo)簽
moblelable = Label(fmMob, text="手機(jī)號(hào):")
# 設(shè)置手機(jī)號(hào)標(biāo)簽的位置
moblelable.pack(side=LEFT, padx=5, pady=10)
# 添加手機(jī)號(hào)輸入框
self.mobleInput = Entry(fmMob, width=50, textvariable=StringVar())
# 設(shè)置手機(jī)號(hào)輸入框的位置
self.mobleInput.pack(side=LEFT)
# 將以前的手機(jī)號(hào)自動(dòng)填寫進(jìn)來,便于用戶核對(duì)方便修改
if self.data != None:
self.mobleInput.insert(0, self.data['mobile'])
fmMob.pack()
# 添加界面的按鈕設(shè)置
def addButtonFrame(self,title):
# 初始化框架
fmButton = Frame(self.inputRootFrame)
# 設(shè)置框架位置
fmButton.pack(side=BOTTOM, anchor=W, fill=X)
# 添加保存按鈕
confrmButton = Button(fmButton, text=title, command=self.saveInput)
confrmButton.pack(side=RIGHT, fill=BOTH)
# 添加取消按鈕
cencelButton = Button(fmButton, text="取消", command=self.cancelInput)
cencelButton.pack(side=RIGHT)
# 名片信息存儲(chǔ)
def saveInput(self):
# 獲取輸入的姓名
name = self.nameInput.get()
# 獲取輸入的性別
sex = self.sexInput.get()
# 獲取輸入的手機(jī)號(hào)
mobile = self.mobleInput.get()
# 確保輸入的姓名不為空
if name == None or name == '':
messagebox.showinfo("提示","請(qǐng)輸入姓名!")
return
# 確保輸入的性別不為空
if sex == None or sex == '':
messagebox.showinfo("提示","請(qǐng)輸入性別!")
return
# 確保輸入的性別為“男” 或者 “女”
if sex != '男' and sex != '女':
messagebox.showinfo("提示","請(qǐng)選擇男或者女!")
return
# 確保輸入的手機(jī)號(hào)不為空
if mobile == None or mobile == '':
messagebox.showinfo("提示","請(qǐng)輸入手機(jī)號(hào)!")
return
# 將輸入的整條名片信息以字典的形式存儲(chǔ)
info = {'name': name, 'sex': sex, 'mobile': mobile}
# 如果在添加頁(yè)面添加數(shù)據(jù)成功后,就把數(shù)據(jù)更新到主界面
if self.data == None:
self.mainFrame.addItem(info)
else:
self.mainFrame.updateItem(self.data,info)
# 返回主界面
self.inputRootFrame.destroy()
# 點(diǎn)擊修改頁(yè)面上的“取消”按鈕,就返回到主界面上
def cancelInput(self):
self.inputRootFrame.destroy()
# 程序入口
if __name__ == '__main__':
# 創(chuàng)建一個(gè) main frame 對(duì)象,即創(chuàng)建一個(gè)主窗口實(shí)例
mainFrame = MainFrame()
# 調(diào)用主窗口的show()方法顯示主窗口
mainFrame.show()

