python:tkinter图形界面通讯录+txt文本存储数据

news2024/12/23 13:35:49

1 实验目的与要求

实验目的:设计一个实用的小型通讯录程序

实验要求:最后的通讯录要写入文件中保存起来

2 实验内容

本次实验内容如下:

设计一个实用的小型通讯录程序,具有添加,查询和删除功能。由姓名,籍贯,电话号码1,电话号码2,电子邮箱组成,姓名可以由字符和数字混合编码。电话号码可由字符和数字组成。

要求:最后的通讯录要写入的文件中保存起来;

实现功能:

(1)系统以菜单方式工作

(2)信息录入功能

(3)信息浏览功能

(4)信息查询功能

(5)信息修改功能

(6)系统退出功能

3 主要实验步骤

(1)导入所需的库:tkinter.messagebox用于显示消息框,json用于处理JSON数据,os用于文件操作,tkinter用于创建GUI界面。

(2)创建主窗口:root = tkinter.Tk()创建一个主窗口,并设置标题和大小。

(3)添加滚动条:创建一个垂直滚动条并将其与列表框关联。

(4)创建通讯录显示区域:使用Frame在主窗口中创建一个框架用于显示通讯录信息,包括联系人姓名、手机号等。

(5)打开通讯录文件:在当前目录下打开名为"通讯录.txt"的文件,如果文件不存在则创建一个新文件。

(6)定义函数showinfo():用于显示通讯录中的联系人信息。

(7)创建按钮和输入框:包括添加联系人、删除联系人、修改联系人、查找联系人和退出按钮,以及一个用于输入联系人姓名的输入框。

(8)绑定按钮事件:分别绑定添加联系人、删除联系人、修改联系人、查找联系人和退出按钮的点击事件,点击按钮时会执行相应的函数。

(9)运行主循环:使用“root.mainloop()”来运行主窗口的事件循环,使窗口能够响应用户操作。

4 实验过程

4.1 导入所需模块

导入三个模块:tkinter.messagebox、json和os。

import tkinter.messagebox

import json

import os

import tkinter

其中:

tkinter.messagebox模块提供了一些用于在GUI程序中显示消息框的函数;

json模块提供了一些用于读取和编写JSON数据的函数;

os模块提供了一些与操作系统交互的函数。

这里还导入了一个名为tkinter的模块,它是Python内置的一个图形用户界面(GUI)工具包,在开发桌面应用程序时经常被使用。

4.2 创建主窗口

使用tkinter.Tk()创建一个名为root的主窗口,并设置窗口的标题为"通讯录",以及窗口的大小为550x500。

root = tkinter.Tk()

root.title('通讯录')

root.geometry("550x500")

这段代码是使用Python中的tkinter模块创建一个名为"root"的窗口(或者称为主窗口)。其中:

tkinter.Tk()方法创建了一个顶层窗口对象,并将其赋值给变量root,这个窗口对象将作为所有其他小组件的父容器。

root.title()方法设置主窗口的标题为“通讯录”。

root.geometry()方法用于设置主窗口的大小为宽550像素和高500像素。在Python中,你可以通过字符串来指定窗口的大小、位置等参数。例如,本段代码中的"550x500"字符串表示设置窗口宽度为550像素,高度为500像素。

4.3 添加滚动条

创建一个垂直滚动条,并将其放置在主窗口的右侧。

scrollbar = tkinter.Scrollbar(root)

scrollbar.pack(side=tkinter.RIGHT, fill=tkinter.Y)

这段代码使用tkinter模块在root窗口(主窗口)中创建了一个名为"scrollbar"的滚动条对象。其中:

tkinter.Scrollbar()方法创建了一个Scrollbar组件对象,并将其赋值给变量scrollbar。

scrollbar.pack()方法用于将滚动条小部件放置在主窗口的右侧,并充满其中的Y轴。

这里pack()方法是tkinter中最简单的一种布局管理器,在GUI开发中比较常用,可以让小部件自适应大小并排列在一起,但是它只能实现比较简单的布局需求。如果需要更加灵活和高级的布局控制,可以使用其他的布局管理器,如grid()或place()等。

4.4 创建联系人列表框

创建一个框架Frame_info,用于容纳联系人列表框。在框架中创建一个列表框listbox,并将垂直滚动条与列表框绑定起来。

Frame_info = tkinter.Frame(root, height=150, width=180)

Frame_info.place(x=40, y=80)

listbox = tkinter.Listbox(Frame_info, yscrollcommand=scrollbar.set, font=('宋体', 15))

listbox.grid(row=2, column=0, columnspan=5, sticky=tkinter.NSEW)

scrollbar.config(command=listbox.yview)

这段代码使用tkinter模块在root窗口(主窗口)中创建了一个名为"Frame_info"的框架对象,以及一个名为"listbox"的列表框对象,并将它们放置在主窗口的指定位置上。其中:

tkinter.Frame()方法创建了一个Frame组件对象,并将其赋值给变量Frame_info。该组件通常用于作为其他小部件的容器,以便更好地管理它们的布局。

Frame_info.place()方法用于将Frame_info组件放置在主窗口(x=40, y=80)的指定位置上。

listbox = tkinter.Listbox(Frame_info,...)方法创建了一个Listbox组件对象,并将其赋值给变量listbox。该组件用于显示一个可滚动的文本列表。

