本专栏目录:
一、实验综述
二、基于MySQL进行的数据库的搭建
三、程序登录、注册界面的制作(即本篇)
四、数据导入界面的制作
五、collage(大学)表的增删改查界面的制作
六、province(省份)表的增删改查界面的制作
七、student_num(考生人数)表的增删改查界面以及数据可视化的制作
八、min_score_line(最低分数线)表的增删改查界面以及数据可视化的制作
九、collage_level(学校等级)表的增删改查界面的制作
十、enrollment_type(招生类型)表的增删改查界面的制作
十一、enrollment(招生人数)表的增删改查界面以及数据可视化的制作
十二、school_type(学校类型)表的增删改查界面的制作
十三、collage_school_level(各高校等级)表的增删改查界面的制作
十四、collage_province_enrollment_type(各高校招生类型)表的增删改查界面的制作
本部分将正式进入程序的编写,将叙述如何基于数据库中的user(用户)表搭建出一个看上去还算可以的登录以及注册界面;
这部分总共包括四个界面:初始界面,注册界面,使用指南界面以及登陆成功后的功能、表格选择界面;
可以实现的功能包括:支持账号密码验证登录,支持未注册账号提醒注册,支持密码输入格式规范化检查,支持密码防误差二次验证,支持用户名重复性检查,支持邮箱格式规范化检查,支持账号密码空值检查,支持成绩输入非整数检查,支持对除账户表格外其他表格进行选择,并进入增删改查界面或数据导入表格选择界面。
接下来将舞台交给代码段,所有的解释都将以注释的形式呈现:
import tkinter as tk # 本代码段需用
import pymysql as py # 本代码段需用
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from tkinter import ttk
from tkinter import messagebox # 本代码段需用
import re # 本代码段需用
import turtle # 本代码段需用
import random # 本代码段需用
import time # 本代码段需用
# 配置数据库IP,只有明确了IP,才能连接数据库,这个IP的意思实际上是本机IP,由于一些技术上的原因,导致该程序无法跨局域网运行,因此直接开摆,干脆只让它在主机运行
ip = "127.0.0.1"
# 窗口
window = tk.Tk() # 这是主窗口,也就是所说的初始界面
window.title("欢迎使用本系统") # 窗口名
window.geometry("450x300") # 窗口大小
# 背景图片
canvas = tk.Canvas(window, height=1450, width=1300) # 背景画布大小以及画布的所在窗口,即主窗口
image0 = tk.PhotoImage(file="樱顶1.png") # 设定背景图像路径,这张图片是什么随便你
image = canvas.create_image(0, 0, anchor="nw", image=image0) # 设置图像位置等参数
canvas.pack(side="top")
# 标签
tk.Label(window, text="高校报考信息查询系统").place(x=170, y=60) # 设置提示文本及像素位置
tk.Label(window, text="请切记务必在使用本系统前仔细阅读使用说明,不然保证无法使用").place(x=60, y=90)
tk.Label(window, text="用户名:").place(x=100, y=150) # 这是用户名输入框的提示文字
tk.Label(window, text="密码:").place(x=100, y=190) # 类上
# 输入框
username_input = tk.StringVar()
frame_username_input = tk.Entry(window, textvariable=username_input)
frame_username_input.place(x=160, y=150) # 设置账号输入框及其位置,并获取输入值
password_input = tk.StringVar()
frame_password_input = tk.Entry(window, textvariable=password_input, show="*") # 密码输入全部用*隐藏
frame_password_input.place(x=160, y=190) # 设置账号输入框及其位置,并获取输入值
# 登录函数
def log_in():
username = username_input.get()
password = password_input.get() # 获取账号密码的输入值
conn = py.connect(host='%s' % ip, user='lzx', password='lzx', port=3306, database='dbms_report',
charset='utf8') # 登录数据库,建立数据库连接,账号密码端口啥的都是自己在数据库那边设好的,不是固定的
cursor = conn.cursor() # 设置游标
a = cursor.execute("select * from user") # 执行SQL语句
b = cursor.fetchall() # 获取SQL执行结果
list_usernames = []
list_passwords = [] # 预设两个空的列表
for i in range(0, a):
list_usernames.append(b[i][0])
list_passwords.append(b[i][1]) # 获取数据一一对应输入新列表(列表有序性的好处就体现出来了)
dict_users = dict(zip(list_usernames, list_passwords)) # 拼接列表形成字典,用于密码校验(即账号密码一一对应)
if username in list_usernames: # 检查账号是否存在
if password == dict_users[username]: # 账号存在的话,检查密码是否正确
tk.messagebox.showinfo(title="welcome", message=username+",欢迎您") # 密码校验成功进入主系统,并弹出欢迎窗口
choose() # 运行功能、表格选择界面函数
else:
tk.messagebox.showerror(message="密码错误") # 密码校验失败弹出警示窗口
elif username == "":
tk.messagebox.showerror(message="用户名不能为空") # 检查用户名不能为空,弹出警示窗口
elif password == "":
tk.messagebox.showerror(message="密码不能为空") # 检查密码不能为空,弹出警示窗口
else:
sign_up_ask = tk.messagebox.askyesno("提醒", "您尚未注册,是否注册?") # 提示注册并选择是与否
if sign_up_ask is True:
sign_up() # 是,运行注册界面函数
conn.commit() # 事务成功运行完成
conn.close() # 关闭连接
# 注册界面函数
def sign_up():
# 写入函数
def save_user():
try:
conn = py.connect(host='%s' % ip, user='lzx', password='lzx', port=3306, database='dbms_report',
charset='utf8')
cursor = conn.cursor()
# 密码等检查
try:
save_username = str(new_username.get())
save_password = str(new_password.get())
save_password_confirm = str(new_password_confirm.get())
save_user_e_mail = str(user_e_mail.get())
save_province_name = str(province_name.get())
save_score = int(score.get()) # 获取数据,为数字检查做准备,至于这个数据哪里来的,还请往后看,输入框啥的在后面,不能放在前面的原因在于运行顺序的问题。
pattern_password = r"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[0-9a-zA-Z]{8,12}$" # 正则表达式:密码8到12位,且需要包含数字以及大小写字母
pattern_e_mail = r"^[0-9a-zA-Z]+(@)[0-9a-zA-Z]+\.(com)$" # 正则表达式校验邮箱格式:xxx@xxx.com
result_password = re.match(pattern_password, save_password) # 校验密码格式
result_e_mail = re.match(pattern_e_mail, save_user_e_mail) # 校验邮箱格式
if save_username == "" or save_password == "":
tk.messagebox.showerror("错误", "用户名或密码不能为空")
elif not result_password:
tk.messagebox.showerror("错误", "请输入8到12位由数字、大小写字母构成的密码")
elif not result_e_mail:
tk.messagebox.showerror("错误", "请输入正确的电子邮箱")
elif save_password_confirm != save_password: # 密码两次输入结果一致性校验
tk.messagebox.showerror("错误", "密码前后不一致") # 上面这一堆不合规范的解释想必都看得懂,对于result_password以及result_e_mail,当校验成功时会返回True,反之则为False
else:
sql = "insert into user(user_name,user_password,user_e_mail,province_name,score)\
values('%s','%s','%s','%s',%d)"\
% (save_username, save_password, save_user_e_mail, save_province_name, save_score) # 校验完成,将信息写入数据库,%的用途大家应该看得懂
cursor.execute(sql) #执行上面的SQL语句
cursor.execute("select * from user") # 查询全部用户
list_sql2 = cursor.fetchall() # 获取全部用户
row_sql2 = len(list_sql2) # 统计的已注册用户列表的长度,从而获得已注册用户的数量
conn.commit()
conn.close()
tk.messagebox.showinfo("欢迎", "您是第%d位用户" % row_sql2) # 美好的提示,虽然没有实际用途
window_sign_up.destroy() # 关闭窗口
except py.err.IntegrityError:
tk.messagebox.showerror("错误", "用户名已存在或省份输入格式不正确") # 利用数据库主码特性(实体完整性原则)进行检查
except ValueError:
tk.messagebox.showerror("错误", "成绩应为数字") # 前面设置了int,防止输入一些乱七八糟的值
# 注册界面,以下的这些和前面初始界面搭建的结构是完全一样的逻辑
window_sign_up = tk.Toplevel(window)
window_sign_up.geometry("350x320")
window_sign_up.title("注册")
# 新建用户名
new_username = tk.StringVar()
tk.Label(window_sign_up, text="请输入用户名:").place(x=10, y=10)
tk.Entry(window_sign_up, textvariable=new_username).place(x=150, y=10)
# 新建密码
new_password = tk.StringVar()
tk.Label(window_sign_up, text="请输入8-12位包含\n大小写字母和数字的密码:").place(x=10, y=40)
tk.Entry(window_sign_up, textvariable=new_password, show="*").place(x=150, y=50)
# 再次输入密码
new_password_confirm = tk.StringVar()
tk.Label(window_sign_up, text="请再次输入密码:").place(x=10, y=90)
tk.Entry(window_sign_up, textvariable=new_password_confirm, show="*").place(x=150, y=90)
# 输入邮箱
user_e_mail = tk.StringVar()
tk.Label(window_sign_up, text="请输入邮箱:").place(x=10, y=130)
tk.Entry(window_sign_up, textvariable=user_e_mail).place(x=150, y=130)
# 输入省份
province_name = tk.StringVar()
tk.Label(window_sign_up, text="请输入省份:").place(x=10, y=170)
tk.Entry(window_sign_up, textvariable=province_name).place(x=150, y=170)
# 输入分数
score = tk.StringVar()
tk.Label(window_sign_up, text="请输入分数:").place(x=10, y=210)
tk.Entry(window_sign_up, textvariable=score).place(x=150, y=210)
# 确认注册按钮
confirm_sign_up = tk.Button(window_sign_up, text="注册", command=save_user)
confirm_sign_up.place(x=150, y=250)
# 退出的函数
def quit_windows():
window.destroy() # 关闭窗口
main() # 启动彩蛋函数
# 彩蛋函数三连(tree,petal,main),这段代码网上抄的,没啥意义,就是图一乐
def trees(branch_len, t):
time.sleep(0.000005)
if branch_len > 3:
if 8 <= branch_len <= 12:
if random.randint(0, 2) == 0:
t.color('snow')
else:
t.color('light coral')
t.pensize(branch_len / 3)
elif branch_len < 8:
if random.randint(0, 1) == 0:
t.color('snow')
else:
t.color('light coral')
t.pensize(branch_len / 2)
else:
t.color('sienna')
t.pensize(branch_len / 10)
t.forward(branch_len)
a = 1.5 * random.random()
t.right(20 * a)
b = 1.5 * random.random()
trees(branch_len - 10 * b, t)
t.left(40 * a)
trees(branch_len - 10 * b, t)
t.right(20 * a)
t.speed(100)
t.up()
t.backward(branch_len)
t.down()
def petal(m, t):
for i in range(m):
a = 200 - 400 * random.random()
b = 10 - 20 * random.random()
t.speed(100)
t.up()
t.forward(b)
t.left(90)
t.forward(a)
t.down()
t.color('light coral')
t.circle(1)
t.up()
t.backward(a)
t.right(90)
t.backward(b)
def main():
t = turtle.Turtle()
w = turtle.Screen()
t.hideturtle()
t.getscreen().tracer(5, 0)
w.screensize(canvwidth=1000, canvheight=1000, bg="wheat")
t.speed(100)
t.left(90)
t.up()
t.backward(150)
t.down()
t.color('sienna')
trees(60, t)
petal(200, t)
w.exitonclick()
# 使用手册界面函数
def for_users():
window_user_page = tk.Tk()
window_user_page.geometry("450x330")
window_user_page.title("使用指南")
tk.Label(window_user_page, text="1.使用前请现将随程序附带的数据库dbms_report安装至MySQL中并保持原名").place(x=0, y=0)
tk.Label(window_user_page, text="2.该系统默认的MySQL连接信息为IP:127.0.0.1,账户密码均为lzx,字符集为utf8").\
place(x=0, y=30)
tk.Label(window_user_page, text="2.本系统配置了查询、插入和修改数据三个主要功能,但未设置级联操作").place(x=0, y=60)
tk.Label(window_user_page, text="3.插入和删除均受到外键限制,为保护数据库,每次删除仅能删除一条至数条数据").place(x=0, y=90)
tk.Label(window_user_page, text="4.本系统基于DBMS MySQL搭建,使用MySQL自带的并发控制机制").place(x=0, y=120)
tk.Label(window_user_page, text="5.标注有“关键词”字样的输入框是查询所需的关键词,如果不予限制将输出整表").place(x=0, y=150)
tk.Label(window_user_page, text="6.本表支持模糊关键字查询,例如,输入“山”会返回山东省和山西省的数据").place(x=0, y=180)
tk.Label(window_user_page, text="7.当点击查询却无返回结果时,请检查您的关键词使用是否正确").place(x=0, y=210)
tk.Label(window_user_page, text="8.所有表格均支持不完全关键字查询").place(x=0, y=240)
tk.Label(window_user_page, text="9.图像显示可能不清晰,尤其是坐标轴,受制于matplotlib本身限制,暂时无法解决").place(x=0, y=270)
tk.Label(window_user_page, text="10.请勿删库,已备份,删库无用,删库封号").place(x=0, y=300)
# 主界面登录、注册、退出、使用指南按钮
login = tk.Button(window, text="登录", command=log_in) # command后面的函数就是点击这个键的时候要运行的函数
login.place(x=140, y=230)
logup = tk.Button(window, text="注册", command=sign_up)
logup.place(x=210, y=230)
logdown = tk.Button(window, text="退出", command=quit_windows)
logdown.place(x=280, y=230)
user_page = tk.Button(window, text="使用指南", command=for_users)
user_page.place(x=199, y=270)
# 功能、表格选择函数,还是和前面完全一样的逻辑,看懂前面的一样的逻辑,创建一个界面,在上面堆一堆按钮和提示文字之类的,这上面的command都对应了一个界面函数,前十个在以后会单独讲,最后一个就是下一部分要讲的数据导入界面
def choose():
window_choose = tk.Tk()
window_choose.title("表格选择")
window_choose.geometry("450x300")
tk.Label(window_choose, text="高校报考信息查询系统").place(x=160, y=0)
tk.Label(window_choose, text="请选择表格").place(x=190, y=20)
collage = tk.Button(window_choose, text="大学", command=collage_use)
collage.place(x=0, y=50)
province = tk.Button(window_choose, text="省份", command=province_use)
province.place(x=0, y=80)
student_num = tk.Button(window_choose, text="考生人数", command=student_num_use)
student_num.place(x=0, y=110)
min_score_line = tk.Button(window_choose, text="最低分数线", command=min_score_line_use)
min_score_line.place(x=0, y=140)
school_level = tk.Button(window_choose, text="学校等级", command=school_level_use)
school_level.place(x=0, y=170)
enrollment_type = tk.Button(window_choose, text="招生类型", command=enrollment_type_use)
enrollment_type.place(x=225, y=50)
enrollment = tk.Button(window_choose, text="招生人数", command=enrollment_use)
enrollment.place(x=225, y=80)
school_type = tk.Button(window_choose, text="学校类型", command=school_type_use)
school_type.place(x=225, y=110)
collage_school_level = tk.Button(window_choose, text="各高校等级", command=collage_school_level_use)
collage_school_level.place(x=225, y=140)
collage_province_enrollment_type = tk.Button(window_choose, text="各高校招生类型",
command=collage_province_enrollment_type_use)
collage_province_enrollment_type.place(x=225, y=170)
load_data = tk.Button(window_choose, text="导入数据", command=load_data_choose)
load_data.place(x=125, y=230) # 运行数据导入程序
# 返回函数,就是关闭窗口
def quit_window_choose():
window_choose.destroy()
quit_window_choose = tk.Button(window_choose, text="返回", command=quit_window_choose) # 返回键
quit_window_choose.place(x=280, y=230)
喜闻乐见的运行截图: