美文网首页pythonPython
Python面向对象实战:学生教师信息管理(5)

Python面向对象实战:学生教师信息管理(5)

作者: 小雨Coding | 来源:发表于2021-03-15 20:28 被阅读0次

前言

这一节我们将实现校验、添加、修改、删除、保存的功能。

part5 完成项目

一、创建StudentServicel类

1. 准备好校验类check

为了完善学生或教师信息的添加功能,我们需要对输入的数据进行校验。前面我们已经使用过Check类,利用正则表达式分别对学号、姓名、性别、手机号、邮箱的基本规范做校验。现在我们可以直接拿来使用。

2. 定义抽象类services

我们再定义一个抽象类services,准备定义抽象方法有:add
updatedeletecheck;

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("系统消息", "所有都符合要求")

这里我们只对学号、姓名、手机号码、邮箱进行校验,如果不满足,就弹出警示框。


学号必须以95开头5位数

三、添加学生信息

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.gif

四、修改学生信息

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

效果演示:

图片.png
然后在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.gif

五、删除学生信息

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.gif

六、保存数据到文件

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. 效果演示
1.gif

最后

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

相关文章

网友评论

    本文标题:Python面向对象实战:学生教师信息管理(5)

    本文链接:https://www.haomeiwen.com/subject/qdeoqltx.html