在listbox.grid(...)方法中的设置参数用于设置listbox对象在Frame_info框架内的偏移和大小等显示属性。

scrollbart.config(command=listbox.yview)用于实现关联滚动条与对应的文本列表。

这里sticky=tkinter.NSEW表示使组件能够在框架中展开并填充空间,以便自适应大小,从而占据整个格子。如果不指定sticky,则只会占据所需的最小空间,无法自适应扩展。

4.5 打开通讯录文件并显示联系人信息:

file = open("通讯录.txt", mode='a', encoding='utf-8')

file.close()

这里尝试以追加模式打开名为"通讯录.txt"的文件,如果文件不存在则会创建一个空文件。然后立即关闭文件。

def showinfo():

    listbox.delete(0, tkinter.END)

    file = open("通讯录.txt", mode='r', encoding='utf-8')

    if len(file.read()) != 0:

        file.seek(0, 0)

        file_data = file.read()

        split_info = file_data.split('\n')

        split_info.remove(split_info[len(split_info) - 1])

        name_li = []

        all_info_li = []

        for i in split_info:

            dict_info = json.loads(i.replace("\'", '\"'))

            all_info_li.append(dict_info)

            listbox.insert(tkinter.END, dict_info['姓名'] + ' ' + dict_info['手机号1'] + ' ' + dict_info['手机号2'] + ' ' +

                           dict_info['邮箱'] + ' ' + dict_info['地址'])

file.close()

定义了一个showinfo()函数,用于显示联系人信息。函数首先清空列表框listbox的内容,然后打开通讯录文件并读取其中的信息。通过解析JSON字符串,将每个联系人的信息添加到all_info_li列表中,并将姓名和其他信息拼接后插入到列表框中。最后关闭文件。其中:

listbox.delete(0, tkinter.END)方法用于清空之前列表框中的所有数据。

file = open("通讯录.txt", mode='r', encoding='utf-8')打开名为“通讯录.txt”的文件,并将文件对象赋值给变量file。mode='r'表示以只读模式打开文件,encoding='utf-8'则指定了文件的编码格式。

len(file.read()) != 0用于判断当前文件是否为空。如果不为空,则说明存在通讯录信息需要进行展示。

file.seek(0, 0)表示将文件指针移动到文件开头。

file_data = file.read()将整个文件读取到一个字符串变量file_data中。

split_info = file_data.split('\n')使用split()方法将文件内容按照换行符分割成一个个子字符串,并返回一个列表split_info。

split_info.remove(split_info[len(split_info) - 1])移除列表split_info的最后一个空字符串元素。

在for循环中,逐一遍历列表split_info中的每一个子字符串i。首先使用json.loads()方法解析该字符串中的JSON格式数据,然后将其添加到列表all_info_li中保存。接着,将解析好的通讯录资料信息按照规定的格式插入listbox中。

最后要记得关闭文件,防止文件句柄资源泄漏。

4.6 添加联系人功能

def add_def():

    add_info = {'姓名': '', '手机号1': '', '手机号2': '', '邮箱': '', '地址': ''}

    add_info['姓名'] = name_input.get()

    if add_info['姓名'] == '':

        tkinter.messagebox.showinfo('提示', '请输入姓名!')

        return

    add_info['手机号1'] = pho_input.get()

    add_info['手机号2'] = pho_input2.get()

    add_info['邮箱'] = email_input.get()

    add_info['地址'] = address_input.get()

    with open("通讯录.txt", 'a+', encoding='utf-8') as file:

        file.write(str(add_info) + '\n')

    showinfo()

    name_input.delete(0, tkinter.END)

    pho_input.delete(0, tkinter.END)

    pho_input2.delete(0, tkinter.END)

    email_input.delete(0, tkinter.END)

address_input.delete(0, tkinter.END)

定义了一个add_def()函数,用于添加联系人。函数首先创建一个空的联系人信息字典add_info,然后从输入框中获取联系人的姓名、手机号、邮箱和地址,并将其填充到字典中。接下来,将联系人信息以字符串形式写入到通讯录文件中。最后,调用showinfo()函数刷新列表框内容,并清空输入框中的内容。其中:

add_info = {'姓名': '', '手机号1': '', '手机号2': '', '邮箱': '', '地址': ''}创建一个空的字典add_info。

add_info['姓名'] = name_input.get()从图形界面中获取姓名输入框中的值,并将其保存到字典add_info的“姓名”字段中。

if add_info['姓名'] == '':用于判断姓名是否为空。如果为空,则弹出提示框并结束函数。

add_info['手机号1'] = pho_input.get()从图形界面中获取手机号1输入框中的值,并将其保存到字典add_info的“手机号1”字段中。

add_info['手机号2'] = pho_input2.get()从图形界面中获取手机号2输入框中的值,并将其保存到字典add_info的“手机号2”字段中。

add_info['邮箱'] = email_input.get()从图形界面中获取邮箱输入框中的值,并将其保存到字典add_info的“邮箱”字段中。

add_info['地址'] = address_input.get()从图形界面中获取地址输入框中的值,并将其保存到字典add_info的“地址”字段中。

with open("通讯录.txt", 'a+', encoding='utf-8') as file: 打开名为“通讯录.txt”的文件,并将文件对象赋值给变量file。mode='a+'表示以追加模式打开文件,并且指定了文件的编码格式为utf-8。

