通讯录管理程序设计与实现(Python实现)

(代码较长,不过功能清晰,读者可视情况选取)
(图片未能正常上传,读者可自行运行查看)
一、实验目的与要求
实验目的:锻炼面向对象编程与文件操作能力。
实验要求:
1、熟悉VC++、Visual Studio c#或者Java编程环境。
2、运用面向对象知识对实验题目进行分析和设计。
3、进行程序编写和调试工作。

二、实验内容
设计、实现一个具有通讯信息插入、修改、删除、显示、查询和统计功能的通讯录管理程序。程序设计功能及要求:
1、人数不定,数据使用文件存放。
2、记录每位同学的学号、姓名、性别、工作单位、电话号码和E-mail地址建立单独的条目,存入数据文件。
3、可对记录中的姓名和电话号码等进行修改。
4、可增加或删除记录。
5、可显示所有保存的记录。
6、可以统计男女同学或总人数。
7、通过姓名、学号或电话号码查询到同学的条目。
8、在开始画面加入简单的菜单便于选择功能。
9、储存数据文件格式:
学号 姓名 性别 工作单位 电话号码 E-mail
1 李四 …. …. ….
10、选做:加入文件加密系统,对储存数据文件进行简单的加密,要求通过直接打开储存数据文件无法获得其中的数据。但同时不影响程序对储存数据文件的调用。

三、实验设计
本次实验同样采用python编程环境,通讯录人员信息采用字典类型,各项操作如添加、更改、删除、搜索、统计、存入文件、读取文件等都在字典的基础上进行,以下为此通讯录管理系统包含的各项功能及其设计方法:
1)通讯录人员文件(通讯录.txt)的存入及读取功能:
存入操作设计:因python无法直接将字典类型数据存入文件,故先将包含成员信息的字典转化为字符串(使用str()语句),后存入文件即可。
读取操作设计:调用read()函数从文件中取出字符串,使用eval()函数将其转化为字典,再使用copy模块中的deepcopy()函数拷贝给notes1,在note1上进行操作。
2)添加功能设计:
读取文件,同时打开弹窗,由用户输入各项信息,点击录入按钮。若学号已存在,则显示“该学号已存在”,否则添加信息,并将所得信息写入文件,此时显示“录入成功”。
3)删除功能设计:
读取文件,同时打开弹窗,为防止用户误删,采用姓名与学号同时锁定对象进行删除。由用户输入学号与姓名,点击删除按钮。若学号不存在,则显示“学生不存在!”,若姓名与学号不匹配,则显示“学号与姓名不匹配!”,删除操作采用pop()函数,最后将更改后的信息写入文件,此时显示“删除成功!”。
4)修改功能设计:
读取文件,同时打开弹窗,由用户输入学生学号,随后选择修改项目,在相应的文本框中输入修改结果,点击修改即可,最后将修改后的信息写入文件,此时显示“修改成功!”。
5)搜索功能设计:
此处提供三种可搜索项,用户可通过学号、姓名、电话号进行搜索。首先读取文件,同时打开弹窗,有用户输入检索语句,点击搜索按钮,下方即显示要搜索学生的所有信息。
6)统计功能设计:
此处提供三种统计功能,分别可统计人员总数、男生总数、女生总数。首先读取文件,对文件中的数据进行依次遍历匹配,匹配成功则计数器加一,最终在弹窗上显示结果。
7)菜单设计:
将鼠标的触发位置(二维参数)以post()方法传递给菜单,并将根窗体与鼠标右击响应事件绑定,此时在电脑的上方则会出现菜单栏,添加各项功能语句,并分别与内部函数绑定,使用户在点击时会调出相应的弹窗进行操作。
8)显示界面设计:
读取文件,将信息依次遍历并展现在所设画布中,由于python中无法使画布刷新或重新绘制,本人设立了旗帜flag,并引入全局变量t,使其在下方直接输出信息展现给用户,并有分割线方便用户明确最新信息。

