tkinter+sqlite3學生信息管理系統

剛寫完趁熱打鐵寫個博客記錄一下,初學很多東西不懂,也可能有錯誤的地方,僅是做個記錄。2020.6.19
之前寫了一部分2020.5.9然後做了別的事情

1 數據庫

1.1 用戶信息(pickle)

  • pickle的使用
  • 用戶信息存儲用到了pickle模板,在登錄時輸入用戶名和密碼(均不能爲空),從本地字典獲取用戶信息,判斷用戶名和密碼是否匹配,如果匹配進入學生信息管理界面,如果匹配且僅是密碼錯誤則重新輸入密碼,如果用戶名從未出現過,則提醒註冊。
  • 異常處理,從本地字典獲取用戶信息,如果沒有則新建本地數據庫。
    在這裏插入圖片描述
  • 註冊彈出子窗口,進行註冊時,本地加載已有用戶信息,如果沒有則已有用戶信息爲空。檢查用戶名是否存在、密碼是否爲空、密碼前後是否一致,註冊信息沒有問題則將用戶名密碼寫入數據庫,註冊成功關閉註冊框。
    在這裏插入圖片描述

1.2 學生信息數據庫創建(sqlite3)

  • 用到了sqlite數據庫,std_data.py文件爲用於數據庫創建的文件,創建數據庫名爲std_data.db,創建成功後創建student表,有七項:id,name,sex,age,job,std_id,tel,其中主鍵id自增,然後插入數據。
  • 以下是創建數據庫名爲std_data.db,創建表,表名爲student
  • 數據庫的創建參考教程
  • 增刪查改
import sqlite3
conn=sqlite3.connect("std_data.db")#打開或創建數據庫
c=conn.cursor()                 #獲取遊標
sql='''
    CREATE TABLE student
        (id INTEGER PRIMARY KEY ,
        name MESSAGE_TEXT ,
        sex MESSAGE_TEXT ,
        age NUMERIC ,
        job MESSAGE_TEXT ,
        std_id MESSAGE_TEXT ,
        tel MESSAGE_TEXT );
'''
c.execute(sql)                  #執行sql語句
conn.commit()                   #提交數據庫操作
conn.close()
print("ok")
  • 接下來插入數據
import sqlite3
conn=sqlite3.connect("std_data.db")#打開或創建數據庫
c=conn.cursor()                 #獲取遊標
sql1='''
   insert into student (name, sex, age, job, std_id, tel) 
   values('張三','女',32,'大數據',123456,123456)
'''
sql2='''
   insert into student (name, sex, age, job, std_id, tel) 
   values('李四','男',32,'物聯網',789456,789465)
'''
c.execute(sql1)                  #執行sql語句
c.execute(sql2)
conn.commit()                   #提交數據庫操作
conn.close()

在這裏插入圖片描述

2 界面設計

2.1 登錄界面

  • 登陸界面窗口大小爲300*180;標題爲登錄;兩行內容:用戶名和密碼;兩個按鈕:登錄和退出;佈局用到了grid佈局,username爲用戶輸入的用戶名,password爲用戶輸入的密碼;用tkinter.Label().grid(),tkinter.Entry().grid(),tkinter.Button().grid()放置文字,輸入框和按鈕,用tkinter.messagebox.showerror(title, message)顯示彈窗。
  • 如下爲登錄界面,本地已經存儲用戶名123,密碼123,可直接登錄;或隨意輸入用戶名和密碼,會自動提醒註冊。
    在這裏插入圖片描述
  • 代碼如下:
import tkinter.messagebox
from SignUp import *
from Manage import *

class Loginpage(object):
    def __init__(self, master=None):
        self.root = master
        self.root.geometry('%dx%d' % (300, 180))
        self.root.title('登錄')
        self.username = tkinter.StringVar()
        self.password = tkinter.StringVar()
        self.createPage()

    def createPage(self):

        self.page = tkinter.Frame(self.root)
        self.page.pack()
        tkinter.Label(self.page).grid(row=0, stick='W')
        tkinter.Label(self.page, text='賬戶: ').grid(row=1, stick='W', pady=10)
        tkinter.Entry(self.page, textvariable=self.username).grid(row=1, column=1, stick='E')
        tkinter.Label(self.page, text='密碼: ').grid(row=2, stick='W', pady=10)
        tkinter.Entry(self.page, textvariable=self.password, show='*').grid(row=2, column=1, stick='E')
        tkinter.Button(self.page, text='登陸', command=self.loginCheck).grid(row=3, stick='W', pady=10)
        tkinter.Button(self.page, text='退出', command=self.page.quit).grid(row=3, column=1, stick='E')

    def loginCheck(self):
        name = self.username.get()
        secret = self.password.get()

        try:
            with open('usr_info.pickle', 'rb') as usr_file:
                usrs_info = pickle.load(usr_file)
        except FileNotFoundError:
            with open('usr_info.pickle', 'wb') as usr_file:
                usrs_info = {'admin': 'admin'}
                pickle.dump(usrs_info, usr_file)

        if name in usrs_info:
            if secret == usrs_info[name]:
                tkinter.messagebox.showinfo(title='welcome', message='歡迎您:' + name)
                for widget in self.page.winfo_children():
                    widget.destroy()
                usr_file.close()

                self.page.destroy()
                Manage_student(self.root)
            else:
                tkinter.messagebox.showerror(message='密碼錯誤')

        elif name == '' or secret == '':
            tkinter.messagebox.showerror(message='用戶名或密碼爲空')

        else:
            is_signup = tkinter.messagebox.askyesno('歡迎', '您還沒有註冊,是否現在註冊')
            if is_signup:
                Signuppage(self.root)

2.2 註冊界面

  • 用tkinter.Toplevel(root)創建子窗口,子窗口大小爲350*200;子窗口名爲註冊;三行內容:用戶名、密碼和再次輸入密碼;一個按鈕:確認註冊按鈕;用tkinter.Label().place(),tkinter.Entry().place(),tkinter.Button().place()放置文字,輸入框和按鈕,用tkinter.messagebox.showerror(title, message)顯示彈窗。
  • new_name爲用戶輸入的用戶名,new_pwd爲用戶輸入的祕密,new_pwd_confirm爲用戶輸入的再次確認祕密,註冊信息沒有問題則將用戶名密碼寫入數據庫。
    在這裏插入圖片描述
  • 代碼如下:
import tkinter
import tkinter.messagebox
import pickle

def Signuppage(root):

    def signtowcg():

        nn = new_name.get()
        np = new_pwd.get()
        npf = new_pwd_confirm.get()

        try:
            with open('usr_info.pickle', 'rb') as usr_file:
                exist_usr_info = pickle.load(usr_file)
        except FileNotFoundError:
            exist_usr_info = {}

        if nn in exist_usr_info:
            tkinter.messagebox.showerror('錯誤', '用戶名已存在')
        elif np == '' or nn == '':
            tkinter.messagebox.showerror('錯誤', '用戶名或密碼爲空')
        elif np != npf:
            tkinter.messagebox.showerror('錯誤', '密碼前後不一致')

        else:
            exist_usr_info[nn] = np
            with open('usr_info.pickle', 'wb') as usr_file:
                pickle.dump(exist_usr_info, usr_file)
            tkinter.messagebox.showinfo('歡迎', '註冊成功')
            window_sign_up.destroy()

    window_sign_up = tkinter.Toplevel(root)
    window_sign_up.geometry('350x200')
    window_sign_up.title('註冊')

    new_name = tkinter.StringVar()
    tkinter.Label(window_sign_up, text='用戶名:').place(x=10, y=10)
    tkinter.Entry(window_sign_up, textvariable=new_name).place(x=150, y=10)

    new_pwd = tkinter.StringVar()
    tkinter.Label(window_sign_up, text='請輸入密碼:').place(x=10, y=50)
    tkinter.Entry(window_sign_up, textvariable=new_pwd, show='*').place(x=150, y=50)

    new_pwd_confirm = tkinter.StringVar()
    tkinter.Label(window_sign_up, text='請再次輸入密碼:').place(x=10, y=90)
    tkinter.Entry(window_sign_up, textvariable=new_pwd_confirm, show='*').place(x=150, y=90)

    tkinter.Button(window_sign_up, text='確認註冊', command=signtowcg).place(x=150, y=130)

2.3 學生信息管理界面

  • 學生信息管理界面,標題爲學生管理系統,通過設定root.resizable(False, False)使得窗口大小不能改變,用tkinter.Label().place(),tkinter.Entry().place(),tkinter.Button().place()放置文字,輸入框和按鈕,用tkinter.messagebox.showerror(title, message)顯示彈窗。
  • 在窗口上放置用來顯示學生信息的表格,使用Treeview組件實現,滾動條位於右側,設置了六列,顯示學生信息分別是:姓名、性別、年齡、專業、學號、電話,最後將Treeview組件與垂直滾動條結合,定義Treeview組件的左鍵單擊事件,並綁定到Treeview組件上,單擊鼠標左鍵,設置變量nameToDelete的值,然後可以使用“刪除”按鈕來刪除。
    在這裏插入圖片描述

3 數據處理

  • 設定doSql函數進行基本的數據庫操作,傳入sql語句即可執行。
  • 在查找和修改中都用到了id,但是無法確定id的值,所以依據name,在數據庫中匹配。

3.1 查找

  • 通過輸入姓名的查找方式,name = entry_name.get().strip(),name爲獲取姓名輸入框內容,name爲空,則不能進行查找,如果不爲空,打開std_data數據庫,執行sql語句select id,name,sex,age,job,std_id,tel from student,進行查詢,如果姓名匹配,則講查詢結果返回到輸入框,即在輸入框顯示查詢到的內容,最後關閉數據庫。
        name = entry_name.get().strip()
        if name == '':
            tkinter.messagebox.showerror(title='很抱歉', message='查詢時名字不能爲空')
            return
        conn = sqlite3.connect("std_data.db")
        c = conn.cursor()
        sql1 = '''
           SELECT id,name,sex,age,job,std_id,tel FROM student
        '''
        cursor = c.execute(sql1)
        for row in cursor:
            if row[1] == name:
                entry_name.set(row[1])
                comboSex.set(row[2])
                entry_age.set(row[3])
                entry_job.set(row[4])
                entry_stdid.set(row[5])
                entry_tel.set(row[6])
        conn.close()

3.2 增加

  • 獲取輸入框的所有內容進行添加信息。對信息進行檢查,輸入的姓名不能爲空且不能與數據庫中已有信息姓名重複,SELECT COUNT(id) FROM student WHERE name="’ + name + '",執行語句記錄數據庫中name出現的次數,用於判斷姓名是否重複;對輸入的年齡信息進行檢查,年齡必須爲數字且在1~100之間;檢查輸入的專業不能爲空;檢查輸入的學號不能爲空且必須爲數字;檢查輸入的電話不能爲空且必須爲數字。所有信息都檢查通過的話,插入數據庫,執行語句INSERT INTO student() VALUES(),更新信息並且把顯示的信息表更新。
    def buttonAddClick():
        name = entry_name.get().strip()
        if name == '':
            tkinter.messagebox.showerror(title='很抱歉', message='必須輸入姓名')
            return
        conn = sqlite3.connect('std_data.db')
        cur = conn.cursor()
        cur.execute('SELECT COUNT(id) FROM student WHERE name="' + name + '"')
        c = cur.fetchone()[0]
        conn.close()
        if c != 0:
            tkinter.messagebox.showerror(title='很抱歉', message='姓名不能重複')
            return

        sex = comboSex.get()

        age = entry_age.get().strip()
        if not age.isdigit():
            tkinter.messagebox.showerror(title='很抱歉', message='年齡必須爲數字')
            return
        if not 1 < int(age) < 100:
            tkinter.messagebox.showerror(title='很抱歉', message='年齡必須在1到100之間')
            return

        department = entry_job.get().strip()
        if department == '':
            tkinter.messagebox.showerror(title='很抱歉', message='必須輸入專業')
            return

        std_id = entry_stdid.get().strip()
        if std_id == '' or (not std_id.isdigit()):
            tkinter.messagebox.showerror(title='很抱歉', message='學號必須是數字')
            return

        telephone = entry_tel.get().strip()
        if telephone == '' or (not telephone.isdigit()):
            tkinter.messagebox.showerror(title='很抱歉', message='電話號碼必須是數字')
            return

        sql = 'INSERT INTO student(name,sex,age,job,std_id,tel) VALUES("'
        sql += name + '","' + sex + '",' + age + ',"' + department + '","'
        sql += std_id + '","' + telephone + '")'

        doSql(sql)
        bindData()

3.3 刪除

  • 通過點擊信息表姓名獲取需要刪除的姓名,姓名不可以爲空,選中後執行sql語句DELETE FROM student where name="’ + name + ‘",顯示彈窗刪除成功,更新信息並且把顯示的信息表更新,nameToDelete.set(’’)重置爲空。
    def buttonDeleteClick():
        name = nameToDelete.get()
        if name == '':
            tkinter.messagebox.showerror(title='很抱歉', message='請選擇一條記錄')
            return

        sql = 'DELETE FROM student WHERE name="' + name + '"'
        doSql(sql)
        tkinter.messagebox.showinfo('恭喜', '刪除成功')
        nameToDelete.set('')
        bindData()

3.4 修改

  • 修改信息只有姓名不可以修改,除姓名外的修改信息填入對應的輸入框,點擊修改即可修改。re_sex、re_age、re_job、re_stdid、re_tel分別對應修改的性別、年齡、工作、學號、電話,執行sql語句UPDATE student SET sex = ‘%s’ WHERE id = ‘%s’" %(re_sex, id_row),更新語句每句更改信息最多2處,所以每句只更改1處。
  • 同增加項一樣進行信息檢查。
    def buttonReviseClick():
        name = entry_name.get().strip()
        re_sex = comboSex.get().strip()
        re_age = entry_age.get().strip()
        re_job = entry_job.get().strip()
        re_stdid = entry_stdid.get().strip()
        re_tel = entry_tel.get().strip()

        if name == '':
            tkinter.messagebox.showerror(title='很抱歉', message='必須輸入姓名')
            return

        if not re_age.isdigit():
            tkinter.messagebox.showerror(title='很抱歉', message='年齡必須爲數字')
            return
        if not 1 < int(re_age) < 100:
            tkinter.messagebox.showerror(title='很抱歉', message='年齡必須在1到100之間')
            return

        if re_job == '':
            tkinter.messagebox.showerror(title='很抱歉', message='必須輸入專業')
            return

        if re_stdid == '' or (not re_stdid.isdigit()):
            tkinter.messagebox.showerror(title='很抱歉', message='學號必須是數字')
            return

        if re_tel == '' or (not re_tel.isdigit()):
            tkinter.messagebox.showerror(title='很抱歉', message='電話號碼必須是數字')
            return
        conn = sqlite3.connect("std_data.db")
        c = conn.cursor()
        sql1 = '''
                   SELECT id,name,sex,age,job,std_id,tel FROM student
                '''
        cursor = c.execute(sql1)
        for row in cursor:
            if row[1] == name:
                id_row = row[0]
                if re_sex != row[2] :
                    c.execute("UPDATE student SET sex = '%s'  WHERE id = '%s'"
                              %(re_sex, id_row))
                if re_age != row[3] :
                    c.execute("UPDATE student SET age = '%s'  WHERE id = '%s'"
                              % (re_age, id_row))
                if re_job != row[4] :
                    c.execute("UPDATE student SET job = '%s'  WHERE id = '%s'"
                              % (re_job, id_row))
                if re_stdid != row[5] :
                    c.execute("UPDATE student SET std_id = '%s'  WHERE id = '%s'"
                              % (re_stdid, id_row))
                if re_tel != row[6] :
                    c.execute("UPDATE student SET tel = '%s'  WHERE id = '%s'"
                              % (re_tel, id_row))
        conn.commit()
        conn.close()

        tkinter.messagebox.showinfo('恭喜', '修改成功')
        bindData()

4 心得

  • 完成項目過程中,遇到困難在CSDN博客中都得到了解決。Tkinter模塊在課堂上講過,動手實踐後理解更加透徹。在這次學生信息管理系統設計的過程中,我熟練使用tkinter創建窗口,設置窗口標題,窗口大小等,學會grid佈局和通過place設置放置位置,在實現GUI中發揮很大作用。
  • 課堂上講過數據庫的操作,實踐後理解更加深刻,自己創建了數據庫,創建過程在std_data.py文件中,增刪查改,INSERT INTO,DELETE,SELECT,UPDATE語句的使用。
  • 很感謝老師提供的學生信息管理系統設計這一機會,有這麼一次實踐的經歷,感覺還是很不錯的。因爲我們不只是學到了python的基礎知識,還應該學會如何用模塊實現想要的結果,這提升了許多方面的能力。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章