計算機軟體實習專案四 —— 校園一卡通管理系統 (程式碼實現) 12-27

Upapa發表於2020-12-27

程式碼實現(校園一卡通管理系統)

  這個專案依舊選擇用Python+PyQt5來進行開發,資料庫部分則選擇使用mysql。

  我主要負責實現主視窗部分的學生基本資訊欄和交易記錄欄的增刪改查、批量插入、批量刪除等功能,同時負責部分UI介面的製作以及後端mysql資料庫互動方法的編寫等。

一、主函式(main.py)

  主函式用來建立各個視窗,並且建立各個視窗之間的關係。

from PyQt5.QtWidgets import QApplication

from BatchInsertedWindow import BatchInsertedWindow
from ForgetWindow import ResetWindow, SecurityQuestionWindow
from LoginWindow import LoginWindow
from MainWindow import MainWindow
from InsertWindow import InsertWindow
import sys

if __name__ == "__main__":
    app = QApplication(sys.argv)

    login_widget = LoginWindow()  # 視窗控制元件
    login_widget.show()

    main_widget = MainWindow()  # 視窗控制元件
    forget_widget = SecurityQuestionWindow()  # 密保視窗
    reset_widget = ResetWindow()  # 重置密碼視窗
    insert_widget = InsertWindow()  # 視窗控制元件
    batch_insert_widget = BatchInsertedWindow()  # 批量插入視窗

    login_widget.signal.connect(main_widget.show)  # 連線槽函式
    login_widget.forget_signal.connect(forget_widget.show)  # 顯示忘記密碼視窗
    forget_widget.signal.connect(reset_widget.show)  # 顯示重置密碼視窗
    forget_widget.back_signal.connect(login_widget.show)  # 顯示登入視窗
    reset_widget.signal.connect(login_widget.show)  # 回到登入視窗
    reset_widget.back_signal.connect(login_widget.show)  # 回到登入視窗
    main_widget.batch_signal.connect(batch_insert_widget.show)  # 顯示批量插入視窗

    main_widget.insert_signal.connect(insert_widget.show)  # 連線槽函式
    insert_widget.inserted_signal.connect(main_widget.query)  # 更新資料

    sys.exit(app.exec_())

二、登入視窗(LoginWindow.py)

  登入視窗負責使用者身份驗證,以及彈出忘記密碼視窗等功能。

from PyQt5 import QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import ctypes
from PyQt5.QtWidgets import QMainWindow, QLineEdit, QMessageBox, QWidget

from Functions import load
from Login_UI import Ui_LoginWindow


class LoginWindow(QtWidgets.QMainWindow, Ui_LoginWindow):
    signal = pyqtSignal()
    forget_signal = pyqtSignal()

    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.setWindowTitle('校園一卡通管理系統登入')  # 設定視窗標題
        self.setWindowIcon(QIcon('logo.png'))  # 設定視窗圖示
        # self.setStyleSheet('QWidget{background-color:%s}' % QColor(222, 222, 222).name())  # 設定視窗背景色
        self.setWindowOpacity(0.95)  # 設定整個計算器視窗的透明度
        ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("myappid")  # 工作列圖示
        self.setWindowFlags(Qt.FramelessWindowHint)
        self.show()

        self.set_input()  # 輸入賬號和輸入密碼的設定

        # 將訊號連線到對應槽函式
        self.login_button.clicked.connect(self.username_password)
        self.forget.clicked.connect(self.forget_password)
        self.login_close.clicked.connect(QCoreApplication.instance().quit)

    # 輸入賬號和輸入密碼的設定
    def set_input(self):
        self.input_username.setPlaceholderText("請輸入賬號")  # 灰色的佔位符
        self.input_password.setPlaceholderText("請輸入密碼")  # 灰色的佔位符
        self.input_username.setContextMenuPolicy(Qt.NoContextMenu)  # 禁止複製貼上
        self.input_password.setContextMenuPolicy(Qt.NoContextMenu)  # 禁止複製貼上
        self.input_password.setEchoMode(QLineEdit.Password)  # 輸入時呈現圓點,不顯示密碼

    # 檢查使用者名稱與密碼是否匹配
    def username_password(self):
        if load(self.input_username.text(), self.input_password.text()):
            self.hide()
            self.signal.emit()  # 發射訊號
        else:
            QMessageBox.warning(self, "錯誤", "賬號或密碼錯誤!")
            self.input_password.setText('')
        pass

    # 忘記密碼按鈕觸發的訊號
    def forget_password(self):
        self.hide()
        self.forget_signal.emit()  # 發射忘記密碼訊號

    # 鍵盤登入
    def keyPressEvent(self, event):
        QWidget.keyPressEvent(self, event)
        key = event.key()
        if key == Qt.Key_Enter:
            self.username_password()

三、忘記密碼視窗(ForgetWindow.py)

  忘記密碼視窗負責校驗密保問題,判斷使用者是否擁有修改密碼許可權。

在這裡插入程式碼片from PyQt5 import QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import ctypes
import re
from PyQt5.QtWidgets import QMessageBox, QWidget, QLineEdit
from Functions import SecurityQuestion, ResetPassword
from SecurityQuestion_UI import Ui_SecurityQuestionWindow
from Reset_UI import Ui_ResetWindow


global username_changing


class SecurityQuestionWindow(QtWidgets.QMainWindow, Ui_SecurityQuestionWindow):
    signal = pyqtSignal()
    back_signal = pyqtSignal()

    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.setWindowTitle('忘記密碼')  # 設定視窗標題
        self.setWindowIcon(QIcon('logo.png'))  # 設定視窗圖示
        ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("myappid")  # 工作列圖示
        self.setWindowFlags(Qt.FramelessWindowHint)

        # 將訊號連線到對應槽函式
        self.confirm_button.clicked.connect(self.security_question)
        self.back_button.clicked.connect(self.back_to_login)
        self.close_button.clicked.connect(QCoreApplication.instance().quit)

    # 檢查使用者名稱與密保是否匹配
    def security_question(self):
        if SecurityQuestion(self.input_username.text(), self.input_security.text()):
            global username_changing
            username_changing = self.input_username.text()
            self.input_username.setText('')
            self.input_security.setText('')
            self.hide()
            self.signal.emit()  # 發射訊號
        else:
            QMessageBox.warning(self, "錯誤", "密保錯誤!")
            self.input_security.setText('')

    # 鍵盤確認
    def keyPressEvent(self, event):
        QWidget.keyPressEvent(self, event)
        key = event.key()
        if key == Qt.Key_Enter:
            self.security_question()

    def back_to_login(self):
        self.hide()
        self.back_signal.emit()  # 觸發返回登陸介面的訊號


class ResetWindow(QtWidgets.QMainWindow, Ui_ResetWindow):
    signal = pyqtSignal()
    back_signal = pyqtSignal()

    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.setWindowTitle('重置密碼')  # 設定視窗標題
        self.setWindowIcon(QIcon('logo.png'))  # 設定視窗圖示
        # self.setStyleSheet('QWidget{background-color:%s}' % QColor(222, 222, 222).name())  # 設定視窗背景色
        ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("myappid")  # 工作列圖示
        self.setWindowFlags(Qt.FramelessWindowHint)

        self.set_input()  # 輸入密碼的設定

        # 將訊號連線到對應槽函式
        self.submit_button.clicked.connect(self.Reset)
        self.back_button.clicked.connect(self.back_to_login)
        self.close_button.clicked.connect(QCoreApplication.instance().quit)

    def set_input(self):
        self.input_pass1.setContextMenuPolicy(Qt.NoContextMenu)  # 禁止複製貼上
        self.input_pass2.setContextMenuPolicy(Qt.NoContextMenu)  # 禁止複製貼上
        self.input_pass1.setEchoMode(QLineEdit.Password)  # 輸入時呈現圓點,不顯示密碼
        self.input_pass2.setEchoMode(QLineEdit.Password)  # 輸入時呈現圓點,不顯示密碼

    # 檢查使用者名稱與密保是否匹配
    def Reset(self):
        regx = re.compile(r"^[a-zA-Z]\w{5,14}")
        global username_changing
        if username_changing != '' and self.input_pass1.text() == self.input_pass2.text() and regx.match(self.input_pass1.text()) is not None:
            if regx.match(self.input_pass1.text()).group() == self.input_pass1.text():
                ResetPassword(username_changing, self.input_pass1.text())
                QMessageBox.information(self, "資訊", "修改密碼成功!")
                self.input_pass1.setText('')
                self.input_pass2.setText('')
                self.hide()
                self.signal.emit()  # 發射訊號
            else:
                QMessageBox.warning(self, "警告", "請輸入符合條件的密碼!")
                self.input_pass1.setText('')
                self.input_pass2.setText('')
        else:
            if self.input_pass1.text() != self.input_pass2.text():
                QMessageBox.warning(self, "警告", "兩次輸入的密碼不一致,請重新輸入!")
            else:
                QMessageBox.warning(self, "警告", "請輸入符合條件的密碼!")
            self.input_pass1.setText('')
            self.input_pass2.setText('')

    # 鍵盤確認
    def keyPressEvent(self, event):
        QWidget.keyPressEvent(self, event)
        key = event.key()
        if key == Qt.Key_Enter:
            self.Reset()

    def back_to_login(self):
        self.hide()
        self.back_signal.emit()  # 觸發返回登陸介面的訊號


四、主視窗(MainWindow.py)(重點)

  這部分是我重點負責的部分,我將比較詳細的解釋程式碼。

1. 成員變數
# 在PyQt5裡建立的是QMainWindow,不是Widget,需要注意的是,建立的元素一定要呼叫正確。
class MainWindow(QMainWindow, Ui_MainWindow):
    insert_signal = pyqtSignal()    # 定義插入訊號
    batch_signal = pyqtSignal()     # 定義批量插入訊號
    query_flag = 0      # 查詢標記
    check_list = []     # 確認列表
    delete_f = -1       # 批量刪除選定初始行
    delete_t = -1       # 批量刪除選定末尾行
2. 建構函式

  註釋寫的比較明瞭,就不過多贅述。

    def __init__(self):
        # 初始化視窗
        super().__init__()
        self.setupUi(self)
        self.setWindowTitle('校園一卡通管理系統')  # 設定視窗標題
        self.setWindowIcon(QIcon('logo.png'))  # 設定視窗圖示
        self.setWindowOpacity(1)  # 設定整個視窗的透明度為不透明
        # 初始化編輯框
        self.lineEdit_id.setText("")
        self.lineEdit_name.setText("")
        self.lineEdit_phonenumber.setText("")
        # 初始化下拉框
        self.comboBox_sex.addItems(["", "男", "女"])
        self.comboBox_college.addItems(["", "計算機學院", "機械學院", "外國語學院"])
        self.comboBox_major.addItems(["", "物聯網工程", "電腦科學與技術", "軟體工程", "通訊工程", "資訊保安"])
        self.comboBox_sex_2.addItems(["", "充值", "飲食", "電費", "水費", "車費"])
        # 初始化標記
        self.query_flag = 0
        self.check_list = []
        self.delete_f = -1
        self.delete_t = -1

        # 訊號和槽函式繫結
        # 欄目1(學生基本資訊)
        self.pushButton_query.clicked.connect(self.query)  # 為按鈕新增點選事件
        self.comboBox_college.activated.connect(self.update_ComboBox)   # 如果下拉框被啟用就更新子下拉框
        self.pushButton_insert.clicked.connect(self.insert_button_signal)  # 彈出插入視窗
        self.pushButton_delete.clicked.connect(self.deleteConfirm)  # 刪除操作
        self.tableWidget.itemChanged.connect(self.update_tableWidget)  # 查詢操作
        self.tableWidget.cellPressed.connect(self.update_flag)  # 更新查詢標記
        self.tableWidget.itemSelectionChanged.connect(self.update_selected) # 更新選擇區域
        self.pushButton_batch.clicked.connect(self.batch_button_signal) # 批量插入
        # 欄目2(交易記錄)
        self.pushButton_query_2.clicked.connect(self.upadate_tableWidget2)  # 查記錄
        # 欄目3(充值介面按鈕繫結)
        self.top_up_button.clicked.connect(self.top_up) # 繫結充值
3. 更新選擇區域

  當表格中選中區域發生改變時,更新當前選擇區域。

    # 更新選擇區域
    def update_selected(self):
        list = self.tableWidget.selectedRanges()
        for temp in list:
            self.delete_f = temp.topRow()
            self.delete_t = temp.bottomRow()
4. 便捷修改記錄

  獲取當前選中行列,更新當前行列中的資料。

    # 修改表資訊
    def update_tableWidget(self):
        # print(self.tableWidget.selectedItems()==None)
        # print("x: " + str(self.tableWidget.selectedIndexes()[0].row()) + ",  y: " + str(self.tableWidget.selectedIndexes()[0].column()))
        # print("請求修改資訊")
        if self.query_flag == 1:
            return
        i = self.tableWidget.currentIndex().row()
        j = self.tableWidget.currentIndex().column()
        lable = ['學號', '姓名', '性別', '學院', '專業', '手機號', '餘額']
        # print(self.tableWidget.item(i,0).text(),lable[j],self.tableWidget.item(i,j).text())
        DataUpdate(self.tableWidget.item(i, 0).text(), lable[j], self.tableWidget.item(i, j).text())
5. 更新標記 & 發射訊號

  當表格中有元素被按下就更新查詢標記,防止查詢bug。另外兩個訊號是用來彈出視窗的。

# 更新標誌
    def update_flag(self):
        # print("flag")
        self.query_flag = 0

    # 批量插入按鈕發射訊號
    def batch_button_signal(self):
        self.batch_signal.emit()  # 發射訊號

    # 插入按鈕發射訊號
    def insert_button_signal(self):
        self.insert_signal.emit()  # 發射訊號
6. 單個刪除 & 批量刪除

  單個選擇刪除和批量刪除二者通過當前選擇行列來判斷是哪一種。同時刪除之前會彈出訊息框來確認是否刪除。批量刪除的實現是通過檢查檢視核取方塊的選擇狀態來實現批量刪除的。

    # 批量刪除
    def delete2(self):
        if self.delete_f == -1 and self.delete_t == -1:
            # QMessageBox.warning(self, "失敗", "請框選需要刪除的記錄!")
            return False
        for i in range(self.delete_f,self.delete_t + 1):
            DeleteData(str(self.tableWidget.item(i, 0).text()))
        self.query()
        QMessageBox.information(self, "資訊", "刪除記錄成功!")
        self.delete_t = -1
        self.delete_f = -1
        return True

    # 刪除確認
    def deleteConfirm(self):
        message_box = QMessageBox()
        message_box.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
        message_box.setWindowTitle("提示")
        message_box.setText("確認刪除?")
        message_box.setWindowIcon(QIcon('logo.png'))
        yes = message_box.button(QMessageBox.Yes)
        yes.clicked.connect(self.delete)  # 點選此按鈕則退出程式
        message_box.exec()
        
	# 刪除按鈕發射訊號
    def delete(self):
        if self.delete2():
            return
        flag = 0
        for i in range(0, self.tableWidget.rowCount()):
            if self.check_list[i].checkState() == 2:
                flag = 1
                DeleteData(str(self.tableWidget.item(i, 0).text()))
        if flag == 1:
            self.query()
            QMessageBox.information(self, "提示", "刪除記錄成功!")
            self.delete_t = -1
            self.delete_f = -1
        else:
            QMessageBox.critical(self, "失敗", "請勾選需要刪除的記錄!")
7. 下拉框元素更新
    # 下拉框增加元素
    def update_ComboBox(self):
        coll = self.comboBox_college.currentText()
        self.comboBox_major.clear()
        if coll == "計算機學院":
            self.comboBox_major.addItems(["物聯網工程", "電腦科學與技術", "軟體工程", "通訊工程", "資訊保安"])
        elif coll == "機械學院":
            self.comboBox_major.addItems(["機械電子工程", "測控技術與儀器", "機械設計製造", "工業設計"])
        elif coll == "外國語學院":
            self.comboBox_major.addItems(["英語", "俄語", "日語", "法語", "西班牙語"])

