diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..35410ca
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# 默认忽略的文件
+/shelf/
+/workspace.xml
+# 基于编辑器的 HTTP 客户端请求
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/Courseselection.iml b/.idea/Courseselection.iml
new file mode 100644
index 0000000..d0876a7
--- /dev/null
+++ b/.idea/Courseselection.iml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..1477c4b
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..90eedc6
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/student.py b/student.py
new file mode 100644
index 0000000..8f30283
--- /dev/null
+++ b/student.py
@@ -0,0 +1,454 @@
+import tkinter
+from tkinter import ttk
+import pymysql
+from utils import *
+
+RADIO = 0.1
+WINDOW_SIZE = '800x500+200+100'
+TEXT_INDENT = 60
+TEXT_LINE_SPACE = 30
+
+class menu:
+ def __init__(self, StudentNum):
+ self.studentNum = StudentNum
+ self.root = tkinter.Tk()
+ self.root.geometry(WINDOW_SIZE)
+ self.root.title('学生')
+ self.root.resizable(False, False)
+ # 子区域
+ self.info = tkinter.Frame(self.root)
+ self.choose = tkinter.Frame(self.root)
+ self.drop = tkinter.Frame(self.root)
+ self.grade = tkinter.Frame(self.root)
+ # 菜单栏
+ self.menu = tkinter.Frame(self.root)
+ self.stu_info = tkinter.Button(self.menu, text='个人信息', command=self.stu_info)
+ self.stu_choose = tkinter.Button(self.menu, text='选课', command=self.stu_choose)
+ self.stu_drop = tkinter.Button(self.menu, text='退课', command=self.stu_drop)
+ self.stu_grade = tkinter.Button(self.menu, text='课程成绩', command=self.stu_grade)
+ # 控件布局
+ self.initialize()
+
+ def initialize(self):
+ self.menu.place(relheight=1, relwidth=RADIO)
+ self.stu_info.place(rely=0.0, relheight=0.25, relwidth=1)
+ self.stu_choose.place(rely=0.25, relheight=0.25, relwidth=1)
+ self.stu_drop.place(rely=0.5, relheight=0.25, relwidth=1)
+ self.stu_grade.place(rely=0.75, relheight=0.25, relwidth=1)
+
+ def stu_info(self):
+ self.info.place_forget()
+ self.choose.place_forget()
+ self.drop.place_forget()
+ self.grade.place_forget()
+ stuInfo(self.info, self.studentNum)
+
+ def stu_choose(self):
+ self.info.place_forget()
+ self.choose.place_forget()
+ self.drop.place_forget()
+ self.grade.place_forget()
+ stuChoose(self.choose, self.studentNum)
+
+ def stu_drop(self):
+ self.info.place_forget()
+ self.choose.place_forget()
+ self.drop.place_forget()
+ self.grade.place_forget()
+ stuDrop(self.drop, self.studentNum)
+
+ def stu_grade(self):
+ self.info.place_forget()
+ self.choose.place_forget()
+ self.drop.place_forget()
+ self.grade.place_forget()
+ stuGrade(self.grade, self.studentNum)
+
+ # 启动窗口
+ def start(self):
+ self.root.mainloop()
+
+# 个人信息区域
+class stuInfo:
+ def __init__(self, frame, studentNum):
+ self.frame = frame
+ self.studentNum = studentNum
+ # 个人信息
+ self.numLabel = tkinter.Label(self.frame, text='学号:')
+ self.nameLabel = tkinter.Label(self.frame, text='姓名:')
+ self.sexLabel = tkinter.Label(self.frame, text='性别:')
+ self.ageLabel = tkinter.Label(self.frame, text='年龄:')
+ self.pswdLabel = tkinter.Label(self.frame, text='密码:')
+ # 个人信息显示
+ self.num_Label = tkinter.Label(self.frame)
+ self.name_Label = tkinter.Label(self.frame)
+ self.sex_Label = tkinter.Label(self.frame)
+ self.age_Label = tkinter.Label(self.frame)
+ self.pswdVar = tkinter.StringVar()
+ self.pswd_Entry = tkinter.Entry(self.frame, textvariable=self.pswdVar)
+ # 修改密码
+ self.commitButton = tkinter.Button(self.frame, text='修改密码')
+ # 规则提示,修改密码提示信息是同一个标签
+ self.promptLabel = tkinter.Label(self.frame, text='密码不少于6位, 不能与原密码相同', font=("TkDefaultFont", 8))
+ # 控件布局
+ self.initialize()
+
+ def initialize(self):
+ self.frame.place(relx=RADIO, relheight=1, relwidth=1-RADIO)
+ # 放置不变的组件
+ self.numLabel.place(x=TEXT_INDENT, y=TEXT_LINE_SPACE * 0, anchor='ne')
+ self.nameLabel.place(x=TEXT_INDENT, y=TEXT_LINE_SPACE * 1, anchor='ne')
+ self.sexLabel.place(x=TEXT_INDENT, y=TEXT_LINE_SPACE * 2, anchor='ne')
+ self.ageLabel.place(x=TEXT_INDENT, y=TEXT_LINE_SPACE * 3, anchor='ne')
+ self.pswdLabel.place(x=TEXT_INDENT, y=TEXT_LINE_SPACE * 4, anchor='ne')
+ # 获取信息
+ info = self.get_student_info(self.studentNum)[0]
+ # 设置要显示的信息,及修改密码的函数
+ self.num_Label.configure(text=info[0])
+ self.name_Label.configure(text=info[1])
+ self.sex_Label.configure(text=info[2])
+ self.age_Label.configure(text=info[3])
+ self.pswd_Entry.insert(tkinter.INSERT, info[4])
+ self.commitButton.configure(command=lambda :self.change_pswd(info[4], self.pswd_Entry.get()))
+ # 放置组件,显示信息
+ self.num_Label.place(x=TEXT_INDENT, y=TEXT_LINE_SPACE * 0)
+ self.name_Label.place(x=TEXT_INDENT, y=TEXT_LINE_SPACE * 1)
+ self.sex_Label.place(x=TEXT_INDENT, y=TEXT_LINE_SPACE * 2)
+ self.age_Label.place(x=TEXT_INDENT, y=TEXT_LINE_SPACE * 3)
+ self.pswd_Entry.place(x=TEXT_INDENT, y=TEXT_LINE_SPACE * 4)
+ # 放置修改密码按钮,和密码提示
+ self.frame.update()
+ self.promptLabel.place(x=self.pswd_Entry.winfo_x(), y=self.pswd_Entry.winfo_y() + self.pswd_Entry.winfo_height() + 5)
+ self.commitButton.place(x=self.pswd_Entry.winfo_x() + self.pswd_Entry.winfo_width() + 5, y=self.pswd_Entry.winfo_y() - 5)
+
+ def change_pswd(self, origPswd, pswd):
+ pswd = pswd.strip()
+ if pswd == origPswd:
+ self.promptLabel.configure(text='密码不能与原密码相同!')
+ return
+ elif len(pswd) < 6:
+ self.promptLabel.configure(text='密码不能小于六位!')
+ return
+ else:
+ self.promptLabel.configure(text='密码修改成功!')
+ self.set_student_pswd(pswd)
+ return
+
+ def get_student_info(self, studentID):
+ db = connect()
+ cursor = db.cursor()
+ sql = f'select distinct * from tb_student where studentID = \'{studentID}\''
+ cursor.execute(sql)
+ result = cursor.fetchall()
+ db.close()
+ return result
+
+ def set_student_pswd(self, pswd):
+ db = connect()
+ cursor = db.cursor()
+ sql = f'UPDATE tb_student SET studentPswd= \'{pswd}\' WHERE studentID = \'{self.studentNum}\''
+ cursor.execute(sql)
+ try:
+ db.commit()
+ except Exception as e:
+ db.rollback()
+ db.close()
+
+# 选课区域
+class stuChoose:
+ def __init__(self, frame, studentNum):
+ self.frame = frame
+ self.studentNum = studentNum
+ # 信息放置处, 滚动条
+ self.resultScrollbar = tkinter.Scrollbar(self.frame)
+ self.resultTable = ttk.Treeview(self.frame,
+ height=10,
+ columns=['课程号', '课程名', '课序号', '学分'],
+ show='headings',
+ yscrollcommand=self.resultScrollbar.set)
+ # 选课按钮
+ self.chooseButton = tkinter.Button(self.frame, text='选课', command=self.chooseCourse)
+ # 提示信息
+ self.promptLabel = tkinter.Label(self.frame, text='一次选一门课,已选的课不出现在列表里')
+ # 选中的课程
+ self.selected = None
+
+ self.initialize()
+
+ # frame和button的布局
+ def initialize(self):
+ self.frame.place(relx=RADIO, relheight=1, relwidth=1-RADIO)
+ # 放置组件
+ self.frame.update()
+ self.frame.update()
+ self.resultTable.place(height=self.frame.winfo_height(),
+ relwidth=0.6)
+ self.frame.update()
+ self.promptLabel.place(x=self.resultTable.winfo_x() + self.resultTable.winfo_width() + 5,
+ y=self.resultTable.winfo_y() + self.resultTable.winfo_height(), anchor='sw')
+ self.chooseButton.place(x=self.resultTable.winfo_x() + self.resultTable.winfo_width() + 5,
+ y=self.resultTable.winfo_y() + self.resultTable.winfo_height() - 30, anchor='sw')
+
+ self.displayInfo()
+
+ # 显示选课信息
+ def displayInfo(self):
+ self.clear_course_info()
+ self.resultTable.heading('课程号', text='课程号', anchor='w')
+ self.resultTable.heading('课程名', text='课程名')
+ self.resultTable.heading('课序号', text='课序号')
+ self.resultTable.heading('学分', text='学分')
+
+ self.resultTable.column('课程号', width=100, minwidth=100)
+ self.resultTable.column('课程名', width=150, minwidth=150)
+ self.resultTable.column('课序号', width=50, minwidth=50)
+ self.resultTable.column('学分', width=100, minwidth=100)
+
+ info_valid = self.get_class_optional()
+ for x in info_valid:
+ self.resultTable.insert('', tkinter.END, values=x)
+
+ # print('以下是暂未安排老师的课程,不支持选择')
+ # info_invalid = self.get_invalid_class_optional()
+ # for x in info_invalid:
+ # self.resultTable.insert('', tkinter.END, values=x)
+
+ self.resultTable.bind('', self.get_selected_item)
+
+ # 选课按钮
+ def chooseCourse(self):
+ if self.selected is None:
+ self.promptLabel.configure(text='还未选择课程!')
+ else:
+ if self.insert_student_course(self.studentNum, self.selected['values'][0], self.selected['values'][2]) == 0:
+ self.promptLabel.configure(text='选课成功!')
+ else:
+ self.promptLabel.configure(text='选课失败!')
+ # 选课完成后更新选课列表
+ self.displayInfo()
+
+ # 获得选中课程信息
+ def get_selected_item(self, event):
+ curItem = self.resultTable.focus()
+ self.selected = self.resultTable.item(curItem)
+ print(self.selected)
+
+ # 获取有效选课信息
+ def get_class_optional(self):
+ db = connect()
+ cursor = db.cursor()
+ sql = f'select C.courseID, C.courseName, C.courseNum, C.courseCredit ' \
+ f'from tb_course as C, tb_teacher_course as TC ' \
+ f'where C.courseID = TC.courseID and C.courseNum = TC.courseNum ' \
+ f'and C.courseID not in (select courseID from tb_student_course where studentID = \'{self.studentNum}\')'
+ cursor.execute(sql)
+ result = cursor.fetchall()
+ db.close()
+ return result
+
+ # 获取无效选课信息(没有分配老师的课程)
+ def get_invalid_class_optional(self):
+ db = connect()
+ cursor = db.cursor()
+ sql = f'select C.courseID, C.courseName, C.courseNum, C.courseCredit ' \
+ f'from tb_course as C ' \
+ f'where C.courseID not in \
+ (select C.courseID \
+ from tb_course as C, tb_teacher_course as TC, tb_student_course as SC \
+ where C.courseID = TC.courseID and C.courseNum = TC.courseNum and SC.studentID = \'{self.studentNum}\') '
+ cursor.execute(sql)
+ result = cursor.fetchall()
+ db.close()
+ return result
+
+ # 选课信息提交
+ def insert_student_course(self, studentID, courseID, courseNum):
+ db = connect()
+ cursor = db.cursor()
+ sql = f'INSERT INTO tb_student_course (studentID, courseID, courseNum, grade) VALUES (\'{studentID}\', \'{courseID}\', \'{courseNum}\', -1)'
+ cursor.execute(sql)
+ try:
+ db.commit()
+ db.close()
+ return 0
+ except:
+ db.rollback()
+ db.close()
+ return 1
+
+ # 选课信息清除
+ def clear_course_info(self):
+ for x in self.resultTable.get_children():
+ self.resultTable.delete(x)
+
+# 退课区域
+class stuDrop:
+ def __init__(self, frame, studentNum):
+ self.studentNum = studentNum
+ self.frame = frame
+ # 信息放置处, 滚动条
+ self.resultScrollbar = tkinter.Scrollbar(self.frame)
+ self.resultTable = ttk.Treeview(self.frame,
+ height=10,
+ columns=['课程号', '课程名', '课序号', '学分'],
+ show='headings',
+ yscrollcommand=self.resultScrollbar.set)
+ # 退课按钮
+ self.dropButton = tkinter.Button(self.frame, text='退课', command=self.dropCourse)
+ # 提示信息
+ self.promptLabel = tkinter.Label(self.frame, text='一次退一门课,已退的课不出现在列表里')
+ # 选中的课程
+ self.selected = None
+
+ self.initialize()
+
+ def initialize(self):
+ self.frame.place(relx=RADIO, relheight=1, relwidth=1-RADIO)
+ # 放置组件
+ # self.frame.update()
+ self.frame.update()
+ self.resultTable.place(height=self.frame.winfo_height(),
+ relwidth=0.6)
+ self.frame.update()
+ self.promptLabel.place(x=self.resultTable.winfo_x() + self.resultTable.winfo_width() + 5,
+ y=self.resultTable.winfo_y() + self.resultTable.winfo_height(), anchor='sw')
+ self.dropButton.place(x=self.resultTable.winfo_x() + self.resultTable.winfo_width() + 5,
+ y=self.resultTable.winfo_y() + self.resultTable.winfo_height() - 30, anchor='sw')
+
+ self.displayInfo()
+
+ # 显示选课信息
+ def displayInfo(self):
+ self.clear_course_info()
+ self.resultTable.heading('课程号', text='课程号', anchor='w')
+ self.resultTable.heading('课程名', text='课程名')
+ self.resultTable.heading('课序号', text='课序号')
+ self.resultTable.heading('学分', text='学分')
+
+ self.resultTable.column('课程号', width=50, minwidth=50)
+ self.resultTable.column('课程名', width=120, minwidth=120)
+ self.resultTable.column('课序号', width=50, minwidth=50)
+ self.resultTable.column('学分', width=50, minwidth=50)
+ info = self.get_class_optional()
+ for x in info:
+ self.resultTable.insert('', tkinter.END, values=x)
+
+ self.resultTable.bind('', self.get_selected_item)
+
+ # 退课按钮
+ def dropCourse(self):
+ if self.selected is None:
+ self.promptLabel.configure(text='还未选择课程!')
+ else:
+ if self.drop_student_course(self.studentNum, self.selected['values'][0], self.selected['values'][2]) == 0:
+ self.promptLabel.configure(text='退课成功!')
+ else:
+ self.promptLabel.configure(text='退课失败!')
+ # 选课完成后更新选课列表
+ self.displayInfo()
+
+ # 获得选中课程信息
+ def get_selected_item(self, event):
+ curItem = self.resultTable.focus()
+ self.selected = self.resultTable.item(curItem)
+ print(self.selected)
+
+ # 获取已选信息
+ def get_class_optional(self):
+ db = connect()
+ cursor = db.cursor()
+ sql = f'select C.courseID, C.courseName, C.courseNum, C.courseCredit ' \
+ f'from tb_course as C, tb_student_course as SC ' \
+ f'where SC.studentID = \'{self.studentNum}\' and C.courseID = SC.courseID and C.courseNum = SC.courseNum'
+ cursor.execute(sql)
+ result = cursor.fetchall()
+ db.close()
+ return result
+
+ # 退课信息提交
+ def drop_student_course(self, studentID, courseID, courseNum):
+ db = connect()
+ cursor = db.cursor()
+ sql = f'DELETE FROM tb_student_course WHERE studentID = \'{studentID}\' ' \
+ f'and courseID = \'{courseID}\' and courseNum = \'{courseNum}\''
+ cursor.execute(sql)
+ try:
+ db.commit()
+ db.close()
+ return 0
+ except:
+ db.rollback()
+ db.close()
+ return 1
+
+ # 课程信息清除
+ def clear_course_info(self):
+ for x in self.resultTable.get_children():
+ self.resultTable.delete(x)
+
+# 课程成绩区域
+class stuGrade:
+ def __init__(self, frame, studentNum):
+ self.studentNum = studentNum
+ self.frame = frame
+ # 信息放置处, 滚动条
+ self.resultScrollbar = tkinter.Scrollbar(self.frame)
+ self.resultTable = ttk.Treeview(self.frame,
+ height=10,
+ columns=['课程号', '课程名', '课序号', '教师', '学分', '成绩'],
+ show='headings',
+ yscrollcommand=self.resultScrollbar.set)
+
+ self.initialize()
+
+ def initialize(self):
+ self.frame.place(relx=RADIO, relheight=1, relwidth=1-RADIO)
+ # 放置组件
+ self.frame.update()
+ self.frame.update()
+ self.resultTable.place(height=self.frame.winfo_height(),
+ relwidth=0.8)
+
+ self.displayInfo()
+
+ # 显示选课信息
+ def displayInfo(self):
+ self.clear_course_info()
+ self.resultTable.heading('课程号', text='课程号', anchor='w')
+ self.resultTable.heading('课程名', text='课程名')
+ self.resultTable.heading('课序号', text='课序号')
+ self.resultTable.heading('教师', text='教师')
+ self.resultTable.heading('学分', text='学分')
+ self.resultTable.heading('成绩', text='成绩')
+
+ self.resultTable.column('课程号', width=50, minwidth=50)
+ self.resultTable.column('课程名', width=120, minwidth=120)
+ self.resultTable.column('课序号', width=50, minwidth=50)
+ self.resultTable.column('教师', width=50, minwidth=50)
+ self.resultTable.column('学分', width=50, minwidth=50)
+ self.resultTable.column('成绩', width=50, minwidth=50)
+
+ info = self.get_class_selected()
+ for x in info:
+ self.resultTable.insert('', tkinter.END, values=x)
+
+ # 获取已选课程
+ def get_class_selected(self):
+ db = connect()
+ cursor = db.cursor()
+ sql = f'select SC.courseID, C.courseName, SC.courseNum, T.teacherName, C.courseCredit, SC.grade ' \
+ f'from tb_student_course as SC, tb_teacher as T, tb_teacher_course as TC, tb_course as C ' \
+ f'where SC.studentID = \'{self.studentNum}\' and SC.courseNum = C.courseNum and SC.courseID = C.courseID ' \
+ 'and T.teacherID = TC.teacherID and TC.courseID = C.courseID and TC.courseNum = C.courseNum'
+ cursor.execute(sql)
+ result = cursor.fetchall()
+ db.close()
+ return result
+
+ def clear_course_info(self):
+ for x in self.resultTable.get_children():
+ self.resultTable.delete(x)
+
+if __name__ == '__main__':
+ c = menu('202101')
+ c.start()