四、核心程序代码

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#import pickle as p
import copy
# class person:
#     def write(self):
#       f = open('通讯录.txt','wb+')
#       p.dump(person.notes,f)    #数据封装
#       f.close()
#
#     def read(self):
#       file = '通讯录.txt'
#       try:
#         f = open(file ,'rb+')
#         person.notes = p.load(f)    #从数据文件中读取数据
#         f.close()
#       except:
#         f = open(file ,'w')
#         f.close()
#
# people = person()
# people.read()

#以下开始界面设计
# -*- coding:utf-8 -*-
from tkinter import *
HEIGHT = 5000
WIDTH = 5000
root = Tk()
root.title('可视化通讯录管理系统')
root.geometry('900x800')
#画布设计
# canvas = Canvas(root,height=HEIGHT,width=WIDTH,bg='#80c1ff')
# canvas.pack()

#此处为各个标题的设计
lb1 = Label(root,text='学号',font=('黑体',16,'bold'))
lb1.place(relx=0.05,rely=0.02)
lb2 = Label(root,text='姓名',font=('黑体',16,'bold'))
lb2.place(relx=0.17,rely=0.02)
lb3 = Label(root,text='性别',font=('黑体',16,'bold'))
lb3.place(relx=0.29,rely=0.02)
lb4 = Label(root,text='工作单位',font=('黑体',16,'bold'))
lb4.place(relx=0.41,rely=0.02)
lb5 = Label(root,text='电话号码',font=('黑体',16,'bold'))
lb5.place(relx=0.6,rely=0.02)
lb6 = Label(root,text='E-mail',font=('黑体',16,'bold'))
lb6.place(relx=0.8,rely=0.02)

#frame = Frame(root,bg='#80c1ff',bd=5)
flag = 1
t = 0
#显示/刷新操作
def Show():
    fr = open("通讯录.txt", 'r+')
    s1 = fr.read()
    if len(s1):
        note = eval(s1)  # 读取的str转化为字典
        notes1 = copy.deepcopy(note)
    else:
        notes1={}
    fr.close()
    global t
    global flag
    if flag == 0:
        t = t + 1
    else:
        flag = 0
    for i in notes1.keys():
        label = Label(root, text='%s' % i, font=('宋体',14))
        label.place(relx=0.05, rely=0.06 + 0.03 * t)
        label = Label(root, text='%s' % notes1[i]['姓名'], font=('宋体', 14))
        label.place(relx=0.17, rely=0.06 + 0.03 * t)
        label = Label(root, text='%s' % notes1[i]['性别'], font=('宋体', 14))
        label.place(relx=0.29, rely=0.06 + 0.03 * t)
        label = Label(root, text='%s' % notes1[i]['工作单位'], font=('宋体', 14))
        label.place(relx=0.41, rely=0.06 + 0.03 * t)
        label = Label(root, text='%s' % notes1[i]['电话'], font=('宋体', 14))
        label.place(relx=0.6, rely=0.06 + 0.03 * t)
        label = Label(root, text='%s' % notes1[i]['E-mail'], font=('宋体', 14))
        label.place(relx=0.8, rely=0.06 + 0.03 * t)
        t = t+1
    label1 = Label(root,text='_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ' '_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _' '_ _ _ _以上为最新纪录',font=0.5)
    label1.place(relx=0.05,rely=0.06+0.03*t)

#子窗体设计
#插入 _add 子窗体
def newwind_add():
    winNew = Toplevel(root)
    winNew.geometry('320x240')
    winNew.title('插入')
    #各个录入提示
    lb_1 = Label(winNew,text='请按以下要求依次输入!')
    lb_1.place(relx=0.29,rely=0.05)
    lb_1_1 = Label(winNew,text='学号:')
    lb_1_1.place(relx=0.08,rely=0.18)
    lb_1_2 = Label(winNew, text='姓名:')
    lb_1_2.place(relx=0.08, rely=0.3)
    lb_1_3 = Label(winNew, text='性别:')
    lb_1_3.place(relx=0.08, rely=0.42)
    lb_1_4 = Label(winNew, text='工作单位:')
    lb_1_4.place(relx=0.08, rely=0.54)
    lb_1_5 = Label(winNew, text='电话号码:')
    lb_1_5.place(relx=0.08, rely=0.66)
    lb_1_6 = Label(winNew, text='E-mail:')
    lb_1_6.place(relx=0.09, rely=0.78)
    #各个录入条框
    e1 = StringVar()
    entry1 = Entry(winNew,textvariable=e1)
    entry1.place(relx=0.3,rely=0.18)
    e2 = StringVar()
    entry2 = Entry(winNew, textvariable=e2)
    entry2.place(relx=0.3, rely=0.3)
    e3 = StringVar()
    entry3 = Entry(winNew, textvariable=e3)
    entry3.place(relx=0.3, rely=0.42)
    e4 = StringVar()
    entry4 = Entry(winNew, textvariable=e4)
    entry4.place(relx=0.3, rely=0.54)
    e5 = StringVar()
    entry5 = Entry(winNew, textvariable=e5)
    entry5.place(relx=0.3, rely=0.66)
    e6 = StringVar()
    entry6 = Entry(winNew, textvariable=e6)
    entry6.place(relx=0.3, rely=0.78)
    def add():      #插入成员函数
        fr = open("通讯录.txt",'w+')
        s1 = fr.read()
        if len(s1):
            note = eval(s1)   #读取的str转化为字典
            notes1 = copy.deepcopy(note)
        else:
            notes1 = {}
        fr.close()
        id = e1.get()
        if id in notes1:
            lb_1_8 = Label(winNew, text='该学号已存在!')
            lb_1_8.place(relx=0.5, rely=0.9)
        else:
            name = e2.get()
            sex = e3.get()
            workspace = e4.get()
            telephone = e5.get()
            email = e6.get()
            label = {'姓名': name, '性别': sex, '工作单位': workspace, '电话': telephone, 'E-mail': email}
            notes1[id] = label
            lb_1_7 = Label(winNew, text='录入成功!')
            lb_1_7.place(relx=0.5, rely=0.9)
            fw = open("通讯录.txt","w+")
            fw.write(str(notes1))    #把字典转化为str
            fw.close()
    #录入按钮设计
    btAdd = Button(winNew,text='录入',command=add)
    btAdd.place(relx=0.4,rely=0.9)
    #退出按钮设计
    btClose=Button(winNew,text='退出',command=winNew.destroy)
    btClose.place(relx=0.88,rely=0.9)

#删除学生子窗体
def newwind_del():
    fr = open("通讯录.txt", 'r+')
    s1 = fr.read()
    if len(s1):
        note = eval(s1)  # 读取的str转化为字典
        notes1 = copy.deepcopy(note)
    else:
        notes1={}
    fr.close()
    DelNew = Toplevel(root)
    DelNew.geometry('600x240')
    DelNew.title('删除')
    lb_2_1 = Label(DelNew, text='请输入要删除学生学号:')
    lb_2_1.pack()
    e7 = StringVar()
    entry1 = Entry(DelNew,textvariable=e7)
    entry1.pack()
    lb_2_2 = Label(DelNew, text= '请输入要删除学生姓名:')
    lb_2_2.pack()
    e8 = StringVar()
    entry2 = Entry(DelNew,textvariable=e8)
    entry2.pack()
    def mydel():    #为防止误删,此处用姓名与学号同时锁定对象
        id = e7.get()
        name = e8.get()
        if id in notes1:
            if name == notes1[id]['姓名']:
                e = notes1.pop(id)
                lb_2_3 = Label(DelNew, text='删除成功!')
                lb_2_3.pack()
                fw = open("通讯录.txt", "w+")
                fw.write(str(notes1))  # 把字典转化为str
                fw.close()
            else:
                lb_2_3 = Label(DelNew, text='学号与姓名不匹配!')
                lb_2_3.pack()
        else:
            lb_2_3 = Label(DelNew, text='学生不存在!')
            lb_2_3.pack()
    btDel = Button(DelNew,text='删除',command=mydel)
    btDel.pack()
    btClose = Button(DelNew,text='退出',command=DelNew.destroy)
    btClose.pack()


