用 Python 開發名片管理系統

簡介

這是一個用 Python 開發的可視化的名片管理系統,主要實現名片的添加、刪除、修改三大功能。效果圖如下所示


首頁
添加頁面

思路分析

界面實現:使用 Tkinter 庫進行 GUI 界面設計開發。tkinter 是 python 內置的一套用于開發 GUI 程序的包。

數據存儲:1.0版本的數據在內存中以列表形式存儲,序列化到本地時使用文件存儲方案

# 所有數據集合
self.all_items = []

代碼結構:項目有三個窗口,分別是主界面、添加界面,修改界面,每一個界面使用一個類進行組織,并提供一個 show 方法,用于顯示窗口,因為添加和修改界面可以公用,所以只需定義兩個界面類即可。

  • 主界面:MainFrame
  • 添加/修改界面:InputFrame
    代碼結構如下所示


    類結構

    程序啟動時,新建主界面的實例對象,然后調用 show 方法即可運行程序。


    image.png

開發環境

  • 開發工具:Pycharm
  • 輔助包:tkinter

代碼實現

from tkinter import *
from tkinter import messagebox

# 定義一個主窗口界面類,其父類為 object
class MainFrame(object):
    # 初始化主窗口
    def __init__(self):
        # 初始化所有數據集合列表
        self.all_items = []
        # 使用Tk()函數創建頂級窗口(主窗口)
        self.root = Tk()
        # 窗口自定義名稱為“名片管理系統”
        self.root.title("名片管理系統")
        # 設置主窗口大小
        self.root.wm_minsize(width=400, height=300)

    # 定義 show 方法:顯示主窗口布局
    def show(self):
        # 顯示頂部區域信息
        self.addTopFrame()
        # 初始化信息列表區域
        self.initContent()
        # 從本地文件加載以存儲的信息
        self.loadData()
        # 顯示出所有的名片信息
        self.showAllItem()
        # 開啟主界面,進入主循環
        self.root.mainloop()

    # 定義 showAllItem 方法,顯示所有列表信息
    def showAllItem(self):
        # 遍歷循環所有的列表信息
        for data in self.all_items:
            # 添加信息到列表界面
            self.showItem(data)

    # 定義 save_2_file 方法,將已經添加的名片信息存儲到本地文件中
    def save_2_file(self):
        # 打開文件
        f = open("contacts.data", "w")
        # 將已經添加的信息以字符串形式寫入次文件
        f.write(str(self.all_items))
        # 關閉文件
        f.close()

    # 定義一個loadData方法,加載本地存儲文件中的所有數據
    def loadData(self):
        # 通過"try...except"異常點檢驗方法,檢查存儲名片信息的本地文件的存在性
        try:
            # 打開存儲名片信息的本地文件
            f = open("contacts.data")
            # 讀取本地文件中的所有數據
            self.all_items = eval(f.read())
            """eval 相關知識點以及用法
            功能:將字符串str當成有效的表達式來求值并返回計算結果。
          語法: eval(source[, globals[, locals]]) -> value
            參數:source:一個Python表達式或函數compile()返回的代碼對象
                  globals:可選。必須是dictionary
                  locals:可選。任意map對象"""
            f.close()
        except Exception:
            pass

    # 添加主窗口布局需要的控件
    def addTopFrame(self):
        # 添加一個框架將首頁的題目和添加按鈕都放在一起
        topFrame = Frame(self.root)
        # 在次框架中添加一個標簽,其題目:名片信息
        titlelable = Label(topFrame, text="名片信息")
        # 顯示框架,并設定向左排列,x和y軸的寬度均為5個像素
        titlelable.pack(side=LEFT, padx=5, pady=6)

        # 定義一個添加按鈕,其中command點擊事件通過lambda函數實現:調用showInputFrame
        addButton = Button(topFrame, text="添加", command=lambda : self.showInputFrame("添加",None))
        # 顯示按鈕,并設定向左排列,x和y軸的寬度均為默認像素
        addButton.pack(side=RIGHT)

        # 設置此框架的背景顏色為藍色
        topFrame.config(bg="#3f51b5")
        # 橫向填充
        topFrame.pack(fill=X)

    # 顯示添加頁面
    def showInputFrame(self,title,dict):
        # 定義 inputFrame 實例,即創建一個添加界面
        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):
        # 獲取原始數據列表的索引
        index = self.all_items.index(origin_data)
        # 將需要修改的內容從數據列表中移除
        self.all_items.remove(origin_data)
        # 添加修改后的名片信息到數據列表
        self.all_items.insert(index,new_data)
        # 將修改后的信息保存到本地文件夾
        self.save_2_file()

        # 為了讓修改后的信息整體生效,先將主界面上的所有信息都刪除
        self.remove_allItem()
        # 然后在主界面上重新顯示所有信息
        self.showAllItem()

    # 清空主界面上的每一行數據:
    def remove_allItem(self):
        # 通過for循環將主界面上的名片信息都逐一刪除
        for child_item in self.item_container.winfo_children():
            child_item.destroy()

    # 在主界面上顯示一行信息
    def showItem(self, dict):
        # 初始化主框架
        item_frame = Frame(self.item_container)

        # 添加姓名信息標簽
        name_label = Label(item_frame, text=dict['name'])
        name_label.pack(side=LEFT, padx=5, pady=5)

        # 添加性別信息標簽
        sex_label = Label(item_frame, text=dict['sex'])
        sex_label.pack(side=LEFT)

        # 添加手機號信息標簽
        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)

        # 將整個框架整體封裝
        item_frame.pack()

    # 刪除信息
    def delete_item(self, data,item_frame):
        # 從數據列表中刪除數據
        self.all_items.remove(data)
        # 將刪除后的信息存儲到本地文件
        self.save_2_file()
        # 在主界面中將刪除的這條信息移除
        item_frame.pack_forget()