8. 模糊查詢

  通過獲取編輯框和下拉框的資料來進行查詢,通過輸入的欄位來改變sql語句進行模糊查詢。

    # 模糊查詢
    def query(self):
        self.query_flag = 1
        id = self.lineEdit_id.text()
        name = self.lineEdit_name.text()
        sex = self.comboBox_sex.currentText()
        coll = self.comboBox_college.currentText()
        major = self.comboBox_major.currentText()
        number = self.lineEdit_phonenumber.text()
        result = informationInput(id, name, sex, coll, major, number)

        self.check_list.clear()
        for i in range(0, result.__len__()):
            # 下面六行用於生成居中的checkbox,不知道有沒有別的好方法
            ck = QCheckBox()
            self.check_list.append(ck)

        # 呼叫資料庫
        self.tableWidget.setRowCount(result.__len__())
        self.tableWidget.setColumnCount(8)
        self.tableWidget.setHorizontalHeaderLabels(['學號', '姓名', '性別', '學院', '專業', '手機號', '餘額', '選擇'])
        self.tableWidget.setColumnWidth(0, 200)
        self.tableWidget.setColumnWidth(1, 100)
        self.tableWidget.setColumnWidth(2, 50)
        self.tableWidget.setColumnWidth(3, 160)
        self.tableWidget.setColumnWidth(4, 160)
        self.tableWidget.setColumnWidth(5, 150)
        self.tableWidget.setColumnWidth(6, 120)
        self.tableWidget.setColumnWidth(7, 87)
        for i in range(0, self.tableWidget.rowCount()):
            self.tableWidget.setRowHeight(i, 44)

        lable1 = ['學號', '姓名', '性別', '學院', '專業', '手機號', '餘額', '選擇']
        for i in range(result.__len__()):
            temp = result[i]
            for j in range(0, lable1.__len__()):
                if j < 7:
                    if temp[lable1[j]] is not None:
                        self.tableWidget.setItem(i, j, QTableWidgetItem(str(temp[lable1[j]])))
                    else:
                        self.tableWidget.setItem(i, j, QTableWidgetItem(" "))
                else:
                    h = QHBoxLayout()
                    h.setAlignment(Qt.AlignCenter)
                    h.addWidget(self.check_list[i])
                    w = QWidget()
                    w.setLayout(h)
                    self.tableWidget.setCellWidget(i, j, w)
9. 更新交易記錄

  根據輸入欄位模糊查詢交易記錄。

    # 更新交易記錄
    def upadate_tableWidget2(self):
        id2 = self.lineEdit_id_2.text()
        name2 = self.lineEdit_name_2.text()
        type2 = self.comboBox_sex_2.currentText()
        result = TransactionRecords(id2, name2, type2)

        # 呼叫資料庫
        lable1 = ['學號', '姓名', '消費型別', '消費時間', '金額變動', '餘額']
        self.tableWidget_2.setRowCount(result.__len__())
        self.tableWidget_2.setColumnCount(6)
        self.tableWidget_2.setHorizontalHeaderLabels(lable1)
        self.tableWidget_2.setColumnWidth(0, 200)
        self.tableWidget_2.setColumnWidth(1, 150)
        self.tableWidget_2.setColumnWidth(2, 100)
        self.tableWidget_2.setColumnWidth(3, 300)
        self.tableWidget_2.setColumnWidth(4, 138)
        self.tableWidget_2.setColumnWidth(5, 138)
        for i in range(0, self.tableWidget_2.rowCount()):
            self.tableWidget_2.setRowHeight(i, 45)

        for i in range(result.__len__()):
            temp = result[i]
            for j in range(0, lable1.__len__()):
                if temp[j] is not None:
                    if j == 4:
                        money = str(temp[j])
                        if money[0] != '-':
                            money = "+ " + money
                        else:
                            money = "- " + money[1:]
                        self.tableWidget_2.setItem(i, 4, QTableWidgetItem(money))
                    else:
                        self.tableWidget_2.setItem(i, j, QTableWidgetItem(str(temp[j])))
                else:
                    self.tableWidget_2.setItem(i, j, QTableWidgetItem(" "))
10. 充值

  通過學號和充值金額進行更新資料。

    # 充值
    def top_up(self):
        username = self.top_up_id.text()
        money = self.top_up_money.text()
        result = Recharge(money, username)
        if result == 0:
            QMessageBox.warning(self, "錯誤", "請輸入有效學號!")
            self.top_up_id.setText('')
        elif result == 1:
            QMessageBox.warning(self, "錯誤", "請輸入正確金額!")
            self.top_up_money.setText('')
        else:
            QMessageBox.information(self, "成功", "充值成功!")
            self.top_up_id.setText('')
            self.top_up_money.setText('')

五、單條插入視窗(InsertWindow.py)

from PyQt5.QtCore import pyqtSignal
from PyQt5.QtGui import QStandardItemModel, QStandardItem, QIcon
from PyQt5.QtWidgets import *
from Insert_UI import Ui_InsertWindow
from Functions import *


class InsertWindow(QMainWindow, Ui_InsertWindow):
    inserted_signal = pyqtSignal()

    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.setWindowTitle('校園一卡通管理系統')  # 設定視窗標題
        self.setWindowIcon(QIcon('logo.png'))  # 設定視窗圖示
        # self.setWindowIcon(QIcon('1.jpg'))  # 設定視窗圖示
        # self.setStyleSheet('QWidget{background-color:%s}' % QColor(222, 222, 222).name())  # 設定視窗背景色
        self.setWindowOpacity(1)  # 設定整個計算器視窗的透明度
        # ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("myappid")  # 工作列圖示
        self.comboBox_sex.addItems([" ", "男", "女"])
        self.comboBox_college.addItems([" ", "計算機學院", "機械學院", "外國語學院"])
        self.comboBox_major.addItems([" ", "物聯網工程", "電腦科學與技術", "軟體工程", "通訊工程", "資訊保安"])
        # self.show()

        # 按鈕繫結
        self.pushButton_insert.clicked.connect(self.insert)  # 插入事件
        self.comboBox_college.activated.connect(self.update_ComboBox)

    # 下拉框增加元素
    def update_ComboBox(self):
        coll = self.comboBox_college.currentText()
        self.comboBox_major.clear()
        if coll == "計算機學院":
            self.comboBox_major.addItems(["物聯網工程", "電腦科學與技術", "軟體工程", "通訊工程", "資訊保安"])
        elif coll == "機械學院":
            self.comboBox_major.addItems(["機械電子工程", "測控技術與儀器", "機械設計製造", "工業設計"])
        elif coll == "外國語學院":
            self.comboBox_major.addItems(["英語", "俄語", "日語", "法語", "西班牙語"])

    def insert(self):
        # 資料庫互動
        id = self.lineEdit_id.text()
        name = self.lineEdit_name.text()
        sex = self.comboBox_sex.currentText()
        coll = self.comboBox_college.currentText()
        major = self.comboBox_major.currentText()
        number = self.lineEdit_phonenumber.text()
        Imformation(id, name, sex, coll, major, number)
        self.inserted_signal.emit()
        QMessageBox.information(self, "成功", "插入記錄成功!")
        pass

六、批量匯入視窗(BatchInsertedWindow.py)

import os

from PyQt5 import QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import ctypes
import time
from PyQt5.QtWidgets import QLineEdit, QMessageBox, QWidget

from BatchInserted_UI import Ui_BatchInsertedWindow


class BatchInsertedWindow(QtWidgets.QMainWindow, Ui_BatchInsertedWindow):
    step = 0
    first = 0
    last = 0
    number = 1

    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.setWindowTitle('校園一卡通管理系統')  # 設定視窗標題
        self.setWindowIcon(QIcon('logo.png'))  # 設定視窗圖示
        ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("myappid")  # 工作列圖示

        # 將訊號連線到對應槽函式
        self.batch_insert_button.clicked.connect(self.BatchInsert)
        # self.batch_insert_button.clicked.connect(self.timerEvent)

        self.timer = QBasicTimer
        self.pbar.setValue(self.step)

    # 鍵盤登入
    def keyPressEvent(self, event):
        QWidget.keyPressEvent(self, event)
        key = event.key()
        if key == Qt.Key_Enter:
            self.BatchInsert()

    def BatchInsert(self):
        path = self.insert_path.text()
        self.first = self.lineEdit.text()
        self.last = self.lineEdit_2.text()
        self.StudentInformation(path, self.first, self.last)

    def StudentInformation(self, path, start, last):
        import pymysql
        from openpyxl import load_workbook
        from datetime import date, datetime
        db = pymysql.connect("localhost", "root", "123456", "onecartoon")
        # 使用cursor()方法獲取操作遊標
        # 使用cursor()方法獲取操作遊標
        cursor = db.cursor()
        if path == "":
            path = ".//student.xlsx"
        if os.path.exists(path):
            workbook = load_workbook(filename=path)
            sheet1 = workbook["sheet1"]
            if start == "":
                start = 1
            if last == "":
                last = 1
            start = int(start)
            last = int(last)
            self.step = 0
            self.first = start
            self.last = last
            from builtins import str
            list1 = []
            # from builtins import range
            for q in range(start, last + 1):
                list1.append([])
                # print(q)
                for row in sheet1.iter_rows(min_row=q, max_row=q):
                    # print(row)
                    for cell in row:
                        # from builtins import str
                        string = str(cell.value)
                        # print(string)
                        # print(string)
                        list1[q - start].append(string)
            # print(list1)
            cnt = 0
            for i in range(0, len(list1)):
                date = list1[i]
                # print(i, date)
                # print(date)
                str1 = ""
                self.number = i + 1
                for j in range(6):
                    str1 += "'" + date[j] + "',"

                str1 = str1[:-1]
                sql_str = "INSERT INTO 學生基本資訊(學號, 姓名, 性別, 學院, 專業, 手機號, 餘額) VALUES(%s,%s)" % (str1, int(date[6]))
                try:
                    # 執行sql語句
                    db.ping(reconnect=True)
                    cursor.execute(sql_str)
                    db.commit()
                    cnt += 1
                except Exception as e:
                    # 如果發生錯誤則回滾
                    print("修改失敗!")
                    print(e)
                    db.rollback()
                    # 關閉資料庫連線
                    db.close()

                # print(len(list1))
                self.step = self.number / (self.last + 1 - self.first) * 100
                self.pbar.setValue(self.step)
                if self.step == 100.0:
                    time.sleep(0.3)
                    text = '成功插入' + str(cnt) + '條記錄!'
                    QMessageBox.warning(self, "成功", text)
                    self.step = 0
                    self.pbar.setValue(self.step)

        else:
            QMessageBox.warning(self, "錯誤", "請輸入正確路徑!")

七、與資料庫互動的各種方法(Functions.py)

  與資料庫進行增刪改查等操作的各種方法。

from datetime import datetime
from multiprocessing import connection

Cno = '0'  # 用於最後的登出


# 註冊賬號密碼
# 對應引數分別是學號,密碼,密保
def register(studentNumber, password, SecretGuard):
    import pymysql
    db = pymysql.connect("localhost", "root", "123456", "onecartoon")
    # 使用cursor()方法獲取操作遊標
    # 使用cursor()方法獲取操作遊標
    cursor = db.cursor()
    ch = "select 學號 from 學生基本資訊 where 學號='%s'" % studentNumber
    cursor.execute(ch)
    ch1 = cursor.fetchone()
    if ch1 == None:
        print("學號輸入錯誤")
    else:
        sql = """INSERT INTO 註冊(學號,
                      密碼,密保)
                      VALUES ('%s', '%s', '%s')""" % (studentNumber, password, SecretGuard)
        try:
            # 執行sql語句
            cursor.execute(sql)
            # 提交到資料庫執行
            db.commit()
        except:
            # 如果發生錯誤則回滾
            db.rollback()
            # 關閉資料庫連線
            db.close()
        else:
            print("註冊成功!")
        return


# 登入
# 需要對應的變數來存放登入的賬號
def load(studentNumber, password):
    global Cno
    import pymysql.cursors
    connection = pymysql.connect(host='localhost', port=3306, user='root', password='123456', db='onecartoon',
                                 charset='utf8mb4', cursorclass=pymysql.cursors.DictCursor)
    cur = connection.cursor()
    # pattern = re.compile()
    sqlDL = "select 學號  from 註冊 where 註冊.學號='%s' and 註冊.密碼='%s'" % (studentNumber, password)
    cur.execute(sqlDL)
    jilu = cur.fetchone()  # 登錄檔中沒有對應賬號和密碼
    if jilu == None:
        return False
    elif jilu != None:
        Cno = studentNumber
        return True


# 資訊的錄入
# 對應引數分別是 學號 性別 姓名 學院 專業 手機號 餘額
def Imformation(studentNumber, name, gender, College, major, mobileNumber):
    import pymysql
    # 開啟資料庫連線
    db = pymysql.connect("localhost", "root", "123456", "onecartoon")
    # 使用cursor()方法獲取操作遊標
    cursor = db.cursor()
    money = 100
    lable = [studentNumber, name, gender, College, major, mobileNumber]
    lable1 = ['學號', '姓名', '性別', '學院', '專業', '手機號']
    str = ''  # 初始化為空串
    str1 = ''
    flag = 0
    for i in range(4, 6):
        # print(i)
        if lable[i] != '':
            str1 += lable1[i] + ","
            flag = 1
            str += "'" + lable[i] + "',"
    str = str[:-1]
    str1 = str1[:-1]
    # print(studentNumber)
    # # SQL 插入語句
    if flag == 0:
        sql = "INSERT INTO 學生基本資訊(學號,姓名,性別,學院,餘額) VALUES('%s','%s','%s','%s',%s)" % (
        studentNumber, name, gender, College, money)
    else:
        sql = "INSERT INTO 學生基本資訊(學號,姓名,性別,學院,%s,餘額) VALUES ('%s','%s','%s','%s',%s, %s)" % (
            str1, studentNumber, name, gender, College, str, money)
    try:
        # 執行sql語句
        print(sql)
        cursor.execute(sql)
        # 提交到資料庫執行
        db.commit()
    except:
        # 如果發生錯誤則回滾
        print("資訊錄入錯誤")
        db.rollback()
        # 關閉資料庫連線
        db.close()
    else:
        print('資訊錄入成功')
        return


# 對應引數是 屬性和具體的值   比如性別,男
def Check(fun, natural):
    import pymysql.cursors
    connection = pymysql.connect(host='localhost', port=3306, user='root', password='123456', db='onecartoon',
                                 charset='utf8mb4', cursorclass=pymysql.cursors.DictCursor)
    cur = connection.cursor()
    if fun == '性別':
        sqlJiaoYi = "select * from 交易記錄 where 性別='%s'" % (natural)
    elif fun == '學號':
        sqlJiaoYi = "select * from 交易記錄 where 學號='%s'" % (natural)
    elif fun == '消費型別':
        sqlJiaoYi = "select * from 交易記錄 where 消費型別='%s'" % (natural)
    elif fun == '1':
        sqlJiaoYi = "select * from 交易記錄"
    cur.execute(sqlJiaoYi)
    result = cur.fetchall()
    for data in result:
        print(data)
    cur.close()
    connection.close()


# Check('性別', '女')
# 充值校園卡   要改
# 對應引數是 錢數 學號 時間
def Recharge(money, nameNumber):
    import pymysql
    db = pymysql.connect("localhost", "root", "123456", "onecartoon")
    # 使用cursor()方法獲取操作遊標
    cursor = db.cursor()
    time = datetime.now()
    ch = "select 學號 from 學生基本資訊 where 學號='%s'" % (nameNumber)
    cursor.execute(ch)  # 載入到資料庫中
    ch1 = cursor.fetchone()  # 將資料拿出來
    if ch1 is None:
        return 0
    else:
        sql1 = "select 學號,餘額 from 學生基本資訊 where 學號='%s'" % (nameNumber)
        cursor.execute(sql1)
        ch3 = cursor.fetchone()
        print(ch3)
        sql = "update 學生基本資訊 set 餘額=餘額+%s where 學號='%s'" % (money, nameNumber)
        sql3 = "INSERT INTO 交易記錄(學號,消費型別,金額變動,消費時間,餘額) VALUES ('%s','充值',%s,'%s',%s)" % (ch3[0], money, time, ch3[1] + float(money))
        print(sql)
        print(sql3)
        try:
            # 執行sql語句
            cursor.execute(sql)
            # 提交到資料庫執行
            db.commit()
            cursor.execute(sql3)
            db.commit()
            return 2
        except:
            # 如果發生錯誤則回滾
            db.rollback()
            # 關閉資料庫連線
            db.close()
            return 1