#修改学生子窗体
def newwind_modi():

    ModiNew = Toplevel(root)
    ModiNew.geometry('500x600')
    ModiNew.title('修改')
    lb_3_1 = Label(ModiNew, text='请输入要修改学生学号:')
    lb_3_1.pack()
    e9 = StringVar()
    entry1 = Entry(ModiNew, textvariable=e9)
    entry1.pack()

    def modi_name():
        fr = open("通讯录.txt", 'r+')
        s1 = fr.read()
        if len(s1):
            note = eval(s1)  # 读取的str转化为字典
            notes1 = copy.deepcopy(note)
        else:
            notes1 = {}
        fr.close()
        id = e9.get()
        lb_3_3 = Label(ModiNew, text='要修改学生姓名为:')
        lb_3_3.pack()
        e10 = StringVar()
        entry_1 = Entry(ModiNew, textvariable=e10)
        entry_1.pack()
        def name2():
            notes1[id]['姓名'] = e10.get()
            lb_3_8 = Label(ModiNew, text='修改成功!')
            lb_3_8.pack()
            fw = open("通讯录.txt", "w")
            fw.write(str(notes1))  # 把字典转化为str
            fw.close()
        btCtl = Button(ModiNew, text='修改', command=name2)
        btCtl.pack()



    def modi_sex():
        fr = open("通讯录.txt", 'r+')
        s1 = fr.read()
        if len(s1):
            note = eval(s1)  # 读取的str转化为字典
            notes1 = copy.deepcopy(note)
        else:
            notes1 = {}
        fr.close()
        id = e9.get()
        lb_3_4 = Label(ModiNew, text='要修改学生性别为:')
        lb_3_4.pack()
        e11 = StringVar()
        entry3 = Entry(ModiNew, textvariable=e11)
        entry3.pack()
        def sex2():
            notes1[id]['性别'] = e11.get()
            lb_3_8 = Label(ModiNew, text='修改成功!')
            lb_3_8.pack()
            fw = open("通讯录.txt", "w")
            fw.write(str(notes1))  # 把字典转化为str
            fw.close()
        btCtl = Button(ModiNew, text='修改', command=sex2)
        btCtl.pack()


    def modi_workspace():
        fr = open("通讯录.txt", 'r+')
        s1 = fr.read()
        if len(s1):
            note = eval(s1)  # 读取的str转化为字典
            notes1 = copy.deepcopy(note)
        else:
            notes1 = {}
        fr.close()
        id = e9.get()
        lb_3_5 = Label(ModiNew, text='要修改学生工作单位为:')
        lb_3_5.pack()
        e12 = StringVar()
        entry4 = Entry(ModiNew, textvariable=e12)
        entry4.pack()
        def workspace2():
            notes1[id]['工作单位'] = e12.get()
            lb_3_8 = Label(ModiNew, text='修改成功!')
            lb_3_8.pack()
            fw = open("通讯录.txt", "w")
            fw.write(str(notes1))  # 把字典转化为str
            fw.close()
        btCtl = Button(ModiNew, text='修改', command=workspace2)
        btCtl.pack()

    def modi_telephone():
        fr = open("通讯录.txt", 'r+')
        s1 = fr.read()
        if len(s1):
            note = eval(s1)  # 读取的str转化为字典
            notes1 = copy.deepcopy(note)
        else:
            notes1 = {}
        fr.close()
        id = e9.get()
        lb_3_6 = Label(ModiNew, text='要修改学生电话号码为:')
        lb_3_6.pack()
        e13 = StringVar()
        entry5 = Entry(ModiNew, textvariable=e13)
        entry5.pack()
        def telephone2():
            notes1[id]['电话'] = e13.get()
            lb_3_8 = Label(ModiNew, text='修改成功!')
            lb_3_8.pack()
            fw = open("通讯录.txt", "w")
            fw.write(str(notes1))  # 把字典转化为str
            fw.close()
        btCtl = Button(ModiNew, text='修改', command=telephone2)
        btCtl.pack()

    def modi_email():
        fr = open("通讯录.txt", 'r+')
        s1 = fr.read()
        if len(s1):
            note = eval(s1)  # 读取的str转化为字典
            notes1 = copy.deepcopy(note)
        else:
            notes1 = {}
        fr.close()
        id = e9.get()
        lb_3_7 = Label(ModiNew, text='要修改学生E-mail为:')
        lb_3_7.pack()
        e14 = StringVar()
        entry6 = Entry(ModiNew, textvariable=e14)
        entry6.pack()
        def email2():
            notes1[id]['E-mail'] = e14.get()
            lb_3_8 = Label(ModiNew, text='修改成功!')
            lb_3_8.pack()
            fw = open("通讯录.txt", "w")
            fw.write(str(notes1))  # 把字典转化为str
            fw.close()
        btCtl = Button(ModiNew, text='修改', command=email2)
        btCtl.pack()

    def modi_all():
        fr = open("通讯录.txt", 'r+')
        s1 = fr.read()
        if len(s1):
            note = eval(s1)  # 读取的str转化为字典
            notes1 = copy.deepcopy(note)
        else:
            notes1 = {}
        fr.close()
        id = e9.get()
        if id in notes1:
            lb_3_2 = Label(ModiNew, text='要修改学生项目为')
            lb_3_2.pack()
            btChoose1 = Button(ModiNew, text='姓名', command=modi_name)
            btChoose1.pack(side=LEFT,anchor=NW,ipadx=0.2)
            btChoose2 = Button(ModiNew, text='性别', command=modi_sex)
            btChoose2.pack(side=LEFT,anchor=NW,ipadx=0.2)
            btChoose3 = Button(ModiNew, text='工作单位', command=modi_workspace)
            btChoose3.pack(side=LEFT,anchor=NW,ipadx=0.2)
            btChoose4 = Button(ModiNew, text='电话号码', command=modi_telephone)
            btChoose4.pack(side=LEFT,anchor=NW,ipadx=0.2)
            btChoose5 = Button(ModiNew, text='E-mail', command=modi_email)
            btChoose5.pack(side=LEFT,anchor=NW,ipadx=0.2)
        else:
            lb_3_9 = Label(ModiNew, text='学生不存在!')
            lb_3_9.pack()
    btCtl = Button(ModiNew, text='修改', command=modi_all)
    btCtl.pack()
    btclose = Button(ModiNew, text='退出', command=ModiNew.destroy)
    btclose.place(relx=0.89,rely=0.89)