# 定義了一個添加界面類,其父類為 object
class InputFrame(object):
    def __init__(self, mainFrame,title,dict):
        self.mainFrame = mainFrame
        self.data = dict
        # 初始化添加窗口
        self.inputRootFrame = Tk()
        # 設置這一窗口的題目
        self.inputRootFrame.title(title)
        # 設置窗口大小
        self.inputRootFrame.wm_minsize(width=200, height=250)


    def show(self):
        # 添加界面的展示信息
        self.addInputFrame()
        # 由于添加和編輯用了同一個界面,所以根據界面不同,按鈕的文本需要改變
        if self.data == None:
            self.addButtonFrame('保存')
        else:
            self.addButtonFrame('確定修改')

        self.inputRootFrame.mainloop()

    # 添加界面布局信息展示
    def addInputFrame(self):
        # 初始化姓名框架以及界面
        fmname = Frame(self.inputRootFrame)
        # 添加姓名標簽
        self.namelable = Label(fmname, text="姓名:")
        # 設置姓名標簽的位置以及大小
        self.namelable.pack(side=LEFT, padx=5, pady=10)
        # 添加姓名輸入框
        self.nameInput = Entry(fmname, width=50, textvariable=StringVar())
        # 設置姓名輸入框的位置
        self.nameInput.pack(side=LEFT)
        # 將以前的姓名自動填寫進來,便于用戶核對方便修改
        if self.data != None:
            self.nameInput.insert(0, self.data['name'])
            self.nameInput['state'] = DISABLED
        fmname.pack()

        # 初始化性別框架以及信息
        fmSex = Frame(self.inputRootFrame)
        # 添加性別標簽
        self.sexlable = Label(fmSex, text="性別:")
        # 設置性別標簽的位置
        self.sexlable.pack(side=LEFT, padx=5, pady=10)

        # 添加性別輸入框
        self.sexInput = Entry(fmSex, width=50, textvariable=StringVar())
        # 設置性別輸入框的位置
        self.sexInput.pack(side=LEFT)
        # 將以前的性別自動填寫進來,便于用戶核對方便修改
        if self.data != None:
            self.sexInput.insert(0, self.data['sex'])
        fmSex.pack()

        # 初始化手機號的框架以及顯示內容
        fmMob = Frame(self.inputRootFrame)
        # 添加手機號標簽
        moblelable = Label(fmMob, text="手機號:")
        # 設置手機號標簽的位置
        moblelable.pack(side=LEFT, padx=5, pady=10)
        # 添加手機號輸入框
        self.mobleInput = Entry(fmMob, width=50, textvariable=StringVar())
        # 設置手機號輸入框的位置
        self.mobleInput.pack(side=LEFT)
        # 將以前的手機號自動填寫進來,便于用戶核對方便修改
        if self.data != None:
            self.mobleInput.insert(0, self.data['mobile'])
        fmMob.pack()

    # 添加界面的按鈕設置
    def addButtonFrame(self,title):
        # 初始化框架
        fmButton = Frame(self.inputRootFrame)
        # 設置框架位置
        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)

    # 名片信息存儲
    def saveInput(self):
        # 獲取輸入的姓名
        name = self.nameInput.get()
        # 獲取輸入的性別
        sex = self.sexInput.get()
        # 獲取輸入的手機號
        mobile = self.mobleInput.get()

        # 確保輸入的姓名不為空
        if name == None or name == '':
            messagebox.showinfo("提示","請輸入姓名!")
            return
        # 確保輸入的性別不為空
        if sex == None or sex == '':
            messagebox.showinfo("提示","請輸入性別!")
            return
        # 確保輸入的性別為“男” 或者 “女”
        if sex != '男' and sex != '女':
            messagebox.showinfo("提示","請選擇男或者女!")
            return

        # 確保輸入的手機號不為空
        if mobile == None or mobile == '':
            messagebox.showinfo("提示","請輸入手機號!")
            return

        # 將輸入的整條名片信息以字典的形式存儲
        info = {'name': name, 'sex': sex, 'mobile': mobile}
        # 如果在添加頁面添加數據成功后,就把數據更新到主界面
        if self.data == None:
            self.mainFrame.addItem(info)
        else:
            self.mainFrame.updateItem(self.data,info)
        # 返回主界面
        self.inputRootFrame.destroy()

    # 點擊修改頁面上的“取消”按鈕,就返回到主界面上
    def cancelInput(self):
        self.inputRootFrame.destroy()


# 程序入口
if __name__ == '__main__':
    # 創建一個 main frame 對象,即創建一個主窗口實例
    mainFrame = MainFrame()
    # 調用主窗口的show()方法顯示主窗口
    mainFrame.show()

總結

最後編輯於
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,578評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,701評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,691評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,974評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,694評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,026評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,015評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,193評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,719評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,442評論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,668評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,151評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,846評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,255評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,592評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,394評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,635評論 2 380

推薦閱讀更多精彩內容