#  修改資訊
# 對應引數是學號
def Exchange(name):
    import pymysql.cursors
    connection = pymysql.connect(host='localhost', port=3306, user='root', password='123456', db='onecartoon',
                                 charset='utf8mb4', cursorclass=pymysql.cursors.DictCursor)
    cur = connection.cursor()
    secretGuard = input("請輸入密保:")
    sqlXH = "select 密保 from 註冊 where 註冊.學號='%s'" % (name)
    cur.execute(sqlXH)
    jilu = cur.fetchone()
    # for data in jilu:
    if jilu == {'密保': secretGuard}:
        NewpPassword = input("請輸入新密碼:")
        sqlNewPassword = "update 註冊 set 密碼='%s' where 學號='%s'" % (NewpPassword, name)
        print("修改成功")
    elif jilu != {'密碼': secretGuard}:
        print("密保錯誤")
        Exchange(name)
    cur.close()
    connection.close()


# 基本資訊表的輸出
# 對應引數是要輸出的表 比如要輸出學生基本資訊  str=學生基本資訊
def inputInformation(str):
    import pymysql.cursors
    connection = pymysql.connect(host='localhost', port=3306, user='root', password='123456', db='onecartoon',
                                 charset='utf8mb4', cursorclass=pymysql.cursors.DictCursor)
    try:
        cursor = connection.cursor()
        sql = "select * from %s" % (str)
        cursor.execute(sql)
        result = cursor.fetchall()
        # 資訊的輸出
        for data in result:
            print(data)
    except Exception as e:
        print("資訊輸入錯誤")
        # 提示錯誤資訊
        # print(e)
        cursor.close()
        connection.close()
    return


# str = input("請輸入所要輸出的表的名字:")
# inputInformation(str)


# 登出賬號
def logOut():
    import pymysql
    db = pymysql.connect("localhost", "root", "123456", "onecartoon")
    # 使用cursor()方法獲取操作遊標
    # 使用cursor()方法獲取操作遊標
    cursor = db.cursor()
    sql = "delete from 學生基本資訊 where 學號='%s'" % Cno
    sql1 = "delete from 註冊 where 學號='%s'" % Cno
    sql2 = "delete from 交易記錄 where 學號='%s'" % Cno
    try:
        # 執行sql語句
        cursor.execute(sql1)
        # 提交到資料庫執行
        db.commit()
        cursor.execute(sql2)
        db.commit()
        cursor.execute(sql)
        db.commit()
    except:
        # 如果發生錯誤則回滾
        print("登出失敗!")
        db.rollback()
        # 關閉資料庫連線
        db.close()
    else:
        print("登出成功!")


# 學生基本資訊查詢
def informationInput(studentNumber, name, gender, College, major, mobileNumber):
    lable = [studentNumber, name, gender, College, major, mobileNumber]
    lable1 = ['學號', '姓名', '性別', '學院', '專業', '手機號']
    str = ""  # 初始化為空串
    flag = 0

    for i in range(6):
        if lable[i] != '':
            flag = 1
            # str += (lable1[i] + "='" + lable[i] + "' and ")
            str += (lable1[i] + " LIKE '%" + lable[i] + "%' and ")

    str = str[:-5]
    # print(str)

    import pymysql.cursors
    connection = pymysql.connect(host='localhost', port=3306, user='root', password='123456', db='onecartoon',
                                 charset='utf8mb4', cursorclass=pymysql.cursors.DictCursor)
    try:
        cursor = connection.cursor()
        if flag == 0:
            sql = "select * from 學生基本資訊"
        else:
            sql = "select * from 學生基本資訊 where %s" % str
        cursor.execute(sql)
        result = cursor.fetchall()
        # 資訊的輸出
        return result
    except Exception as e:
        print("資訊輸入錯誤")
        # 提示錯誤資訊
        print(e)
        cursor.close()
        connection.close()


def DataUpdate(studentNumber, attribute, val):
    import pymysql
    db = pymysql.connect("localhost", "root", "123456", "onecartoon")
    # 使用cursor()方法獲取操作遊標
    # 使用cursor()方法獲取操作遊標
    cursor = db.cursor()
    sql = "update 學生基本資訊 set %s='%s' where 學號='%s'" % (attribute, val, studentNumber)
    print(sql)
    try:
        # 執行sql語句
        cursor.execute(sql)
        # 提交到資料庫執行
        db.commit()
    except:
        # 如果發生錯誤則回滾
        print("修改失敗!")
        db.rollback()
        # 關閉資料庫連線
        db.close()
    else:
        print("修改成功!")