#搜索操作

#按学号查找子窗体:
def newwind_search1():
    fr = open("通讯录.txt", 'r+')
    s1 = fr.read()
    if len(s1):
        note = eval(s1)  # 读取的str转化为字典
        notes1 = copy.deepcopy(note)
    else:
        notes1 = {}
    fr.close()
    Se1New = Toplevel(root)
    Se1New.geometry('600x400')
    Se1New.title('按学号查找')
    lb_4_1 = Label(Se1New,text='请输入要查找学生学号:')
    lb_4_1.pack()
    e15 = StringVar()
    entry1 = Entry(Se1New,textvariable=e15)
    entry1.pack()
    def search1():
        id=e15.get()
        if id in notes1:
            lb_4_2 = Label(Se1New,text = '学号 %s 的姓名是 %s , 性别是 %s , 工作单位是 %s , 电话是 %s , E-mail是 %s'
                      % (id, notes1[id]['姓名'], notes1[id]['性别'], notes1[id]['工作单位'],
                         notes1[id]['电话'], notes1[id]['E-mail']))
            lb_4_2.pack()
        else:
            lb_4_3 = Label(Se1New,text='该学生不存在!')
            lb_4_3.pack()
    btse1 = Button(Se1New,text='搜索',command=search1)
    btse1.pack()

#按姓名查找子窗体:
def newwind_search2():
    fr = open("通讯录.txt", 'r+')
    s1 = fr.read()
    if len(s1):
        note = eval(s1)  # 读取的str转化为字典
        notes1 = copy.deepcopy(note)
    else:
        notes1 = {}
    fr.close()
    Se2New = Toplevel(root)
    Se2New.geometry('600x400')
    Se2New.title('按姓名查找')
    lb_5_1 = Label(Se2New,text='请输入要查找学生姓名:')
    lb_5_1.pack()
    e16 = StringVar()
    entry1 = Entry(Se2New,textvariable=e16)
    entry1.pack()
    def search2():
        name = e16.get()
        t = 0   #计数器
        for i in notes1.keys():
            t = t+1
            if notes1[i]['姓名'] == name:
                lb_5_2 = Label(Se2New,text='学号 %s 的姓名是 %s , 性别是 %s , 工作单位是 %s , 电话是 %s , E-mail是 %s'
                      % (i, notes1[i]['姓名'], notes1[i]['性别'], notes1[i]['工作单位'],
                         notes1[i]['电话'], notes1[i]['E-mail']))
                lb_5_2.pack()
                t = 0   #输出则计数器清零
        if t == len(notes1):
            lb_5_3 = Label(Se2New,text='该学生不存在!')
            lb_5_3.pack()
    btse2 = Button(Se2New, text='搜索', command=search2)
    btse2.pack()

#按电话号码查找子窗体:
def newwind_search3():
    fr = open("通讯录.txt", 'r+')
    s1 = fr.read()
    if len(s1):
        note = eval(s1)  # 读取的str转化为字典
        notes1 = copy.deepcopy(note)
    else:
        notes1 = {}
    fr.close()
    Se3New = Toplevel(root)
    Se3New.geometry('600x400')
    Se3New.title('按电话号码查找')
    lb_6_1 = Label(Se3New,text='请输入要查找学生电话号:')
    lb_6_1.pack()
    e17 = StringVar()
    entry1 = Entry(Se3New,textvariable=e17)
    entry1.pack()
    def search3():
        telephone = e17.get()
        t = 0
        for i in notes1.keys():
            t = t+1
            if notes1[i]['电话']==telephone:
                lb_6_2 = Label(Se3New,text='学号 %s 的姓名是 %s , 性别是 %s , 工作单位是 %s , 电话是 %s , E-mail是 %s'
                      % (i, notes1[i]['姓名'], notes1[i]['性别'], notes1[i]['工作单位'],
                         notes1[i]['电话'], notes1[i]['E-mail']))
                lb_6_2.pack()
                t = 0
            if t==len(notes1):
                lb_6_3 = Label(Se3New,text='该学生已存在!')
                lb_6_3.pack()
    btse3 = Button(Se3New,text='搜索',command=search3)
    btse3.pack()

#统计操作

#统计总人数
def newwind_Sp():
    fr = open("通讯录.txt", 'r+')
    s1 = fr.read()
    if len(s1):
        note = eval(s1)  # 读取的str转化为字典
        notes1 = copy.deepcopy(note)
    else:
        notes1 = {}
    fr.close()
    SpNew = Toplevel(root)
    SpNew.geometry('320x180')
    SpNew.title('总人数')
    sum = len(notes1)
    lb_7 = Label(SpNew,text='学生总数为 %d '%sum,font=('黑体',16,'bold') )
    lb_7.pack()
    btClose = Button(SpNew, text='退出', command=SpNew.destroy)
    btClose.place(relx=0.7, rely=0.7)

#统计男生人数
def newwind_Sman():
    fr = open("通讯录.txt", 'r+')
    s1 = fr.read()
    if len(s1):
        note = eval(s1)  # 读取的str转化为字典
        notes1 = copy.deepcopy(note)
    else:
        notes1 = {}
    fr.close()
    SmanNew = Toplevel(root)
    SmanNew.geometry('320x180')
    SmanNew.title('男生总数')
    t = 0
    for i in notes1.keys():
        if notes1[i]['性别']=='男':
            t = t+1
    lb_8 = Label(SmanNew,text='男生总数为 %d '%t,font=('黑体',16,'bold') )
    lb_8.pack()
    btClose = Button(SmanNew, text='退出', command=SmanNew.destroy)
    btClose.place(relx=0.7, rely=0.7)
#统计女生人数
def newwind_Sfemale():
    fr = open("通讯录.txt", 'r+')
    s1 = fr.read()
    if len(s1):
        note = eval(s1)  # 读取的str转化为字典
        notes1 = copy.deepcopy(note)
    else:
        notes1 = {}
    fr.close()
    SfemaleNew = Toplevel(root)
    SfemaleNew.geometry('320x180')
    SfemaleNew.title('女生总数')
    t = 0
    for i in notes1.keys():
        if notes1[i]['性别']=='女':
            t = t+1
    lb_9 = Label(SfemaleNew, text='女生总数为 %d ' % t,font=('黑体',16,'bold'))
    lb_9.pack()
    btClose = Button(SfemaleNew, text='退出', command=SfemaleNew.destroy)
    btClose.place(relx=0.7, rely=0.7)

#菜单设计
mainmenu = Menu(root)
menuFile = Menu(mainmenu)   #菜单分组 menuFile
mainmenu.add_cascade(label="通讯录",menu=menuFile)
menuFile.add_command(label="显示/刷新",command=Show)
menuFile.add_separator()    #分割线
menuFile.add_command(label="退出",command=root.destroy)

menuEdit = Menu(mainmenu)   #菜单分组 menuEdit
mainmenu.add_cascade(label="编辑",menu=menuEdit)
menuEdit.add_command(label="插入",command=newwind_add)
menuEdit.add_command(label="修改",command=newwind_modi)
menuEdit.add_command(label="删除",command=newwind_del)

menuSearch = Menu(mainmenu) #菜单分组 menuSearch
mainmenu.add_cascade(label="查询",menu=menuSearch)
menuSearch.add_command(label="按学号查找",command=newwind_search1)
menuSearch.add_command(label="按姓名查找",command=newwind_search2)
menuSearch.add_command(label="按电话查找",command=newwind_search3)

menuCount = Menu(mainmenu)  #菜单分组 menuCount
mainmenu.add_cascade(label="统计",menu=menuCount)
menuCount.add_command(label="学生总数",command=newwind_Sp)
menuCount.add_command(label="男生总数",command=newwind_Sman)
menuCount.add_command(label="女生总数",command=newwind_Sfemale)

#将鼠标的触发位置event.x_root 和 event.y_root以post()方法传给菜单
def popupmenu(event):
    mainmenu.post(event.x_root, event.y_root)
root.config(menu=mainmenu)
root.bind('<Button-3>',popupmenu) # 根窗体绑定鼠标右击响应事件

root.mainloop()

五、实验结果
1 界面展示
1)菜单界面及主显示界面:

2)菜单中各选项内部功能:

3)插入操作窗口:

4)删除操作窗口:

5)修改操作窗口:

6)按学号查找窗口:

7)按姓名查找窗口:

8)按电话号码查找窗口:

9)统计总人数窗口:

10)统计男生总数窗口:

11)统计女生总数窗口:

2 各项功能操作展示
1)插入操作
此处共录入三名学生如下:

画布中显示:

文件中显示:

2)修改操作
此处将0003号学生信息进行修改,如下:

画布中显示:

文件中显示:

3)删除操作:
此处删除0001号同学,如下:

画布中显示:

文件中显示:

4)按学号查找:
此处查找0001号学生,因上一步已被删除,故应显示“该学生不存在”,操作如下:

另查找0002号学生,则显示其所有信息,操作如下:

5)按姓名查找:
此处查找刘伊同学,则显示其全部信息,操作如下:

6)按电话查找:
此处搜索122345,应查找到赵可,并输出其全部信息,操作如下:

7)统计学生总人数:
显示弹窗如下:

8)统计男生总人数:
显示弹窗如下:

9)统计女生总人数:
显示弹窗如下:

六、实验总结
本实验设计过程可以说是历经各种坎坷,代码量也十分巨大,共578行(含注释)。
其中文件的存入及读取操作设计部分,由于本人采用字典操作,故需要特别转化进行存入与读取,涉及到的算法经过不断调试最终成功通过,同时在代码开头部分,本人采用pickle模块,可对存入文件中的数据进行封装(使用dump()函数),好处在于可以将数据存取为只能用python编程环境读取的类型(读取时采用load()函数),可起到加密的作用。
在可视化设计过程中,考虑了多项因素,包括按钮,文本框的布局、函数的内部传递参数、特殊情况的程序处理、菜单的设计等等。菜单设计过程中,通过查找大量的博客、阅读他人代码学习到传递位置参量的设计方法并在此次设计实验中得到了应用与体现。而在界面设计过程中,由于python中可调布局的函数(pack(),grid(),place())仅有三种,同时函数的使用需要输入不同的参数,控制其显示位置,故在此过程中,本人为使得到的界面尽量精美,经过了一个漫长的布局过程。不过仍有不足的地方无法调试,例如修改弹窗中各个按钮及文本框的布局中仍有一些空白部分无法填充。
总体过程虽有一些坎坷,好在尽力都解决了已知的问题。此次设计实验充分锻炼了自己调用tkinter模块设计布局的能力,有一个显著的提升,同时也发现,用python环境做可视化设计确实略有一些困难,其内部的一些模块函数还需要持续更新,设计布局函数方面不够人性化,也不够便捷。不过本人为充分锻炼自己的python编程能力,披荆斩棘,也算取得胜利。

补充:
回应评论区的提问: (添加成员时,加入判断信息完整性的功能)
笔者修改了newwind_add子窗体中的add()函数(第132行),修改后的函数如下:

def add():      #插入成员函数
        fr = open("通讯录.txt",'w+')
        s1 = fr.read()
        if len(s1):
            note = eval(s1)   #读取的str转化为字典
            notes1 = copy.deepcopy(note)
        else:
            notes1 = {}
        fr.close()
        id = e1.get()
        if id in notes1:
            lb_1_8 = Label(winNew, text='该学号已存在!')
            lb_1_8.place(relx=0.5, rely=0.9)
        else:
            name = e2.get()
            sex = e3.get()
            workspace = e4.get()
            telephone = e5.get()
            email = e6.get()
            if name=="" or sex=="" or workspace=="" or telephone=="" or email=="":
                lb_1_8 = Label(winNew, text='请保证信息完整!')
                lb_1_8.place(relx=0.5, rely=0.9)
            else:
                label = {'姓名': name, '性别': sex, '工作单位': workspace, '电话': telephone, 'E-mail': email}
                notes1[id] = label
                lb_1_7 = Label(winNew, text='录入成功!')
                lb_1_7.place(relx=0.5, rely=0.9)
                fw = open("通讯录.txt", "w+")
                fw.write(str(notes1))  # 把字典转化为str
                fw.close()