一、背景及分工

这次的博客是对第二次创新课程的作业,关于制作一个中小学数学学习系统和厉平安同学的结对项目的项目总结。这次的项目主要是我(索央)负责对图形化界面进行设计和布局,以及负责图形化界面的代码编写。而厉平安同学则负责对个人项目中的生成题目模块进行改写,并负责题目答案生成和注册模块、登录和修改密码的数据库模块。

二、项目简介

此结对项目我们基于python3.8开发,主要提供了一个中小学生数学学习的系统,我们有用户登录和注册功能,还有在登录状态下的修改密码功能,选择不同的学历生成不同难度的题目的功能,输入生成的卷子总数的功能,题目作答以及查看错题并显示正确答案等功能。

三、项目内容

1.  注册页面

湖南大学结对编程项目_修改密码

 

下面的代码为这个页面的图形化界面部分的代码:

 

 

湖南大学结对编程项目_修改密码_02湖南大学结对编程项目_修改密码_03
class SignIn:
    """
    注册页面
    """
    def __init__(self, parent_window):
        self.window = parent_window
        self.window.title('用户注册')

        self.phone_number = ''  # 手机号,也是用户唯一id
        self.verification = cc.new_verification()  # 新建验证码

        self.frame = tk.Frame(self.window)
        self.frame.place(x=0, y=0, width=800, height=500)
        self.frame.focus_set()

        self.bg_photo = tk.PhotoImage(file=PHOTO_PATH)
        self.canvas = tk.Canvas(self.frame, width=800, height=500,
                                highlightthickness=0, borderwidth=0)
        self.canvas.place(x=0, y=0)
        self.canvas.create_image(0, 0, anchor='nw', image=self.bg_photo)

        self.canvas.create_text(400, 75, text='用 户 注 册',
                                font=('微软雅黑', 40, 'bold'), fill='green')
        #  tip_label用于提示错误信息
        self.tip_label = self.canvas.create_text(
            400, 200,
            text='',
            font=('微软雅黑', 15, 'bold'), fill='red')

        self.canvas.create_text(300, 250, text='手机号:',
                                font=('微软雅黑', 20))
        self.phone_entry = tk.Entry(self.frame, font=('宋体', 20),
                                    relief='groove', width=15)
        self.phone_entry.place(x=450, y=250, anchor=tk.CENTER)

        self.canvas.create_text(300, 300, text='验证码:',
                                font=('微软雅黑', 20))
        self.code_entry = tk.Entry(self.frame, font=('宋体', 20), width=10)
        self.code_entry.place(x=415, y=300, anchor=tk.CENTER)

        self.code_button = tk.Button(self.frame, text='发送',
                                     font=('微软雅黑', 10), width=7, height=1,
                                     command=self.send_code,
                                     fg='black', bg='lightskyblue',
                                     activebackground='pink',
                                     activeforeground='black')
        self.code_button.place(x=530, y=300, anchor=tk.CENTER)

        return_button = tk.Button(self.frame, text="返回", font=('微软雅黑', 20),
                                  width=10, height=1,
                                  command=lambda: LogIn(self.window),
                                  fg='black', bg='tan',
                                  activebackground='pink',
                                  activeforeground='black')

        return_button.place(x=300, y=400, anchor=tk.CENTER)

        log_button = tk.Button(self.frame, text="注册", font=('微软雅黑', 20),
                               width=10, height=1,
                               command=self.log_change_pwd,
                               fg='black', bg='springgreen',
                               activebackground='pink',
                               activeforeground='black')
        log_button.place(x=500, y=400, anchor=tk.CENTER)

        self.window.bind("<Return>", self.log_change_pwd)  # 绑定响应
        self.phone_entry.focus_set()
        self.window.mainloop()
SignIn

 

 

在用户注册页面中用户可以输入自己的手机号,点击发送按钮后就可以在手机短信中收到六位验证码。

 

这个部分最重要的就是这个验证码的部分了,验证码系统就是在用户注册时为了验证是本人真实身份所以需要以验证码的形式来注册,其实在项目还没正式开始前因为对这方面东西并不是很了解,所以还挺担心这个验证码要怎么去弄,知道可以申请腾讯的短信服务后发现还是很麻烦,最终我们决定申请榛子云的短信服务,价格方面也比较实惠,他们使用的SDK非常清楚方便。

下面为发送验证码的函数:

def send_verification(phone_number, verification_code):
    """
    发送验证码
    :param phone_number: 手机号
    :param verification_code: 随机生成的六位数字验证码
    :return:返回发送状态,发送成功返回0
    """
    client = zc.ZhenziSmsClient('https://sms_developer.zhenzikj.com',
                                '110071',
                                'f6e23bfb-452e-409c-867c-4bf56a16a062')
    # AppId应用ID可在应用管理-我的应用下查看
    # AppSecret秘钥可在应用管理-我的应用下查看
    params = {
        'number': phone_number,
        'templateId': '6871',
        'templateParams': [verification_code, '5']}

    return json.loads(client.send(params))['code']

 

2.  登录页面

 湖南大学结对编程项目_图形化界面_04

 

下面的代码为这个页面的图形化界面部分的代码:

 

湖南大学结对编程项目_修改密码_02湖南大学结对编程项目_修改密码_03
class LogIn:
    """
    登录界面类
    """

    def __init__(self, parent_window):
        self.window = parent_window
        self.window.title('中小学数学学习系统')

        self.frame = tk.Frame(self.window)
        self.frame.place(x=0, y=0, width=800, height=500)
        self.frame.focus_set()

        self.bg_photo = tk.PhotoImage(file=PHOTO_PATH)
        self.canvas = tk.Canvas(self.frame, width=800, height=500,
                                highlightthickness=0, borderwidth=0)
        self.canvas.place(x=0, y=0)
        self.canvas.create_image(0, 0, anchor='nw', image=self.bg_photo)

        self.canvas.create_text(400, 75, text='中小学数学学习系统',
                                font=('微软雅黑', 40, 'bold'), fill='green')

        self.canvas.create_text(400, 150, text='By:厉平安 & 索央',
                                font=('微软雅黑', 20))

        self.tip_label = self.canvas.create_text(
            400, 200,
            text='',
            font=('微软雅黑', 15, 'bold'), fill='red')

        self.canvas.create_text(300, 250, text='账号:',
                                font=('微软雅黑', 20))
        self.id_entry = tk.Entry(self.frame, font=('宋体', 20),
                                 relief='groove', width=15)
        self.id_entry.place(x=450, y=250, anchor=tk.CENTER)

        self.canvas.create_text(300, 300, text='密码:',
                                font=('微软雅黑', 20))

        self.pwd_entry = tk.Entry(self.frame, font=('宋体', 20),
                                  width=15, show='*')
        self.pwd_entry.place(x=450, y=300, anchor=tk.CENTER)

        self.show_button = tk.Button(self.frame, text="显示",
                                     font=('微软雅黑', 10),
                                     width=5, height=1,
                                     command=self.show_change,
                                     fg='black', bg='lightpink',
                                     activebackground='pink',
                                     activeforeground='black')
        self.show_button.place(x=585, y=300, anchor=tk.CENTER)
        sign_button = tk.Button(self.frame, text="注册",
                                font=('微软雅黑', 20),
                                width=10, height=1,
                                command=self.sign_in,
                                fg='black', bg='tan',
                                activebackground='pink',
                                activeforeground='black')
        sign_button.place(x=300, y=400, anchor=tk.CENTER)
        log_button = tk.Button(self.frame, text="登录",
                               font=('微软雅黑', 20),
                               width=10, height=1,
                               command=self.log_in,
                               fg='black', bg='springgreen',
                               activebackground='pink',
                               activeforeground='black')
        log_button.place(x=500, y=400, anchor=tk.CENTER)

        self.window.bind("<Return>", self.log_in)  # 绑定响应
        self.id_entry.focus_set()  # 设置聚焦
        self.window.mainloop()

    def show_change(self):
        if self.pwd_entry['show'] == '*':
            self.pwd_entry['show'] = ''
            self.show_button['text'] = '不显示'
        else:
            self.pwd_entry['show'] = '*'
            self.show_button['text'] = '显示'
LogIn

 

在登录界面中我们可以输入账号和密码,在这里密码也可以按下显示按钮来显示出来,如果不按下则密码都显示为“*”。按下注册按钮则跳转到注册页面,按下登录按钮,则会检查账号密码是否匹配(user_login)。

下面为检查账号密码是否匹配的函数:

这里我们没有用表格的形式来存储记录用户信息,而是利用了轻量级的sqlite,sqlite是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。它是一个零配置的数据库,这意味着与其他数据库一样,不需要在系统中配置。

def user_login(user_id, user_pwd):
    """
    检查账号密码是否匹配
    :param user_id: 用户id
    :param user_pwd: 用户密码
    :return: 返回flag是否账号密码匹配
    """
    path = (os.getcwd() + os.path.sep + 'src' +
            os.path.sep + 'user_info\\users.db')
    conn = sqlite3.connect(path)
    cursor = conn.cursor()
    flag = True
    cursor.execute('''SELECT * FROM USER WHERE NAME = ? AND
                    PASSWORD = ?''', (user_id, user_pwd))
    if cursor.fetchone() is None:
        flag = False

    cursor.close()  # 关闭cursor
    conn.commit()  # 提交事务
    conn.close()  # 关闭连接
    return flag

下面这个为实现注册按钮的函数以及实现登录按钮的函数:

    def sign_in(self):
        """
        注册函数
        :return:
        """
        self.frame.destroy()
        SignIn(self.window)

    def log_in(self, unused_ev=None):
        """
        登录函数
        :return:
        """
        user_id = self.id_entry.get()
        user_pwd = self.pwd_entry.get()
        if um.user_login(user_id, user_pwd):
            self.frame.destroy()
            MainMenu(self.window, user_id)
        else:
            self.canvas.itemconfig(self.tip_label,
                                   text='账号或者密码输入错误!')
            self.pwd_entry.delete(0, tk.END)

 

3. 登录后修改密码

湖南大学结对编程项目_修改密码_07

 

 

 下面的代码为这个页面的图形化界面部分的代码:

湖南大学结对编程项目_修改密码_02湖南大学结对编程项目_修改密码_03
class LogInChange:
    """
    注册改变密码
    """
    def __init__(self, parent_window, user_id):
        self.user_id = user_id
        self.window = parent_window
        self.window.title('新用户设置密码')

        self.frame = tk.Frame(self.window)
        self.frame.place(x=0, y=0, width=800, height=500)
        self.frame.focus_set()

        self.bg_photo = tk.PhotoImage(file=PHOTO_PATH)
        self.canvas = tk.Canvas(self.frame, width=800, height=500,
                                highlightthickness=0, borderwidth=0)
        self.canvas.place(x=0, y=0)
        self.canvas.create_image(0, 0, anchor='nw', image=self.bg_photo)

        self.canvas.create_text(400, 75, text='设 置 密 码',
                                font=('微软雅黑', 40, 'bold'), fill='green')
        #  tip_label用于提示错误信息
        self.tip_label = self.canvas.create_text(
            400, 200,
            text='',
            font=('微软雅黑', 15, 'bold'), fill='red')

        self.canvas.create_text(280, 240, text='输入密码:',
                                font=('微软雅黑', 20))
        self.pwd_entry = tk.Entry(self.frame, font=('宋体', 20),
                                  relief='groove', width=15, show='*')
        self.pwd_entry.place(x=450, y=240, anchor=tk.CENTER)

        self.canvas.create_text(450, 270, text='(包含大小写字母及数字,6-10位)',
                                font=('微软雅黑', 10))

        self.canvas.create_text(280, 300, text='再次输入:',
                                font=('微软雅黑', 20))
        self.pwd_again_entry = tk.Entry(self.frame, font=('宋体', 20),
                                        relief='groove', width=15, show='*')
        self.pwd_again_entry.place(x=450, y=300, anchor=tk.CENTER)

        self.show_button = tk.Button(self.frame, text="显示",
                                     font=('微软雅黑', 10),
                                     width=5, height=1,
                                     command=self.show_change,
                                     fg='black', bg='lightpink',
                                     activebackground='pink',
                                     activeforeground='black')
        self.show_button.place(x=585, y=300, anchor=tk.CENTER)

        return_button = tk.Button(self.frame, text="返回", font=('微软雅黑', 20),
                                  width=10, height=1,
                                  command=lambda: LogIn(self.window),
                                  fg='black', bg='tan',
                                  activebackground='pink',
                                  activeforeground='black')

        return_button.place(x=300, y=400, anchor=tk.CENTER)

        confirm_button = tk.Button(self.frame, text="确认", font=('微软雅黑', 20),
                                   width=10, height=1,
                                   fg='black', bg='springgreen',
                                   command=self.check_pwd,
                                   activebackground='pink',
                                   activeforeground='black')
        confirm_button.place(x=500, y=400, anchor=tk.CENTER)

        self.window.bind("<Return>", self.check_pwd)  # 绑定响应
        self.pwd_entry.focus_set()
        self.window.mainloop()
LogInChange

 

下面代码为密码显示按键的一些操作以及两次密码是否相同的判断。

    def show_change(self):
        if self.pwd_entry['show'] == '*':
            self.pwd_entry['show'] = ''
            self.pwd_again_entry['show'] = ''
            self.show_button['text'] = '不显示'
        else:
            self.pwd_entry['show'] = '*'
            self.pwd_again_entry['show'] = '*'
            self.show_button['text'] = '显示'

    def check_pwd(self, unused_ev=None):
        pwd = self.pwd_entry.get()
        pwd_again = self.pwd_again_entry.get()
        compile_pwd = re.compile('^(?=.*[0-9].*)(?=.*[A-Z].*)'
                                 '(?=.*[a-z].*).{6,10}$')
        if compile_pwd.match(pwd):
            if pwd == pwd_again:
                um.user_new(self.user_id, pwd)
                messagebox.showinfo(title='注册成功',
                                    message='用户%s,您已经成功注册!'
                                            % self.user_id)
                LogIn(self.window)
            else:
                self.canvas.itemconfig(self.tip_label,
                                       text='两次输入密码不一致!')
                self.pwd_again_entry.delete(0, tk.END)
                self.pwd_again_entry.focus_set()
        else:
            self.canvas.itemconfig(self.tip_label,
                                   text='密码格式不正确!')
            self.pwd_entry.delete(0, tk.END)
            self.pwd_again_entry.delete(0, tk.END)
            self.pwd_entry.focus_set()

 

4.  主菜单页面

湖南大学结对编程项目_验证码_10

 

下面的代码为这个页面的图形化界面部分的代码:

湖南大学结对编程项目_修改密码_02湖南大学结对编程项目_修改密码_03
class MainMenu:
    """
    主菜单:包括修改密码和选择学历
    """
    def __init__(self, parent_window, user_id):  # 包括传输的密码和账号
        self.user_id = user_id
        self.window = parent_window
        self.window.title('主菜单')

        self.frame = tk.Frame(self.window)
        self.frame.place(x=0, y=0, width=800, height=500)
        self.frame.focus_set()

        self.bg_photo = tk.PhotoImage(file=PHOTO_PATH)
        self.canvas = tk.Canvas(self.frame, width=800, height=500,
                                highlightthickness=0, borderwidth=0)
        self.canvas.place(x=0, y=0)
        self.canvas.create_image(0, 0, anchor='nw', image=self.bg_photo)

        self.canvas.create_text(400, 75, text='请选择对应学历',
                                font=('微软雅黑', 40, 'bold'), fill='green')

        self.tip_label = self.canvas.create_text(
            400, 150,
            text='您选了小学',
            font=('微软雅黑', 15, 'bold'), fill='red')

        self.var = tk.IntVar()  # 单选框变量
        rd1 = tk.Radiobutton(self.frame,
                             variable=self.var, value=1,
                             command=self.select_dis)
        rd1.place(x=350, y=200, anchor=tk.CENTER)
        self.canvas.create_text(400, 200, text='小  学',
                                font=('微软雅黑', 20, 'bold'))
        rd2 = tk.Radiobutton(self.frame,
                             variable=self.var, value=2,
                             command=self.select_dis)
        rd2.place(x=350, y=250, anchor=tk.CENTER)
        self.canvas.create_text(400, 250, text='初  中',
                                font=('微软雅黑', 20, 'bold'))
        rd3 = tk.Radiobutton(self.frame,
                             variable=self.var, value=3,
                             command=self.select_dis)
        rd3.place(x=350, y=300, anchor=tk.CENTER)
        self.canvas.create_text(400, 300, text='高  中',
                                font=('微软雅黑', 20, 'bold'))
        self.var.set(1)

        return_button = tk.Button(self.frame, text="退出",
                                  font=('微软雅黑', 20),
                                  width=10, height=1,
                                  command=lambda: LogIn(self.window),
                                  fg='black', bg='orangered',
                                  activebackground='pink',
                                  activeforeground='black')

        return_button.place(x=200, y=400, anchor=tk.CENTER)

        change_button = tk.Button(self.frame, text="修改密码",
                                  font=('微软雅黑', 20),
                                  width=10, height=1,
                                  fg='black', bg='LavenderBlush',
                                  command=self.change_pwd,
                                  activebackground='pink',
                                  activeforeground='black')
        change_button.place(x=400, y=400, anchor=tk.CENTER)

        confirm_button = tk.Button(self.frame, text="确认", font=('微软雅黑', 20),
                                   width=10, height=1,
                                   fg='black', bg='springgreen',
                                   command=self.test_number,
                                   activebackground='pink',
                                   activeforeground='black')
        confirm_button.place(x=600, y=400, anchor=tk.CENTER)

        self.window.bind("<Return>", self.test_number)  # 绑定响应
        self.window.mainloop()
MainMenu

 

在主菜单中我们可以选择学历也可以修改密码

    def select_dis(self):  # 选择显示
        dic = {1: '小学', 2: '初中', 3: '高中'}
        s = "您选了" + dic.get(self.var.get())
        self.canvas.itemconfig(self.tip_label,
                               text=s)

    def change_pwd(self):  # 修改密码
        self.frame.destroy()
        ChangePwd(self.window, self.user_id)

    def test_number(self, unused_ev=None):  # 进入题目数量模块
        if self.var.get() == 0:
            self.canvas.itemconfig(self.tip_label,
                                   text='您还没进行选择!')
        else:
            self.frame.destroy()
            TestNumber(self.window, self.user_id, self.var.get())

 

5. 题目数量选择界面

湖南大学结对编程项目_spring_13

 

 

 下面的代码为这个页面的图形化界面部分的代码:

湖南大学结对编程项目_修改密码_02湖南大学结对编程项目_修改密码_03
class TestNumber:
    """
    题目数量模块
    """
    dic = {1: '小 学', 2: '初 中', 3: '高 中'}

    def __init__(self, parent_window, user_id, study_level):
        self.user_id = user_id
        self.study_level = study_level  # 对应学历
        self.window = parent_window
        self.window.title('生成题目')

        self.frame = tk.Frame(self.window)
        self.frame.place(x=0, y=0, width=800, height=500)
        self.frame.focus_set()

        self.bg_photo = tk.PhotoImage(file=PHOTO_PATH)
        self.canvas = tk.Canvas(self.frame, width=800, height=500,
                                highlightthickness=0, borderwidth=0)
        self.canvas.place(x=0, y=0)
        self.canvas.create_image(0, 0, anchor='nw', image=self.bg_photo)

        self.canvas.create_text(400, 75,
                                text='%s 题 目'
                                     % self.dic.get(self.study_level),
                                font=('微软雅黑', 40, 'bold'), fill='green')

        self.tip_label = self.canvas.create_text(
            400, 150,
            text='',
            font=('微软雅黑', 15, 'bold'), fill='red')

        self.canvas.create_text(400, 200,
                                text='请输入题目数量(10-30)',
                                font=('微软雅黑', 25, 'bold'))

        self.test_entry = tk.Entry(self.frame, font=('宋体', 40),
                                   relief='groove', width=5)
        self.test_entry.place(x=400, y=275, anchor=tk.CENTER)

        return_button = tk.Button(self.frame, text="返回",
                                  font=('微软雅黑', 20),
                                  width=10, height=1,
                                  command=lambda: MainMenu(self.window,
                                                           user_id),
                                  fg='black', bg='tan',
                                  activebackground='pink',
                                  activeforeground='black')

        return_button.place(x=300, y=400, anchor=tk.CENTER)

        confirm_button = tk.Button(self.frame, text="开始答题",
                                   font=('微软雅黑', 20),
                                   width=10, height=1,
                                   fg='black', bg='springgreen',
                                   command=self.confirm_test,
                                   activebackground='pink',
                                   activeforeground='black')
        confirm_button.place(x=500, y=400, anchor=tk.CENTER)

        self.window.bind("<Return>", self.confirm_test)  # 绑定响应
        self.test_entry.focus_set()  # 设置聚焦
        self.window.mainloop()
TestNumber

 

在这一页面下我们可以自行选择题目的数量,并开始作答或返回学历选择页面

 

6.做题界面

湖南大学结对编程项目_spring_16

 

 

  下面的代码为这个页面的图形化界面部分的代码:

湖南大学结对编程项目_修改密码_02湖南大学结对编程项目_修改密码_03
class Test:
    """
    做题模块
    """
    test_list = []  # 传来的题目

    def __init__(self, parent_window, user_id, study_level, test_number):
        self.user_id = user_id
        self.study_level = study_level
        self.test_number = test_number  # 题目数量
        self.test_list = nt.new_test(self.study_level,
                                     self.test_number)
        self.select_list = [0]*test_number   # 选择的答案列表,开始全为0

        self.window = parent_window
        self.window.title('做题')

        self.frame = tk.Frame(self.window, bg='aliceblue')
        self.frame.place(x=0, y=0, width=800, height=500)
        self.frame.focus_set()

        test_select_frame = tk.Frame(self.frame, bg='aliceblue')
        test_select_frame.place(x=0, y=0, width=200, height=500)

        self.show_label = tk.Label(test_select_frame, text='',
                                   font=('宋体', 20, 'bold'),
                                   fg='red', bg='aliceblue',)
        self.show_label.place(x=0, y=450, width=200, height=100, anchor=tk.W)

        self.test_var = tk.IntVar()  # 选择题目
        self.test_button_list = []
        for i in range(0, self.test_number):
            # value=i,但显示题目要i+1,下标从零开始
            test_button = tk.Radiobutton(test_select_frame, text=str(i+1),
                                         font=('微软雅黑', 10, 'bold'),
                                         bg='aliceblue',
                                         variable=self.test_var, value=i,
                                         command=self.select_dis)
            test_button.grid(row=i//3, column=i-(i//3)*3, pady=5)
            self.test_button_list.append(test_button)
        self.test_var.set(0)

        test_frame = tk.Frame(self.frame, bg='aliceblue')
        test_frame.place(x=200, y=0, width=650, height=400)

        self.test_label = tk.Label(test_frame, text='1) '+self.test_list[0][0],
                                   font=('微软雅黑', 30, 'bold'),
                                   fg='black', bg='aliceblue')

        self.test_label.pack(pady=20)

        self.option_var = tk.IntVar()
        self.a_rd = tk.Radiobutton(test_frame,
                                   text="A." + str(self.test_list[0][2][0]),
                                   font=('微软雅黑', 15, 'bold'),
                                   bg='aliceblue', command=self.option_dis,
                                   variable=self.option_var, value=1)
        self.a_rd.pack(pady=10)
        self.b_rd = tk.Radiobutton(test_frame,
                                   text="B." + str(self.test_list[0][2][1]),
                                   font=('微软雅黑', 15, 'bold'),
                                   bg='aliceblue',
                                   command=self.option_dis,
                                   variable=self.option_var, value=2)
        self.b_rd.pack(pady=10)
        self.c_rd = tk.Radiobutton(test_frame,
                                   text="C." + str(self.test_list[0][2][2]),
                                   font=('微软雅黑', 15, 'bold'),
                                   bg='aliceblue',
                                   command=self.option_dis,
                                   variable=self.option_var, value=3)
        self.c_rd.pack(pady=10)
        self.d_rd = tk.Radiobutton(test_frame,
                                   text="D." + str(self.test_list[0][2][3]),
                                   font=('微软雅黑', 15, 'bold'),
                                   bg='aliceblue',
                                   command=self.option_dis,
                                   variable=self.option_var, value=4)
        self.d_rd.pack(pady=10)
        self.option_var.set(0)

        button_frame = tk.Frame(self.frame, bg='aliceblue')
        button_frame.place(x=350, y=350, width=450, height=100)
        self.last_button = tk.Button(button_frame, text="上一题",
                                     font=('微软雅黑', 15),
                                     width=10, height=1,
                                     fg='black', bg='tan',
                                     command=self.last_test,
                                     state='disable',
                                     activebackground='pink',
                                     activeforeground='black')

        self.last_button.grid(row=0, column=1, sticky=tk.E)
        self.next_button = tk.Button(button_frame, text="下一题",
                                     font=('微软雅黑', 15),
                                     width=10, height=1,
                                     fg='black', bg='tan',
                                     command=self.next_test,
                                     activebackground='pink',
                                     activeforeground='black')

        self.next_button.grid(row=0, column=2, padx=40, sticky=tk.W)
        return_button = tk.Button(button_frame, text="退出",
                                  font=('微软雅黑', 15),
                                  width=10, height=1,
                                  command=lambda: LogIn(self.window),
                                  fg='black', bg='red',
                                  activebackground='pink',
                                  activeforeground='black')

        return_button.grid(row=1, column=1, pady=5, sticky=tk.E)
        self.commit_button = tk.Button(button_frame, text="交卷",
                                       font=('微软雅黑', 15),
                                       width=10, height=1,
                                       command=self.commit_message,
                                       fg='black', bg='springgreen',
                                       activebackground='pink',
                                       activeforeground='black')

        self.commit_button.grid(row=1, column=2, padx=40, pady=5, sticky=tk.W)

        self.window.bind("<Return>", self.commit_message)  # 绑定响应
        self.window.mainloop()
Test

 

代码复用:

其实这次结对项目中还有很多代码复用的部分,我们主要是以栈和优先级的一些思路去完成运算的。

def calculate(equation):
    """
    算式运算
    :param equation: 算式的字符序列
    :return: 返回最后的运算结果
    """
    number = Stack()
    sign = Stack()
    sign_dict = {'^2': 3, '': 3, 'sin': 3, 'cos': 3, 'tan': 3,
                 '*': 2, '/': 2, '+': 1, '-': 1, '(': 0}
    #  符号表按优先级从低到高安排
    for item in equation:
        if item.isdigit():  # 数字直接入栈
            number.push(float(item))
        elif item == '(':  # 左括号入栈
            sign.push(item)
        elif item == ')':  # 右括号则进行运算
            top = sign.pop()
            while top != '(':
                if top in ['+', '-', '*', '/']:
                    op1 = number.pop()
                    op2 = number.pop()
                    number.push(double_value(top, op2, op1))
                    top = sign.pop()
                elif top in ['^2', '', 'sin', 'cos', 'tan']:
                    op = number.pop()
                    number.push(single_value(top, op))
                    top = sign.pop()
        else:  # 运算符要把之前优先级大于其的都弹出来计算
            while (not sign.is_empty()
                   and sign_dict[sign.peek()] >= sign_dict[item]):
                top = sign.pop()
                if top in ['+', '-', '*', '/']:
                    op1 = number.pop()
                    op2 = number.pop()
                    number.push(double_value(top, op2, op1))
                elif top in ['^2', '', 'sin', 'cos', 'tan']:
                    if item in ['^2', '', 'sin', 'cos', 'tan']:
                        sign.push(top)
                        break
                    else:
                        op = number.pop()
                        number.push(single_value(top, op))
            sign.push(item)
    while not sign.is_empty():
        top = sign.pop()
        if top in ['+', '-', '*', '/']:
            op1 = number.pop()
            op2 = number.pop()
            number.push(double_value(top, op2, op1))
        elif top in ['^2', '', 'sin', 'cos', 'tan']:
            op = number.pop()
            number.push(single_value(top, op))
    if int(number.peek()) == number.peek():
        return int(number.pop())
    return float('%.2f' % number.pop())

 

7.得分界面

湖南大学结对编程项目_spring_19

 下面的代码为这个页面的图形化界面部分的代码:

湖南大学结对编程项目_修改密码_02湖南大学结对编程项目_修改密码_03
class Score:
    """
    得分页面
    """
    def __init__(self, parent_window,
                 user_id, test_list,
                 select_list, study_level):

        self.user_id = user_id
        self.test_list = test_list
        self.select_list = select_list
        self.study_level = study_level
        self.window = parent_window
        self.window.title('分数查看')

        self.frame = tk.Frame(self.window)
        self.frame.place(x=0, y=0, width=800, height=500)
        self.frame.focus_set()

        self.bg_photo = tk.PhotoImage(file=PHOTO_PATH)
        self.canvas = tk.Canvas(self.frame, width=800, height=500,
                                highlightthickness=0, borderwidth=0)
        self.canvas.place(x=0, y=0)
        self.canvas.create_image(0, 0, anchor='nw', image=self.bg_photo)

        self.canvas.create_text(400, 75,
                                text='您 的 得 分',
                                font=('微软雅黑', 40, 'bold'), fill='green')

        true_number = 0
        for i in range(0, len(self.select_list)):
            if self.select_list[i] == self.test_list[i][1]:
                true_number += 1
        score = (true_number / len(test_list)) * 100
        score = '%.2f' % score
        self.canvas.create_text(400, 200, text=score,
                                font=('微软雅黑', 50, 'bold'), fill='red')

        return_button = tk.Button(self.frame, text="退出", font=('微软雅黑', 20),
                                  width=10, height=1,
                                  command=lambda: LogIn(self.window),
                                  fg='black', bg='orangered',
                                  activebackground='pink',
                                  activeforeground='black')

        return_button.place(x=200, y=400, anchor=tk.CENTER)

        check_button = tk.Button(self.frame, text="查看错题",
                                 font=('微软雅黑', 20),
                                 width=10, height=1,
                                 fg='black', bg='LavenderBlush',
                                 command=self.check_wrong,
                                 activebackground='pink',
                                 activeforeground='black')
        check_button.place(x=400, y=400, anchor=tk.CENTER)

        continue_button = tk.Button(self.frame, text="继续做题",
                                    font=('微软雅黑', 20),
                                    width=10, height=1,
                                    fg='black', bg='springgreen',
                                    command=self.continue_test,
                                    activebackground='pink',
                                    activeforeground='black')
        continue_button.place(x=600, y=400, anchor=tk.CENTER)

        self.window.mainloop()
Score

 

8.错题界面

在这个界面中用户可以查看错题

湖南大学结对编程项目_验证码_22

 

  下面的代码为这个页面的图形化界面部分的代码:

湖南大学结对编程项目_修改密码_02湖南大学结对编程项目_修改密码_03
class CheckWrong:
    """
    错题页面
    """
    def __init__(self, parent_window,
                 user_id, wrong_test_list,
                 study_level):

        self.user_id = user_id
        self.wrong_test_list = wrong_test_list
        self.study_level = study_level
        self.window = parent_window
        self.window.title('分数查看')

        self.frame = tk.Frame(self.window)
        self.frame.place(x=0, y=0, width=800, height=500)
        self.frame.focus_set()

        self.bg_photo = tk.PhotoImage(file=PHOTO_PATH)
        self.canvas = tk.Canvas(self.frame, width=800, height=500,
                                highlightthickness=0, borderwidth=0)
        self.canvas.place(x=0, y=0)
        self.canvas.create_image(0, 0, anchor='nw', image=self.bg_photo)

        self.position = 0
        self.canvas.create_text(400, 75,
                                text='错 题 查 看',
                                font=('微软雅黑', 40, 'bold'), fill='green')
        self.test = self.canvas.create_text(
            400, 150,
            text=self.wrong_test_list[0][0],
            font=('微软雅黑', 25))
        self.canvas.create_text(300, 200,
                                text='你的答案:',
                                font=('微软雅黑', 25))

        self.own_answer = self.canvas.create_text(
            500, 200,
            text=self.wrong_test_list[0][1],
            font=('微软雅黑', 25), fill='red')

        self.canvas.create_text(300, 250,
                                text='正确答案:',
                                font=('微软雅黑', 25))
        self.true_answer = self.canvas.create_text(
            500, 250,
            text=self.wrong_test_list[0][2],
            font=('微软雅黑', 25), fill='green')

        self.last_button = tk.Button(self.frame, text="上一题",
                                     font=('微软雅黑', 20),
                                     width=10, height=1,
                                     fg='black', bg='tan',
                                     command=self.last_test,
                                     activebackground='pink',
                                     activeforeground='black',
                                     state='disable')

        self.last_button.place(x=300, y=325, anchor=tk.CENTER)

        self.next_button = tk.Button(self.frame, text="下一题",
                                     font=('微软雅黑', 20),
                                     width=10, height=1,
                                     fg='black', bg='tan',
                                     command=self.next_test,
                                     activebackground='pink',
                                     activeforeground='black')
        self.next_button.place(x=500, y=325, anchor=tk.CENTER)

        return_button = tk.Button(self.frame, text="退出",
                                  font=('微软雅黑', 20),
                                  width=10, height=1,
                                  command=lambda: LogIn(self.window),
                                  fg='black', bg='red',
                                  activebackground='pink',
                                  activeforeground='black')

        return_button.place(x=300, y=400, anchor=tk.CENTER)

        confirm_button = tk.Button(self.frame, text="继续答题",
                                   font=('微软雅黑', 20),
                                   width=10, height=1,
                                   fg='black', bg='springgreen',
                                   command=self.continue_test,
                                   activebackground='pink',
                                   activeforeground='black')
        confirm_button.place(x=500, y=400, anchor=tk.CENTER)

        self.window.mainloop()
CheckWrong

 

四、遇到的问题

对于团队项目这种形式而言,其实其中我们也产生了一些分歧,因为是两个不同的人去写,想法上会有一些不同,小到图形化界面中一些颜色的选择上,大到整个项目的完成思路,这些都是需要磨合讨论的,不过我们的项目最终还是以彼此比较满意的样子完成了。

对于项目本身来说,验证码的部分是一个问题,我们利用榛子云的短信服务来解决了,还有最后答案的计算问题上也有些问题,我们最后也是商量了用出栈入栈以及优先级的思路去解决了。

 

五、结对项目总结感受

在这次的结对项目开始前本来一直很紧张,因为之前也没有接触过图形化界面,短信验证码等内容,也没怎么跟同学合作做过这种比较复杂的项目,但最后真的开始以后却觉得不太紧张,甚至因为可以在较短的时间内能够边看边学边写,所以在整个过程中自己是处于较为轻松愉快的状态的。

这次的结对项目中也复用了很多之前个人项目中的代码,我们也对之前的这些代码进行了一些改动,其实也是一个回顾优化的过程。

结对这个形式对我而言,是觉得非常有易的,因为这样我们就有更多的想法更好的想法,遇到问题能两个人一起想办法,在写代码的时候对方也可以找到一些你可能自己发现不了的错误,提高了写项目的效率。

在这次项目中我学到了很多东西,也提升了自己的自信心,我觉得是比较好的完成了这次任务。