简体   繁体   English

PyQt5 和 MySQL GUI 程序崩溃

[英]PyQt5 and MySQL GUI Program Crashing

So, I made a GUI using PyQt5 for a database form that allows you to perform different operations on the database.因此,我使用 PyQt5 为数据库表单制作了一个 GUI,允许您对数据库执行不同的操作。 There are four buttons: Select, Insert, Delete, General View and Clear.有四个按钮:选择、插入、删除、常规视图和清除。 Clear simply wipes/clears out the displayed data in the table of the GUI.清除只是擦除/清除 GUI 表中显示的数据。

Each of select, insert, delete and general view, when pressed, are supposed to run their respected functions to which they are connected.选择、插入、删除和一般视图中的每一个在按下时都应该运行它们所连接的相关功能。 Within the functions, they connect to the database, run the queries and display the result in the table.在函数中,它们连接到数据库、运行查询并将结果显示在表中。

However, when I run the GUI and press a button such as General View for example, the program stops running and crashes and I get no tracebacks or error reports in the IDLE Shell too.但是,当我运行 GUI 并按下诸如常规视图之类的按钮时,程序停止运行并崩溃,并且我在 IDLE Shell 中也没有得到任何回溯或错误报告。

My code is below:我的代码如下:

from PyQt5 import QtCore, QtGui, QtWidgets
import mysql.connector as mc
from PyQt5.QtWidgets import QTableWidgetItem

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(538, 487)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
        self.verticalLayout.setObjectName("verticalLayout")
        self.gridLayout_2 = QtWidgets.QGridLayout()
        self.gridLayout_2.setObjectName("gridLayout_2")
        self.lineCMS = QtWidgets.QLineEdit(self.centralwidget)
        self.lineCMS.setObjectName("lineCMS")
        self.gridLayout_2.addWidget(self.lineCMS, 0, 1, 1, 1)
        self.lineRoom = QtWidgets.QLineEdit(self.centralwidget)
        self.lineRoom.setObjectName("lineRoom")
        self.gridLayout_2.addWidget(self.lineRoom, 3, 1, 1, 1)
        self.CMS = QtWidgets.QLabel(self.centralwidget)
        self.CMS.setObjectName("CMS")
        self.gridLayout_2.addWidget(self.CMS, 0, 0, 1, 1)
        self.lineName = QtWidgets.QLineEdit(self.centralwidget)
        self.lineName.setObjectName("lineName")
        self.gridLayout_2.addWidget(self.lineName, 1, 1, 1, 1)
        self.Room = QtWidgets.QLabel(self.centralwidget)
        self.Room.setObjectName("Room")
        self.gridLayout_2.addWidget(self.Room, 3, 0, 1, 1)
        self.Department = QtWidgets.QLabel(self.centralwidget)
        self.Department.setObjectName("Department")
        self.gridLayout_2.addWidget(self.Department, 2, 0, 1, 1)
        self.Name = QtWidgets.QLabel(self.centralwidget)
        self.Name.setObjectName("Name")
        self.gridLayout_2.addWidget(self.Name, 1, 0, 1, 1)
        self.lineDepartment = QtWidgets.QLineEdit(self.centralwidget)
        self.lineDepartment.setObjectName("lineDepartment")
        self.gridLayout_2.addWidget(self.lineDepartment, 2, 1, 1, 1)
        self.lineDOB = QtWidgets.QLineEdit(self.centralwidget)
        self.lineDOB.setObjectName("lineDOB")
        self.gridLayout_2.addWidget(self.lineDOB, 4, 1, 1, 1)
        self.DOB = QtWidgets.QLabel(self.centralwidget)
        self.DOB.setObjectName("DOB")
        self.gridLayout_2.addWidget(self.DOB, 4, 0, 1, 1)
        self.verticalLayout.addLayout(self.gridLayout_2)
        self.horizontalLayout = QtWidgets.QHBoxLayout()
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.Select = QtWidgets.QPushButton(self.centralwidget)
        self.Select.setObjectName("Select")
        self.horizontalLayout.addWidget(self.Select)
        self.line = QtWidgets.QFrame(self.centralwidget)
        self.line.setFrameShape(QtWidgets.QFrame.VLine)
        self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.line.setObjectName("line")
        self.horizontalLayout.addWidget(self.line)
        self.Insert = QtWidgets.QPushButton(self.centralwidget)
        self.Insert.setObjectName("Insert")
        self.horizontalLayout.addWidget(self.Insert)
        self.line_2 = QtWidgets.QFrame(self.centralwidget)
        self.line_2.setFrameShape(QtWidgets.QFrame.VLine)
        self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.line_2.setObjectName("line_2")
        self.horizontalLayout.addWidget(self.line_2)
        self.Delete = QtWidgets.QPushButton(self.centralwidget)
        self.Delete.setObjectName("Delete")
        self.horizontalLayout.addWidget(self.Delete)
        self.line_3 = QtWidgets.QFrame(self.centralwidget)
        self.line_3.setFrameShape(QtWidgets.QFrame.VLine)
        self.line_3.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.line_3.setObjectName("line_3")
        self.horizontalLayout.addWidget(self.line_3)
        self.Clear = QtWidgets.QPushButton(self.centralwidget)
        self.Clear.setObjectName("Clear")
        self.horizontalLayout.addWidget(self.Clear)
        self.verticalLayout.addLayout(self.horizontalLayout)
        self.table = QtWidgets.QTableWidget(self.centralwidget)
        self.table.setObjectName("table")
        self.table.setColumnCount(5)
        self.table.setRowCount(0)
        item = QtWidgets.QTableWidgetItem()
        self.table.setHorizontalHeaderItem(0, item)
        item = QtWidgets.QTableWidgetItem()
        self.table.setHorizontalHeaderItem(1, item)
        item = QtWidgets.QTableWidgetItem()
        self.table.setHorizontalHeaderItem(2, item)
        item = QtWidgets.QTableWidgetItem()
        self.table.setHorizontalHeaderItem(3, item)
        item = QtWidgets.QTableWidgetItem()
        self.table.setHorizontalHeaderItem(4, item)
        self.verticalLayout.addWidget(self.table)
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        self.verticalLayout.addLayout(self.horizontalLayout_2)
        self.generalView = QtWidgets.QPushButton(self.centralwidget)
        self.generalView.setObjectName("generalView")
        self.verticalLayout.addWidget(self.generalView)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 538, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)
        self.Select.clicked.connect(self.select)
        self.Insert.clicked.connect(self.insert)
        self.Delete.clicked.connect(self.delete)
        self.generalView.clicked.connect(self.view)
        self.Clear.clicked.connect(self.clear)
    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "Student"))
        self.CMS.setText(_translate("MainWindow", "CMS"))
        self.Room.setText(_translate("MainWindow", "Room No."))
        self.Department.setText(_translate("MainWindow", "Department"))
        self.Name.setText(_translate("MainWindow", "Name"))
        self.DOB.setText(_translate("MainWindow", "Date of Birth"))
        self.Select.setText(_translate("MainWindow", "SELECT"))
        self.Insert.setText(_translate("MainWindow", "INSERT"))
        self.Delete.setText(_translate("MainWindow", "DELETE"))
        self.Clear.setText(_translate("MainWindow", "CLEAR"))
        item = self.table.horizontalHeaderItem(0)
        item.setText(_translate("MainWindow", "CMS"))
        item = self.table.horizontalHeaderItem(1)
        item.setText(_translate("MainWindow", "Name"))
        item = self.table.horizontalHeaderItem(2)
        item.setText(_translate("MainWindow", "Department"))
        item = self.table.horizontalHeaderItem(3)
        item.setText(_translate("MainWindow", "Room No."))
        item = self.table.horizontalHeaderItem(4)
        item.setText(_translate("MainWindow", "Date of Birth"))
        self.generalView.setText(_translate("MainWindow", "GENERAL VIEW"))
        
    def select():
        try:
            self.table.setRowCount(0)
            QCMS = self.lineCMS.text() + "%"
            QDepartment = self.lineDepartment.text() + "%"
            QName = self.lineName.text() + "%"
            QRoom = self.lineRoom.text() + "%"
            QDOB = self.lineDOB.text() + "%"

            mydb = mc.connect(host="localhost",user="root",password="",database="sakila")
            mycursor = mydb.cursor()
            selectQuery = "SELECT * FROM Student WHERE CMS like '{}' and Department like '{}' and Name like '{}' and RoomNo like '{}' and DateOfBirth like '{}'".format(QCMS, QDepartment, QName, QRoom, QDOB)
            mycursor.execute(selectQuery)
            queryResult = mycursor.fetchall()
            for row_number, row_data in enumerate(queryResult):
                self.table.insertRow(row_number)
                for column_number, data in enumerate(row_data):
                    self.table.setItem(row_number,column_number,QTableWidgetItem(str(data)))
            
        except mc.Error as e:
            print("Error!")

    def insert():
        try:
            self.table.setRowCount(0)
            QCMS = self.lineCMS.text() + "%"
            QDepartment = self.lineDepartment.text() + "%"
            QName = self.lineName.text() + "%"
            QRoom = self.lineRoom.text() + "%"
            QDOB = self.lineDOB.text() + "%"

            mydb = mc.connect(host="localhost",user="root",password="",database="sakila")
            mycursor = mydb.cursor()
            insertQuery = "INSERT INTO Student Values({}, '{}', '{}', {}, '{}')".format(QCMS, QName, QDepartment, QRoom, QDOB)
            triggerQuery = "SELECT * FROM Student WHERE CMS like '{}' and Department like '{}' and Name like '{}' and RoomNo like '{}' and DateOfBirth like '{}'".format(QCMS, QDepartment, QName, QRoom, QDOB)
            mycursor.execute(insertQuery)
            insertResult = mycursor.fetchall()
            mycursor.execute(triggerQuery)
            triggerResult = mycursor.fetchall()
            for row_number, row_data in enumerate(triggerResult):
                self.table.insertRow(row_number)
                for column_number, data in enumerate(row_data):
                    self.table.setItem(row_number,column_number,QTableWidgetItem(str(data)))
            
        except mc.Error as e:
            print("Error!")

    def delete():
        try:
            self.table.setRowCount(0)
            QCMS = self.lineCMS.text() + "%"
            QDepartment = self.lineDepartment.text() + "%"
            QName = self.lineName.text() + "%"
            QRoom = self.lineRoom.text() + "%"
            QDOB = self.lineDOB.text() + "%"

            mydb = mc.connect(host="localhost",user="root",password="",database="sakila")
            mycursor = mydb.cursor()
            deleteQuery = "DELETE FROM Student WHERE CMS like '{}' and Department like '{}' and Name like '{}' and RoomNo like '{}' and DateOfBirth like '{}'".format(QCMS, QDepartment, QName, QRoom, QDOB)
            triggerQuery = "SELECT * FROM Student WHERE CMS like '{}' and Department like '{}' and Name like '{}' and RoomNo like '{}' and DateOfBirth like '{}'".format(QCMS, QDepartment, QName, QRoom, QDOB)
            mycursor.execute(deleteQuery)
            deleteResult = mycursor.fetchall()
            mycursor.execute(triggerQuery)
            triggerResult = mycursor.fetchall()
            for row_number, row_data in enumerate(triggerResult):
                self.table.insertRow(row_number)
                for column_number, data in enumerate(row_data):
                    self.table.setItem(row_number,column_number,QTableWidgetItem(str(data)))
            
        except mc.Error as e:
            print("Error!")

    def view():
        try:
            self.table.setRowCount(0)
            

            mydb = mc.connect(host="localhost",user="root",password="",database="sakila")
            mycursor = mydb.cursor()
            query = "SELECT * FROM Student"
            mycursor.execute(query)
            queryResult = mycursor.fetchall()
            
            
            for row_number, row_data in enumerate(queryResult):
                self.table.insertRow(row_number)
                for column_number, data in enumerate(row_data):
                    self.table.setItem(row_number,column_number,QTableWidgetItem(str(data)))
            
        except mc.Error as e:
            print("Error!")


    def clear():
        self.table.setRowCount(0)
    


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