def DeleteData(studentNumber):
    import pymysql
    db = pymysql.connect("localhost", "root", "123456", "onecartoon")
    # 使用cursor()方法獲取操作遊標
    # 使用cursor()方法獲取操作遊標
    cursor = db.cursor()
    # print(studentNumber)
    sql = "DELETE FROM 學生基本資訊 WHERE 學號='%s'" % (studentNumber)
    sql1 = "DELETE FROM 交易記錄 WHERE 學號='%s'" % (studentNumber)
    try:
        # 執行sql語句
        cursor.execute(sql1)
        # 提交到資料庫執行
        db.commit()
        cursor.execute(sql)
        # 提交到資料庫執行
        db.commit()
    except:
        # 如果發生錯誤則回滾
        print("刪除資訊失敗!")
        #         db.rollback()
        #         # 關閉資料庫連線
        db.close()
    else:
        print("刪除成功!")


# 交易記錄輸出
def TransactionRecords(studentNumber, name, ConsumptionType):
    lable = [studentNumber, name, ConsumptionType]
    lable1 = ['學號', '姓名', '消費型別']
    str = ""  # 初始化為空串
    flag = 0
    for i in range(3):
        if lable[i] != "":
            flag = 1
            if i == 0:
                str += "學生基本資訊." + lable1[i] + " LIKE '%" + lable[i] + "%' and "
            elif i == 1:
                str += "學生基本資訊." + lable1[i] + " LIKE '%" + lable[i] + "%' and "
            elif i == 2:
                str += lable1[i] + " LIKE '%" + lable[i] + "%' and "

    if str.__len__()>5:
        str = str[:-5]
    import pymysql.cursors
    connection = pymysql.connect(host='localhost', port=3306, user='root', password='123456', db='onecartoon')
    cur = connection.cursor()
    if flag == 0:
        sql = "select 學生基本資訊.學號,學生基本資訊.姓名,消費型別,消費時間,金額變動,交易記錄.餘額 from 學生基本資訊,交易記錄 where 學生基本資訊.學號=交易記錄.學號"
    else:
        sql = "select 學生基本資訊.學號,學生基本資訊.姓名,消費型別,消費時間,金額變動,交易記錄.餘額 from 交易記錄,學生基本資訊 where 學生基本資訊.學號=交易記錄.學號 and %s" % str
    # print(sql)
    cur.execute(sql)
    result = cur.fetchall()
    # print(result)
    # for data in result:
    #     print(data)
    # 更改欄位
    list = []
    for i in range(result.__len__()):
        temp = result[i]
        list.append([])
        for j in range(0, 6):
            list[i].append(temp[j])
    return list
    cur.close()
    connection.close()

# 檢查密保問題
def SecurityQuestion(name, secretGuard):
    import pymysql.cursors
    connection = pymysql.connect(host='localhost', port=3306, user='root', password='123456', db='onecartoon',
                                 charset='utf8mb4', cursorclass=pymysql.cursors.DictCursor)
    cur = connection.cursor()
    sqlXH = "select 密保 from 註冊 where 註冊.學號='%s'" % name
    cur.execute(sqlXH)
    jilu = cur.fetchone()
    # for data in jilu:
    cur.close()
    connection.close()
    if jilu == {'密保': secretGuard}:
        return True
    else:
        return False


# 重置密碼
def ResetPassword(name, new_password):
    import pymysql
    db = pymysql.connect("localhost", "root", "123456", "onecartoon")
    # 使用cursor()方法獲取操作遊標
    cursor = db.cursor()
    sqlNewPassword = "update 註冊 set 密碼='%s' where 學號='%s'" % (new_password, name)
    cursor.execute(sqlNewPassword)  # 提交到資料庫執行
    db.commit()
    # 關閉資料庫連線
    db.close()


def StudentInformation(path, start, last):
    import pymysql
    from openpyxl import load_workbook
    from datetime import date, datetime
    db = pymysql.connect("localhost", "root", "123456", "onecartoon")
    # 使用cursor()方法獲取操作遊標
    # 使用cursor()方法獲取操作遊標
    cursor = db.cursor()
    print("666")
    if path == "":
        path = "student.xlsx"
    workbook = load_workbook(filename=".\\" + path)
    # print(workbook.sheetnames)
    sheet1 = workbook["sheet1"]
    print("999")
    if start == "":
        start = 1
    if last == "":
        last = 1
    start = int(start)
    last = int(last)
    print("start:" + str(start) + ",  end:" + str(last))
    list1 = []
    # from builtins import range
    for q in range(start, last+1):
        list1.append([])
        # print(q)
        for row in sheet1.iter_rows(min_row=q, max_row=q):
            # print(row)
            for cell in row:
                # from builtins import str
                string = str(cell.value)
                # print(string)
                # print(string)
                list1[q - start].append(string)
    print(list1)
    for i in range(0, len(list1)):
        date = list1[i]
        # print(i, date)
        # print(date)
        str1 = ""

        for j in range(6):
            str1 += "'" + date[j] + "',"

        str1 = str1[:-1]
        sql_str = "INSERT INTO 學生基本資訊(學號, 姓名, 性別, 學院, 專業, 手機號, 餘額) VALUES(%s,%s)" % (str1, int(date[6]))
        print(sql_str)
        try:
            # 執行sql語句
            db.ping(reconnect=True)
            cursor.execute(sql_str)
            db.commit()
        except Exception as e:
            # 如果發生錯誤則回滾
            print("修改失敗!")
            print(e)
            db.rollback()
            # 關閉資料庫連線
            db.close()



———2020.12.27(羅涵)

THE END

相關文章