file.write(str(add_info) + '\n')将字典add_info以字符串形式写入文件中,并在末尾添加一个换行符。

showinfo()调用“showinfo()”函数,用于刷新通讯录数据展示部分。

最后,清空各个输入框中的数据并继续等待用户输入。

4.7 删除联系人功能

def del_def():

    selected_item = listbox.curselection()

    if not selected_item:

        tkinter.messagebox.showinfo('提示', '请选择要删除的联系人!')

        return

    else:

        file = open("通讯录.txt", mode='r', encoding='utf-8')

        read_data = file.readlines()

        file.close()

        selected_index = selected_item[0]

        del read_data[selected_index]

        file = open("通讯录.txt", mode='w', encoding='utf-8')

        file.writelines(read_data)

        file.close()

        showinfo()

定义了一个del_def()函数,用于删除选定的联系人。首先检查是否选定了联系人,如果没有选定则弹出提示框。如果有选定的联系人,则打开通讯录文件并逐行读取其中的内容。找到选定联系人的索引后,删除相应的行,并将剩余的内容重新写入文件中。最后,调用showinfo()函数刷新列表框内容。其中:

selected_item = listbox.curselection()通过“curselection()”方法获取用户在图形界面中选择的联系人,并将其保存到变量selected_item中。

if not selected_item:判断用户是否选择了要删除的联系人。如果没有选择,则弹出提示框并结束函数。

file = open("通讯录.txt", mode='r', encoding='utf-8')打开名为“通讯录.txt”的文件,并将文件对象赋值给变量file。mode='r'表示以只读模式打开文件,并且指定了文件的编码格式为utf-8。注意,在此之前需要确认该文件已被创建。

read_data = file.readlines()读取文件中的所有行,并将其保存到列表read_data中。

file.close()关闭文件。

selected_index = selected_item[0]获取用户选择的联系人的索引值,并将其保存到变量selected_index中。

del read_data[selected_index]从列表read_data中删除用户选择的联系人的数据。

file = open("通讯录.txt", mode='w', encoding='utf-8')重新以写入模式打开文件,并将文件对象赋值给变量file。mode='w'表示以覆盖模式打开文件,并且指定了文件的编码格式为utf-8。

file.writelines(read_data)将处理后的全部数据重新写入文件中。

file.close()关闭文件。

showinfo()调用“showinfo()”函数,用于刷新通讯录数据展示部分。

4.8 修改联系人功能

def update_def():

    selected_item = listbox.curselection()

    if not selected_item:

        tkinter.messagebox.showinfo('提示', '请选择要修改的联系人!')

        return

    else:

        file = open("通讯录.txt", mode='r', encoding='utf-8')

        read_data = file.readlines()

        file.close()

        selected_index = selected_item[0]

        selected_info = json.loads(read_data[selected_index].replace("\'", '\"'))

        name_input.insert(0, selected_info['姓名'])

        pho_input.insert(0, selected_info['手机号1'])

        pho_input2.insert(0, selected_info['手机号2'])

        email_input.insert(0, selected_info['邮箱'])

        address_input.insert(0, selected_info['地址'])

        del read_data[selected_index]

        file = open("通讯录.txt", mode='w', encoding='utf-8')

        file.writelines(read_data)

        file.close()

        showinfo()

定义了一个update_def()函数,用于修改选定的联系人。首先检查是否选定了联系人,如果没有选定则弹出提示框。如果有选定的联系人,则打开通讯录文件并逐行读取其中的内容。找到选定联系人的索引后,将其信息解析为字典,并将对应的值填充到相应的输入框中。接着删除选定的联系人信息,并将剩余的内容重新写入文件中。最后,调用showinfo()函数刷新列表框内容。

这段代码定义了一个名为"update_def()"的函数,该函数实现了修改通讯录信息的功能。其中:

selected_item = listbox.curselection()通过“curselection()”方法获取用户在图形界面中选择的联系人,并将其保存到变量selected_item中。

if not selected_item:判断用户是否选择了要修改的联系人。如果没有选择,则弹出提示框并结束函数。

file = open("通讯录.txt", mode='r', encoding='utf-8')打开名为“通讯录.txt”的文件,并将文件对象赋值给变量file。mode='r'表示以只读模式打开文件,并且指定了文件的编码格式为utf-8。注意,在此之前需要确认该文件已被创建。

read_data = file.readlines()读取文件中的所有行,并将其保存到列表read_data中。

file.close()关闭文件。

selected_index = selected_item[0]获取用户选择的联系人的索引值,并将其保存到变量selected_index中。

selected_info= json.loads(read_data[selected_index].replace("\'", '\"'))从read_data中获取用户选择的联系人的信息,并转换成字典格式的数据(因为使用了单引号,需要先将其替换成双引号)。

name_input.insert(0, selected_info['姓名'])将选中的联系人的姓名信息显示在对应的文本框中。

pho_input.insert(0, selected_info['手机号1'])将选中的联系人的手机号1信息显示在对应的文本框中。

pho_input2.insert(0, selected_info['手机号2'])将选中的联系人的手机号2信息显示在对应的文本框中。

email_input.insert(0, selected_info['邮箱'])将选中的联系人的邮箱信息显示在对应的文本框中。

address_input.insert(0, selected_info['地址'])将选中的联系人的地址信息显示在对应的文本框中。

del read_data[selected_index]从列表read_data中删除用户选择的联系人的数据。

file = open("通讯录.txt", mode='w', encoding='utf-8')重新以写入模式打开文件,并将文件对象赋值给变量file。mode='w'表示以覆盖模式打开文件,并且指定了文件的编码格式为utf-8。

file.writelines(read_data)将处理后的全部数据重新写入文件中。

file.close()关闭文件。

showinfo()调用“showinfo()”函数,用于刷新通讯录数据展示部分。

4.9 创建各个组件

name_label = tkinter.Label(root, text='姓名:', font=('宋体', 15))

name_label.place(x=40, y=280)

name_input = tkinter.Entry(root, font=('宋体', 15))

name_input.place(x=90, y=280)

pho_label = tkinter.Label(root, text='手机号1:', font=('宋体', 15))

pho_label.place(x=10, y=330)

pho_input = tkinter.Entry(root, font=('宋体', 15))

pho_input.place(x=90, y=330)

pho_label2 = tkinter.Label(root, text='手机号2:', font=('宋体', 15))

pho_label2.place(x=10, y=380)

pho_input2 = tkinter.Entry(root, font=('宋体', 15))

pho_input2.place(x=90, y=380)

email_label = tkinter.Label(root, text='邮箱:', font=('宋体', 15))

email_label.place(x=40, y=430)

email_input = tkinter.Entry(root, font=('宋体', 15))

email_input.place(x=90, y=430)

address_label = tkinter.Label(root, text='地址:', font=('宋体', 15))

address_label.place(x=40, y=480)

address_input = tkinter.Entry(root, font=('宋体', 15))

address_input.place(x=90, y=480)

add_button = tkinter.Button(root, text='添加', font=('宋体', 15), command=add_def)

add_button.place(x=420, y=280)

del_button = tkinter.Button(root, text='删除', font=('宋体', 15), command=del_def)

del_button.place(x=420, y=330)

update_button = tkinter.Button(root, text='修改', font=('宋体', 15), command=update_def)

update_button.place(x=420, y=380)

quit_button = tkinter.Button(root, text='退出', font=('宋体', 15), command=root.quit)

quit_button.place(x=420, y=430)

创建了标签、输入框和按钮等各种GUI组件,并使用place()方法将它们放置在主窗口的指定位置。其中:

Label 创建文本标签,用于显示文本内容。

Entry 创建文本框,用于输入和显示文本内容。

Button 创建按钮,用于触发相应的操作。

place(x, y) 方法用于设置组件在界面上的位置坐标。

具体地:

name_label 创建了一个名为“姓名”的文本标签,并将其放置在位置(40, 280)的坐标处。

name_input 创建了一个用于输入姓名的文本框,并将其放置在位置(90, 280)的坐标处。

pho_label 创建了一个名为“手机号1”的文本标签,并将其放置在位置(10, 330)的坐标处。

pho_input 创建了一个用于输入手机号码的文本框,并将其放置在位置(90, 330)的坐标处。

pho_label2 创建了一个名为“手机号2”的文本标签,并将其放置在位置(10, 380)的坐标处。

pho_input2 创建了另一个用于输入手机号码的文本框,并将其放置在位置(90, 380)的坐标处。

email_label 创建了一个名为“邮箱”的文本标签,并将其放置在位置(40, 430)的坐标处。

email_input 创建了一个用于输入邮箱的文本框,并将其放置在位置(90, 430)的坐标处。

address_label 创建了一个名为“地址”的文本标签,并将其放置在位置(40, 480)的坐标处。

address_input 创建了一个用于输入地址的文本框,并将其放置在位置(90, 480)的坐标处。

接下来是四个按钮:

add_button 创建了一个名为“添加”的按钮,并将其放置在位置(420,280)的坐标处。该按钮触发了 add_def() 函数,实现添加联系人信息的功能。

del_button 创建了一个名为“删除”的按钮,并将其放置在位置(420,330)的坐标处。该按钮触发了 del_def() 函数,实现删除联系人信息的功能。

update_button 创建了一个名为“更新”的按钮,并将其放置在位置(420,380)的坐标处。该按钮触发了 update_def() 函数,实现修改联系人信息的功能。

quit_button 创建了一个名为“添加”的按钮,并将其放置在位置(420,430)的坐标处。该按钮实现退出功能。

4.10 显示联系人信息

showinfo()

调用showinfo()函数,初始化时显示已有的联系人信息。

4.11 运行主循环

root.mainloop()

通过调用mainloop()方法启动GUI应用程序的主循环,等待用户交互事件的发生。

以上就是代码的详细实现过程。通过创建GUI窗口、读取文件、添加、删除和修改联系人等功能,实现了一个简单的通讯录应用程序。用户可以在界面上输入联系人信息,然后通过按钮操作实现对联系人的增删改查。

【完整代码】

import tkinter.messagebox
import json
import os
import tkinter

root = tkinter.Tk()
root.title('通讯录')
root.geometry("550x500")

# 添加滚动条
scrollbar = tkinter.Scrollbar(root)
scrollbar.pack(side=tkinter.RIGHT, fill=tkinter.Y)

Frame_info = tkinter.Frame(root, height=150, width=180)
Frame_info.place(x=40, y=80)#滚动框位置

# 绑定滚动条和列表
listbox = tkinter.Listbox(Frame_info, yscrollcommand=scrollbar.set, font=('宋体', 15))
listbox.grid(row=2, column=0, columnspan=5, sticky=tkinter.NSEW)

# 设置滚动条和列表的关系
scrollbar.config(command=listbox.yview)
#

#标题属性的另一个设置方法
# name_label = tkinter.Label(Frame_info, text="名字", font=('宋体', 15))
# name_label.grid(row=1, column=0)
# phone_label = tkinter.Label(Frame_info, text="手机号1", font=('宋体', 15))
# phone_label.grid(row=1, column=1)
# phone_label = tkinter.Label(Frame_info, text="手机号2", font=('宋体', 15))
# phone_label.grid(row=1, column=2)
# mail_label = tkinter.Label(Frame_info, text="邮箱", font=('宋体', 15))
# mail_label.grid(row=1, column=3)
# address_label = tkinter.Label(Frame_info, text="地址", font=('宋体', 15))
# address_label.grid(row=1, column=4)


file = open("通讯录.txt", mode='a', encoding='utf-8')
file.close()

def showinfo():
    # 清空列表
    listbox.delete(0, tkinter.END)

    file = open("通讯录.txt", mode='r', encoding='utf-8')
    if len(file.read()) != 0:
        file.seek(0, 0)
        file_data = file.read()
        split_info = file_data.split('\n')
        split_info.remove(split_info[len(split_info) - 1])
        name_li = []  # 用于存储联系人姓名的列表
        all_info_li = []  # 用于存储所有信息的列表
        for i in split_info:
            dict_info = json.loads(i.replace("\'", '\"'))
            all_info_li.append(dict_info)
            # 添加到列表中
            listbox.insert(tkinter.END, dict_info['姓名'] + ' ' + dict_info['手机号1'] + ' ' + dict_info['手机号2'] + ' ' +
                           dict_info['邮箱'] + ' ' + dict_info['地址'])
            row_count = 0
            column_count = 0

        # for i in all_info_li:
        #     # row_count += 1
        #     column_count += 1

            # for title, info_value in person_info.items():
            #     tktest = tkinter.Label(Frame_info, text=info_value, font=('宋体', 15, 'bold'))
            #     tktest.grid(row=row_count, column=column_count)
            #     column_count += 1
            # row_count += 1
            tktest = tkinter.Label(Frame_info, text=" " *42, font=('宋体', 15, 'bold'))#设置滚动框显示的宽度
            tktest.grid(row=row_count, column=column_count)


showinfo()

# 添加
def add_def(event):
    def add_man(event):
        name = name_new.get()
        phone1 = phone_new1.get()
        phone2 = phone_new2.get()
        mail = mail_new.get()
        address = adr_new.get()
        if name == "" or phone1 == " " or phone2 == " " or mail == " " or address == " ":
            tkinter.messagebox.showerror('错误', '所填信息都不能为空')
        else:
            card_dict = {"姓名": name, "手机号1": phone1, "手机号2": phone2,
                         "邮箱": mail, "地址": address}
            f = open("通讯录.txt", mode='a+', encoding='utf-8')
            f.write(str(card_dict) + '\n')
            f.close()
            tkinter.messagebox.showinfo('消息提示框', f'添加“{name}“为联系人成功!')
            showinfo()
            window_add.destroy()



    # 弹出框
    window_add = tkinter.Toplevel(root)
    window_add.geometry('300x250')
    # 姓名
    name_new = tkinter.StringVar()
    tkinter.Label(window_add, text='新联系人姓      名:').place(x=10, y=10)
    tkinter.Entry(window_add, textvariable=name_new).place(x=130, y=10)
    # 手机号1
    phone_new1 = tkinter.StringVar()
    tkinter.Label(window_add, text='新联系人手机号1:').place(x=10, y=50)
    tkinter.Entry(window_add, textvariable=phone_new1).place(x=130, y=50)
    # 手机号2
    phone_new2 = tkinter.StringVar()
    tkinter.Label(window_add, text='新联系人手机号2:').place(x=10, y=90)
    tkinter.Entry(window_add, textvariable=phone_new2).place(x=130, y=90)
    # 邮箱
    mail_new = tkinter.StringVar()
    tkinter.Label(window_add, text='新联系人邮      箱:').place(x=10, y=130)
    tkinter.Entry(window_add, textvariable=mail_new).place(x=130, y=130)
    # 地址
    adr_new = tkinter.StringVar()
    tkinter.Label(window_add, text='新联系人地      址:').place(x=10, y=170)
    tkinter.Entry(window_add, textvariable=adr_new).place(x=130, y=170)
    # 确认
    confirm_button = tkinter.Button(window_add, text='确认添加', font=('宋体', 15))
    confirm_button.bind("<Button-1>", add_man)
    confirm_button.place(x=100, y=200)

# 删除
def del_def(event):
    name = man_name.get()
    file = open("通讯录.txt", mode='r+', encoding='utf-8')
    if len(file.read()) != 0:
        file.seek(0, 0)
        file_data = file.read()
        split_info = file_data.split('\n')
        split_info.remove(split_info[len(split_info) - 1])
        name_li = []
        all_info_li = []
        for i in split_info:
            dict_info = json.loads(i.replace("\'", '\"'))
            all_info_li.append(dict_info)
            name_li.append(dict_info['姓名'])
        if name in name_li:
            通讯录_copy = open('通讯录_copy.txt', mode='w+', encoding="utf-8")
            for person_info in all_info_li:
                if name not in str(person_info):
                    通讯录_copy.write(str(person_info) + '\n')
            通讯录_copy.close()
            file.close()
            os.rename('通讯录.txt', '通讯录_del.txt')
            os.rename('通讯录_copy.txt', '通讯录.txt')
            os.remove('通讯录_del.txt')
            tkinter.messagebox.showinfo('消息提示', f'删除“{name}“成功!')
            showinfo()
        else:
            tkinter.messagebox.showinfo('消息提示', '查无此人!')


# 修改
def update_def(event):
    def update_man(event):
        name = name_new.get()
        phone1 = phone_new1.get()
        phone2 = phone_new2.get()
        mail = mail_new.get()
        address = address_new.get()
        if name != "" and phone1 != "" and phone2 != "" and mail != "" and address != "":
            通讯录_copy = open('通讯录_copy.txt', mode='w', encoding="utf-8")
            # 将数据封装到字典中
            card_dict = {"姓名": name, "手机号1": phone1, "手机号2": phone2,
                         "邮箱": mail, "地址": address}
            for person_info in all_info_li:
                if name_old in str(person_info):
                    person_info = str(card_dict)
                通讯录_copy.write(str(person_info) + '\n')
            通讯录_copy.close()
            file.close()
            os.rename('通讯录.txt', '通讯录_del.txt')
            os.rename('通讯录_copy.txt', '通讯录.txt')
            os.remove('通讯录_del.txt')
            tkinter.messagebox.showinfo('消息提示框', '更新成功!')
            showinfo()
        else:
            tkinter.messagebox.showinfo('消息提示框', '请输入正确信息,或输入完整信息')
    name_old = man_name.get()
    file = open("通讯录.txt", mode='r+', encoding='utf-8')
    if len(file.read()) != 0:
        file.seek(0, 0)
        file_data = file.read()
        split_info = file_data.split('\n')
        split_info.remove(split_info[len(split_info) - 1])
        name_li = []
        all_info_li = []
        for i in split_info:
            dict_info = json.loads(i.replace("\'", '\"'))
            all_info_li.append(dict_info)
            name_li.append(dict_info['姓名'])
        if name_old in name_li:
            window_update = tkinter.Toplevel(root)
            window_update.geometry('280x200')
            # 输入更新的信息
            name_new = tkinter.StringVar()
            phone_new1 = tkinter.StringVar()
            phone_new2 = tkinter.StringVar()
            mail_new = tkinter.StringVar()
            address_new = tkinter.StringVar()
            # 输入更改后的信息
            tkinter.Label(window_update, text='姓      名:').place(x=20, y=0)
            tkinter.Entry(window_update, textvariable=name_new).place(x=90, y=0)
            tkinter.Label(window_update, text='手机号1:').place(x=20, y=30)
            tkinter.Entry(window_update, textvariable=phone_new1).place(x=90, y=30)
            tkinter.Label(window_update, text='手机号2:').place(x=20, y=60)
            tkinter.Entry(window_update, textvariable=phone_new2).place(x=90, y=60)
            tkinter.Label(window_update, text='邮      箱:').place(x=20, y=90)
            tkinter.Entry(window_update, textvariable=mail_new).place(x=90, y=90)
            tkinter.Label(window_update, text='地      址:').place(x=20, y=120)
            tkinter.Entry(window_update, textvariable=address_new).place(x=90, y=120)
            # 确认
            confirm_button = tkinter.Button(window_update, text='确认修改', font=('宋体', 15))
            confirm_button.bind("<Button-1>", update_man)
            confirm_button.place(x=100, y=150)
        else:
            tkinter.messagebox.showinfo('消息提示', '通讯录中查无此人')

# 查找
def find_def(event):
    name = man_name.get()
    file = open("通讯录.txt", mode='r+', encoding='utf-8')
    if len(file.read()) != 0:
        file.seek(0, 0)
        file_data = file.read()
        split_info = file_data.split('\n')
        split_info.remove(split_info[len(split_info) - 1])
        name_li = []
        all_info_li = []
        for i in split_info:
            dict_info = json.loads(i.replace("\'", '\"'))
            all_info_li.append(dict_info)
            name_li.append(dict_info['姓名'])
        if name in name_li:
            man_find = tkinter.Toplevel(root)
            man_find.geometry('400x140')
            for person_info in all_info_li:
                if name in str(person_info):
                    for title, info_value in person_info.items():
                        tem_text = title + ":" + info_value + " " *10
                        tktest = tkinter.Label(man_find, text=tem_text, font=('宋体', 15))
                        tktest.pack(side="top", anchor='w')
        else:
            tkinter.messagebox.showinfo('消息提示', '通讯录中查无此人')

# 退出
def over_def(event):
    root.destroy()

# 输入框
man_nametitle = tkinter.Label(root,text="请输入联系人姓名:", font=('宋体', 10)).place(x=40,y=358)#x为距离左侧距离
man_name = tkinter.StringVar()
tkinter.Entry(root, textvariable=man_name, width=28).place(x=160, y=355)#输入框位置

# 联系人名单标题
man_nametitle = tkinter.Label(root,text="联系人名单列表", font=('宋体', 20, 'bold')).place(x=180,y=35)
man_nametitle = tkinter.Label(root,text="-"*150,).place(x=0,y=10)

#属性标题
man_nametitle = tkinter.Label(root,text="姓名    手机号1    手机号2      邮箱   地址", font=('宋体', 15, 'bold')).place(x=44,y=75)
man_nametitle = tkinter.Label(root,text="-"*150,).place(x=0,y=10)
# 添加
button1 = tkinter.Button(root, text="添加联系人", width=10, height=2,font=('宋体', 15))
button1.place(x=40, y=400)
button1.bind('<Button-1>', add_def)

# 删除
button3 = tkinter.Button(root, text="删除联系人", width=10,height=2, font=('宋体', 15))
button3.place(x=280, y=400)
button3.bind('<Button-1>', del_def)

# 修改
button4 = tkinter.Button(root, text="修改联系人", width=10,height=2, font=('宋体', 15))
button4.place(x=160, y=400)
button4.bind('<Button-1>', update_def)

# 查找
button5 = tkinter.Button(root, text="查找联系人", width=10, font=('宋体', 15))
button5.place(x=398, y=350)
button5.bind('<Button-1>', find_def)

# 退出
button6 = tkinter.Button(root, text="退出", width=10, height=2, font=('宋体', 15))
button6.place(x=398, y=400)
button6.bind('<Button-1>', over_def)

root.mainloop()  # 显示主窗体

5 实验结果

6 实验总结

本实验设计过程可以说是历经各种坎坷,代码量也挺多,共293行(含注释)。

其中文件的存入及读取操作设计部分,由于本人采用字典操作,故需要特别转化进行存入与读取,涉及到的算法经过不断调试最终成功通过。

在可视化设计过程中,考虑了多项因素,包括按钮,文本框的布局、函数的内部传递参数、特殊情况的程序处理、菜单的设计等等。菜单设计过程中,通过查找大量的博客、阅读他人代码学习到传递位置参量的设计方法并在此次设计实验中得到了应用与体现。而在界面设计过程中,由于python中可调布局的函数(pack(),grid(),place()仅有三种,同时函数的使用需要输入不同的参数,控制其显示位置,故在此过程中,本人为使得到的界面尽量精美,经过了一个漫长的布局过程。不过仍有不足的地方无法调试,例如修改弹窗中各个按钮及文本框的布局中仍有一些空白部分无法填充。

总体过程虽有一些坎坷,好在尽力都解决了已知的问题。此次设计实验充分锻炼了自己调用tkinter模块设计布局的能力,有一个显著的提升,同时也发现,用python环境做可视化设计确实略有一些困难,其内部的一些模块函数还需要持续更新,设计布局函数方面不够人性化,也不够便捷。不过本人为充分锻炼自己的python编程能力,披荆斩棘,也算取得胜利。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/636240.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

jmeter008:结婚fiddler查看结果

如果通过jmeter的(察看结果树)查看响应数据不完整时&#xff0c; 可以结合fiddler来查看请求数据&#xff0c; 方法如下&#xff1a; 在请求的(高级)填写本地ip&#xff0c; 端口号&#xff0c;打开fiddler&#xff0c;运行jmeter请求即可抓包

【新版】系统架构设计师 - 计算机网络

个人总结&#xff0c;仅供参考&#xff0c;欢迎加好友一起讨论 架构 - 计算机网络 考点摘要 TCP/IP协议族&#xff08;★★★★&#xff09; 网路规划与设计&#xff08;★★★★&#xff09; 组网技术&#xff08;★&#xff09; 网络存储&#xff08;★&#xff09; IPv…

LabVIEW开发经济高效的多轴运动控制

LabVIEW开发经济高效的多轴运动控制 使用PC并行端口到驱动器电路接口技术开发的&#xff0c;该技术消除了在PC内部安装昂贵的插入式运动控制板的要求。为所介绍的系统开发了PC到电机接口和驱动器电路板。该系统能够使用直流电机控制四轴运动或使用步进电机控制两轴运动。 运动…

chatgpt赋能Python-python怎么在程序环境中保存

介绍 Python是一个广泛应用于各种领域的高级编程语言&#xff0c;它具有易于学习、可读性强、支持多种编程范式、强大且丰富的库、较高的运行速度等众多优点。无论是数据科学、人工智能、Web开发、自动化测试、游戏开发等领域&#xff0c;Python都是优秀的选择。 然而&#x…

GPDB中Latch等待与唤醒实现机制

GPDB中Latch等待与唤醒实现机制 GreenPlum/PostgreSQL中有很多Latch以帮助多进程以及主线程与从线程之间协作。那么Latch是如何实现的呢&#xff1f;Latch可以在多进程之间以及主线程和从线程之间实现等待与唤醒&#xff0c;WaitEventSet是实现这项功能的关键结构。本文我们聊聊…

基于SpringBoot+Vue的平时成绩管理系统

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 在现代教育环境中&…

2023全新微信公众号无限回调系统源码 亲测可用

2023年微信公众号无限回调全新升级&#xff0c;无限回调系统功能更强大&#xff0c;现已对接易支付&#xff0c;支持用户自助充值、购买授权、更换授权和续费授权。此次升级还增加了多项实用性功能&#xff0c;为公众号运营者提供更好的服务和支持。

使用Python中的Pandas工具将多个CSV格式的数据文件合并为一个

文章目录 使用软件安装Pandas工具编写py程序运行程序注意事项 使用软件 Pycharm 2020.1 安装Pandas工具 执行命令&#xff1a;pip install pandas 编写py程序 path&#xff1a;文件所处路径 import pandas as pd import os# 指定多个csv文件所在的目录 csv_dir path# 获…

LinkedHashSet源码

介绍 LinkedHashSet是HashSet的子类 LinkedHashSet底层是一个LinkedHashMap&#xff0c;底层维护了一个数组双向链表 LinkedHashSet根据元素的hashCOde值来决定元素的存储位置&#xff0c;同时使用链表维护元素的次序&#xff0c;这使元素看起来以插入顺序保存的 LinkedHas…

辅助驾驶功能开发-功能规范篇(27)-导航辅助驾驶NAP-微避障策略

1.微避障策略功能概述 微避障策略是在NAP功能激活过程中,当邻车道有大型车辆时(卡车、公交车、大巴等)或小车压线或左右侧靠近路沿时,控制本车进行横向偏移,达到远离目标车或路沿的效果。本文分别对大型车辆偏移、小车压线偏移、路沿偏移、Merge处理和偏移规划这五个部分展…

华为OD机试真题 JavaScript 实现【不爱施肥的小布】【2023Q1 100分】

一、题目描述 某农村主管理了一大片果园&#xff0c;fields[i]表示不同国林的面积&#xff0c;单位m2&#xff0c;现在要为所有的果林施肥且必须在n天之内完成&#xff0c;否则影响收成。小布是国林的工作人员&#xff0c;他每次选择一片果林进行施肥&#xff0c;且一片国林施…

Reinforce算法原理及Tensorflow代码实现

Q-learning和DQN算法都是强化学习中的Value-based的方法&#xff0c;它们都是先经过Q值来选择动作。强化学习中还有另一大类是策略梯度方法&#xff08;Policy Gradient Methods&#xff09;。Policy Gradient 是一类直接针对期望回报&#xff08;Expected Return&#xff09;通…

电气火灾监控系统如何有效的预防木材加工企业电气火灾隐患

摘要&#xff1a;本文分析了木材加工企业的特点、现状及常见电气火灾隐患&#xff0c;提出了消灭电气火灾隐患的措施。结尾介绍了木材加工企业常用电气设备的选用及电气火灾监控系统在其低压配电系统的应用方案及产品选型。 关键词&#xff1a;木材加工企业&#xff1b;电气火…

网络服务——DHCP服务

个人简介&#xff1a;云计算网络运维专业人员&#xff0c;了解运维知识&#xff0c;掌握TCP/IP协议&#xff0c;每天分享网络运维知识与技能。座右铭&#xff1a;海不辞水&#xff0c;故能成其大&#xff1b;山不辞石&#xff0c;故能成其高。 个人主页&#xff1a;小李会科技的…

我和老刘又被搞惨了

前两天在调试PHY的时候遇到了一堆问题&#xff0c;老刘都不耐其烦的搞定了&#xff0c;这次我们开始调试音频部分&#xff0c;音频部分很简单&#xff0c;无非就是录音&#xff0c;要是能把录音的音频拿到了&#xff0c;那就万事大吉了。老刘也是信心满满&#xff0c;老刘对我说…

操作系统性能提升之内核锁优化

性能为王&#xff0c;系统的性能提升是每一个工程师的追求。目前&#xff0c;性能优化主要集中在消除系统软件堆栈中的低效率上或绕过高开销的系统操作。例如&#xff0c;内核旁路通过在用户空间中移动多个操作来实现这个目标&#xff0c;还有就是为某些类别的应用程序重构底层…

提升效率,从这款智能挂灯开始

❤️作者主页&#xff1a;小虚竹 ❤️作者简介&#xff1a;大家好,我是小虚竹。2022年度博客之星评选TOP 10&#x1f3c6;&#xff0c;Java领域优质创作者&#x1f3c6;&#xff0c;CSDN博客专家&#x1f3c6;&#xff0c;华为云享专家&#x1f3c6;&#xff0c;掘金年度人气作…

华为项目经理就是CEO,华为对项目经理的要求是什么?

项目经理要向上发展&#xff0c;下面我们来看看华为对项目经理的要求。 原文出自&#xff1a;pmo前沿

太空大战-第14届蓝桥杯国赛Scratch真题中级组第6题

[导读]&#xff1a;超平老师的《Scratch蓝桥杯真题解析100讲》已经全部完成&#xff0c;后续会不定期解读蓝桥杯真题&#xff0c;这是Scratch蓝桥杯真题解析第148讲。 太空大战&#xff0c;本题是2023年5月28日上午举行的第14届蓝桥杯国赛Scratch图形化编程中级组真题第6题&am…

Flume学习---3、自定义Interceptor、自定义Source、自定义Sink

1、自定义Interceptor 1、案例需求 使用 Flume 采集服务器本地日志&#xff0c;需要按照日志类型的不同&#xff0c;将不同种类的日志发往不同的分析系统。 2、需求分析 在实际的开发中&#xff0c;一台服务器产生的日志类型可能有很多种&#xff0c;不同类型的日志可能需要发…