前言
这一节我们将实现校验、添加、修改、删除、保存的功能。
part5 完成项目
一、创建StudentServicel类
1. 准备好校验类check
为了完善学生或教师信息的添加功能,我们需要对输入的数据进行校验。前面我们已经使用过Check
类,利用正则表达式分别对学号、姓名、性别、手机号、邮箱的基本规范做校验。现在我们可以直接拿来使用。
2. 定义抽象类services
我们再定义一个抽象类services
,准备定义抽象方法有:add
、update
、delete
、check
;
from abc import *
class Services(metaclass=ABCMeta):
@abstractmethod
def add(self): pass
@abstractmethod
def update(self): pass
@abstractmethod
def delete(self): pass
@abstractmethod
def check(self): pass
之后,我们在实现学生操作的功能创建一个studentservice模块,继承Services和Check。
class StudentServices(Services, Check):
def __init__(self, list_all, student_current: Student):
Services.__init__(self)
Check.__init__(self)
self.list_all = list_all
self.student_current = student_current
二、对输入的数据数据进行校验
开发到这个阶段,在主界面点击添加按钮的时候,如果系统报错。可能是我们的StudentDetail
类的构造函数第二个参数current_student
没有设置默认值,我们只需要给其添加一个默认值current_student=""
即可。它即使没有收到参数的传递它也不会报错了。
1. 实现校验功能
当我们点击添加按钮打开明细窗体,填入数据的时候,点击保存按钮时,此时应当触发对所填入数据的校验。
由于我们的保存按钮写在了basedetail
中,所以我们先定义一个commit
函数。然后在studentdetail
重写commit
方法。
之后我们在StudentService
类中定义一个check
方法,用来校验输入的信息是否有效。由于性别是通过radiobutton获取的无需校验,这里我们只校验学号、姓名、电话、邮箱,并作出如下规定:
check的返回值 | 含义 |
---|---|
1 | 符合要求 |
2 | 学号不符合要求 |
3 | 姓名不符合要求 |
4 | 电话不符合要求 |
5 | 邮箱地址不符合要求 |
我们定义校验函数如下:
def check(self):
return_number = 0
if not self.check_sno(self.student_current.sno):
return_number = 2
elif not self.check_name(self.student_current.name):
return_number = 3
elif not self.check_mobile(self.student_current.mobile):
return_number = 4
elif not self.check_email(self.student_current.email):
return_number = 5
else:
return_number = 1
return return_number
我们回到studentdetail
模块中,给commit
函数添加功能,其中包括:封装当前填入的学生信息。
我们定义一个方法get_current_student
把填入的信息封装到student类
def get_current_student(self):
sno = self.var_sno.get()
name = self.var_name.get()
gender = ""
if self.var_gender.get() == 1:
gender = "男"
elif self.var_gender.get() == 2:
gender = "女"
birthday = self.var_birthday.get()
mobile = self.var_mobile.get()
email = self.var_email.get()
profession = self.var_profession.get()
entry_time = self.var_entry_time
# 封装
current_student = Student(sno, gender, birthday, birthday, mobile, email, profession, entry_time)
# 返回
return current_student
然后在commit
方法里,对封装的学生对象调用check
方法进行校验:
# 【1】封装当前的学生
current_student = self.get_current_student()
current_studentservices = StudentServices(self.list_student_all, current_student)
# 【2】校验学生
return_number = current_studentservices.check()
if return_number == 2:
showinfo("系统消息", "学号不符合要求")
elif return_number == 3:
showinfo("系统消息", "姓名不符合要求")
elif return_number == 4:
showinfo("系统消息", "手机号码不符合要求")
elif return_number == 5:
showinfo("系统消息", "邮箱地址不符合要求")
elif return_number == 1:
showinfo("系统消息", "所有都符合要求")
这里我们只对学号、姓名、手机号码、邮箱进行校验,如果不满足,就弹出警示框。

三、添加学生信息
1. 需求分析
我们希望打开添加学生信息窗口后,填入学生信息,点击保存按钮后,数据会立即显示在学校信息列表里。
2. 实现过程
为了获取填入的信息,我们在studentservices
中定义add
方法,将student_current
中的各个属性依次添加到current_student_list
列表中,再加current_student_list
列表加入到总列表list_all
中即可。
def add(self):
"""
添加学生
"""
# 暂存填入的学生信息
current_student_list = []
current_student_list.append(self.student_current.sno)
current_student_list.append(self.student_current.name)
current_student_list.append(self.student_current.gender)
current_student_list.append(self.student_current.birthday)
current_student_list.append(self.student_current.mobile)
current_student_list.append(self.student_current.email)
current_student_list.append(self.student_current.profession)
current_student_list.append(self.student_current.entry_time)
# 当前学生添加到集合中
self.list_all.append(current_student_list)
我们再到studentdetail
模块中,将commit
方法继续完善,补充添加功能。
current_studentservices.add()
执行add
方法后,list_student_all
总学生列表已经发生了变化,在明细窗口当我们点击关闭的时候,我们要将变化体现到主窗口的表格中来。
在我们添加完成后定义一个反馈信号给主窗体,
self.userinfo = 1
然后关闭这个明细窗体:
self.destory()
另一边,在主窗体中继续完善add_student
方法,在加载添加页面的方法中传入所有学生列表,和当前学生信息。然后获取明细窗体返回的值,刷新学生信息列表的Treeview
,这样添加学生信息,并且显示在主窗体表格的功能就实现了。
def add_student(self):
"""
添加学生信息
"""
self.flag = 3
# 加载添加的页面
detail = StudentDetail(self.flag, self.student_all, self.student_current)
self.wait_window(detail)
# 接受返回的值
get_return_number = detail.userinfo
# 如果为1 就刷新
if get_return_number == 1:
self.load_student_treeview()
3. 效果演示

四、修改学生信息
1. 需求分析
上面我们讲了添加学生信息,现在我们继续将修改学生信息。我们需要完成的功能是在主界面表格中选择某一行,点击修改按钮,打开修改明细窗口界面。
2. 实现过程
首先我们在主界面修改学生信息的方法中,在update_student
方法中,修改flag,获取当前行的信息,最后再实例化明细窗体界面。这些操作与添加学生信息的过程基本一致,这里不做过多重复讲解。
def update_student(self):
"""
修改学生信息
"""
# 修改flag
self.flag = 2
# 获取当前行的信息
item = self.Tree_student.selection()[0]
current_student = self.Tree_student.item(item,"values")
for item in self.student_all:
if current_student[0] == item[0]:
self.student_current = item
# 实例化界面
detail = StudentDetail(self.flag, self.student_all, self.student_current)
接着,我们在明细窗体中队load_gui_by_flag
方法再做完善,补充当flag==2
的情况。和查看明细窗口一样,我们需要将主窗体表格中选中的学生信息填充到明细窗体中来。由于学号是不允许修改的,所以将学号输入框禁用。
self.Entry_sno["state"] = DISABLED
效果演示:

然后在
studentservices
完善一下update
方法,我们通过循环遍历
list_all
,判断如果list_all
中的学号与current_student
学号相同,那么把明细窗体组建中的变量值赋值给list_all
中匹配的那个学生信息。
# 主要通关过循环遍历list,修改信息
for index in range(len(self.list_all)):
if self.list_all[index][0] == self.student_current.sno:
self.list_all[index][1] = self.student_current.name
self.list_all[index][2] = self.student_current.gender
self.list_all[index][3] = self.student_current.birthday
self.list_all[index][4] = self.student_current.mobile
self.list_all[index][5] = self.student_current.email
self.list_all[index][6] = self.student_current.profession
self.list_all[index][7] = self.student_current.entry_time
数据修改完成后,我们在commit
方法中完善修改功能,与添加学生信息的操作一样,我们需要封装当前学生类对象、校验输入的学生信息是否符合要求、调用update
方法修改列表、提示用户修改成功、反馈信号给主窗体、最后关闭这个窗体。
然后我们在主窗体界面中接收反馈,并刷新表格。
我们来看一下修改的动作有没有在主窗体表格中表现出来。
这样,我们修改的动作就已经完成了,其实套路和添加学生信息一样,现在我们演示一下将小新的专业改为“物联网”,一下为演示效果:

五、删除学生信息
1.需求分析
我们希望这主窗体界面的表格中选中学生,然后点击删除按钮,学生信息就被删除掉。注意,以上包括添加、修改、已经这里的删除,其操作对象都是list
,我们还并没有保存到本地文件。写入到本地文件等会我们会统一来做。
删除操作,相对简单,因为它只需要在主界面进行,没有跨越GUI,所有比较方便操作。
2.实现过程
我们首先把student_services
模块中的delete
方法给写好,我们同样还是通过遍历list_all
,然后匹配选中项,根据索引删除该项。
def delete(self):
# 主要通过循环遍历list,删除某条信息
for index in range(len(self.list_all)):
if self.list_all[index][0] == self.student_current.sno:
# pop是根据索引号来删除的
self.list_all.pop(index)
紧接着,我们完善主窗体中的delete_studet
方法,先获取选中行的数据,然后遍历list_all
,找到与被选中学生学号相同的项item
,然后把该条学生项封装成一个待删除的对象student_object
,实例化student_services
后,弹出窗口询问是否删除,如果是则执行删除动作,否则不删除。
def delete_student(self):
"""
删除学生信息
"""
# 获取双击行的数据
item = self.Tree_student.selection()[0]
current_student = self.Tree_student.item(item, "values")
student_object = ""
for item in self.student_all:
if current_student[0] == item[0]:
# 封装到student
student_object = Student(item[1], item[2], item[3], item[4],
item[5], item[0], item[6], item[7])
# 实例化StudentServices
current_student_services = StudentServices(self.student_all, student_object)
# 询问是否删除
choose = askyesno("删除确认","确认要删除学生信息【学号:"+student_object.sno +
",姓名:"+student_object.name+"】的信息吗?")
if choose:
# 执行删除动作
current_student_services.delete()
# 提醒删除成功
showinfo("系统消息", "学生消息删除成功")
# 更新表格
self.load_student_treeview()
else:
return
3. 效果演示

六、保存数据到文件
1. 需求分析
我们以上所做的所有增删改都是对list
进行操作,当程序重新打开后又恢复原样了,我们最后需要做的是把操作结果写入到文本文件中。
2. 实现过程
在file
类中,我们定义方法write_to_file
,先把文本内容清空,然后遍历list_student_all
中的每一个项,用,
填充在每一个项中,然后去除其中可能存在的换行符,但是在每一行的结束加上换行符。
def write_to_file(self):
# ============ 把学生信息写入文件 ========
try:
# 把原先的文件清空
with open(self.student_path, mode="w", encoding="UTF-8") as fd_student:
fd_student.write("")
with open(self.student_path, mode="a", encoding="UTF-8") as fd_student:
for item in self.list_student_all:
temp = ",".join(item)
temp = temp.replace("\n", "") + "\n" # 取出行中可能存在的换行符
fd_student.write(temp)
except Exception as e:
raise e
写入操作完成后,我们应当设置关闭窗口按钮时触发写入文件操作。
我们需要把窗体关闭按钮的行为转化为方法,在主窗体的构造函数中添加一个把窗体关闭按钮的行为转化为方法的语句。
self.protocol("WM_DELETE_WINDOW", self.close_window)
然后在下面定义close_window
的方法,点击窗口关闭按钮时跳出弹窗,询问是否保存修改,如果是则调用write_to_file
方法写入文件,写入成功后系统弹窗提醒用户已经写入成功,写入成功后关闭窗体即可。
def close_window(self):
# 询问是否保存修改
choose= askyesno("关闭前的提醒", "关闭窗体前是否要将修改写入到文件?")
if choose:
try:
self.file_info.write_to_file()
showinfo("系统提示", "所有的修改已经保存并写入到文件")
# 关闭窗口
self.destroy()
except Exception as e:
showinfo("系统消息", e)
else:
self.destroy()
注意:即使点击否,也要调用destory
方法关闭窗口,否则窗体会陷入无法关闭的死循环。
3. 效果演示

最后
以上,就是利用面向对象思想实现学生教师信息管理的全部内容了,如果大家能手动完成这个项目,必将对面向对象思想有着更加深刻的理解。
配套的源码及素材可以私信我获取。
网友评论