Can't think of anything related to the situation I am in right now.想不出任何与我现在所处情况相关的事情。

My best guess is it's because you aren't using any threads in this program.我最好的猜测是因为你没有在这个程序中使用任何线程。

When you click a button, the main event loop that is processing the GUI events (mouse events, window updating) is locked up because it's working on your code for the button.当您单击一个按钮时,处理 GUI 事件(鼠标事件、窗口更新)的主事件循环被锁定,因为它正在处理您的按钮代码。 This makes the GUI appear to be frozen or crashed (not responding) because the event loop is busy with something else.这使得 GUI 看起来被冻结或崩溃(没有响应),因为事件循环正忙于其他事情。

There's some concepts needed to use PyQt5, Threading and Signals and Slots are two of the core concepts.使用 PyQt5 需要一些概念,Threading 和 Signals and Slots 是两个核心概念。

A Thread is code that runs in parallel with your main code, and shares the same code space so they have access to similar variables.线程是与您的主代码并行运行的代码,并共享相同的代码空间,因此它们可以访问相似的变量。

Signals and Slots are a way to pass information between the main thread and other threads that are being run.信号和槽是在主线程和正在运行的其他线程之间传递信息的一种方式。

In your code you will want to create a thread class like this:在您的代码中,您需要创建一个线程类,如下所示:

class ViewThread(QThread):
    # This is a signal when it is emitted it will send along data of type 'list' 
    query_finished_signal = pyqtSignal(list)
    
    def __init__(self):
        super().__init__()

    def run(self):
        # Here you would put the code to execute your SQL and 
        # get the data returned from the SQL fetch statement put in a 
        # list of lists called query_results.
        # NOTE: You'll need to make the instances of your SQL cursor here so 
        # everything is within the scope of this thread class.
        
        # Here we emit the signal, which will emit query_results to our 
        # connected slot.
        self.query_finished_signal.emit(query_results)
        self.finished.emit() 

Then in your Ui_MainWindow class you'll make your view method kick off the thread instead and then have a new method that I called set_view, which does only the operations the main event loop is responsible for updating.然后在你的Ui_MainWindow类中,你将使你的视图方法启动线程,然后有一个我称为 set_view 的新方法,它只执行主事件循环负责更新的操作。

def __init__(self):

    # vvv keep everything else just add this vvv
    
    #Create an instance of the custom QThread
    self.view_thread = ViewThread()
    
    #This is where we connect the signal, when it is emitted it will send the data to the method  self.set_view
    self.view_thread.query_finished_signal.connect(self.set_view) 

def view(self):
    try:      
        self.view_thread.start() 
    except mc.Error as e:
        print("Error!") 
        
def set_view(self, queryResult=None): #queryResult is a slot which will contain the data emitted from the signal connected to this method
    if queryResult:
        self.table.setRowCount(0)
        for row_number, row_data in enumerate(queryResult):
            self.table.insertRow(row_number)
            for column_number, data in enumerate(row_data):
                self.table.setItem(row_number,column_number,QTableWidgetItem(str(data)))

The point of all this is so your event loop only needs to update the table with the data it's given which is relatively fast, but it doesn't need to freeze the GUI while you go and collect the information.所有这一切的要点是,您的事件循环只需要用相对较快的给定数据更新表格,但它不需要在您收集信息时冻结 GUI。 Another note, GUI widgets cannot be altered by threads, so doing something like self.lineedit.setText("Hello") would not work in a thread, it needs to be done by the main thread.另一个注意事项,GUI 小部件不能被线程更改,所以像 self.lineedit.setText("Hello") 这样的事情在线程中不起作用,它需要由主线程完成。

NOTE: This code is meant to be an example only, not to be copy and pasted as working code.注意:此代码仅作为示例,不能复制和粘贴为工作代码。

I would suggest in your current GUI, click a button and if the GUI freezes up just wait it out and see if it eventually responds again.我建议在您当前的 GUI 中单击一个按钮,如果 GUI 冻结,只需等待它结束,看看它是否最终会再次响应。 That's how you'll know you need to implement this solution.这就是您知道需要实施此解决方案的方式。 I hope this helps:)我希望这有帮助:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM