PyQt5跨文件调用登录校验函数时程序无报错意外退出
问题根因
程序无提示崩溃是PyQt特性和代码bug叠加导致:PyQt对槽函数内的未捕获异常默认处理是直接终止进程,不会像tkinter那样自动打印错误栈或弹出提示,你遇到的具体问题点如下:
- 你看到
print("im here")能正常输出,是因为报错点刚好在这行语句之后,异常触发后进程直接终止,后续所有代码(包括你在这行之后加的打印语句)都不会执行 - 数据库连接未初始化:sql.py里的
aMysql、mydb是connect()函数内定义的全局变量,但程序启动时从未主动调用sql.connect()初始化,第一次执行到aMysql.execute()时会直接触发NameError,而你写的try块仅捕获mysql.OperationalError,无法捕获NameError,异常直接抛入PyQt事件循环触发退出 - 缺失依赖导入:登录校验通过后调用了
logs.loginlog(),但sql.py中从未导入logs模块,就算数据库连接正常,走到这行也会触发NameError崩溃 - UI库混用冲突:PyQt程序中直接导入使用tkinter的
messagebox,两个GUI库的事件循环、底层资源逻辑冲突,就算前面逻辑正常,弹提示时也大概率导致无响应或崩溃 - 额外不规范点:PyQt的
clicked信号触发时会传递一个checked布尔参数,不是tkinter逻辑里的event参数,虽然不会直接崩溃,但属于错误写法
修复方案
- 程序启动阶段主动初始化数据库连接,给全局变量设置初始值避免NameError,扩大异常捕获范围覆盖所有数据库操作错误
- 删除所有tkinter相关导入和调用,提示框统一使用PyQt原生的
QMessageBox - 补全缺失的模块导入,未调试完成的日志逻辑可以先注释
- 槽函数入口增加异常捕获打印,避免PyQt吞掉错误信息
修复后代码示例
main.py
from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5.QtWidgets import QMessageBox import sys import sql # 启动时初始化数据库连接 sql.connect() class Ui_login(object): def setupUi(self, login): self.centralwidget = QtWidgets.QWidget(login) login.setCentralWidget(self.centralwidget) self.entry_user = QtWidgets.QLineEdit(self.centralwidget) self.entry_pass = QtWidgets.QLineEdit(self.centralwidget) self.entry_pass.setEchoMode(QtWidgets.QLineEdit.Password) self.button_login = QtWidgets.QPushButton(self.centralwidget) self.button_login.setObjectName("button_login") self.button_login.setText("登录") # 其余PyQt生成的布局、控件代码保持原样 self.button_login.clicked.connect(self.logincheck) # 适配PyQt clicked信号的参数,不需要传event def logincheck(self): try: _result = sql.logincheck(self.entry_user.text().lower(), self.entry_pass.text(),"main") _userlvl = 0 if type(_result) != bool: _userlvl = _result[2] _result = _result[0] print(_result) if _result == True: self.logindestroy(_userlvl) else: # 用PyQt原生提示框替代tkinter的messagebox QMessageBox.critical(None, "Banana: Error", "Invalid login credential") except Exception as e: # 打印异常信息避免PyQt吞错 print(f"登录逻辑报错: {repr(e)}") QMessageBox.critical(None, "运行错误", f"登录失败: {str(e)}") def logindestroy(self, userlvl): # 原有登录成功后的跳转逻辑保持不变 QMessageBox.information(None, "成功", f"登录成功,用户等级: {userlvl}") if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) login = QtWidgets.QMainWindow() ui = Ui_login() ui.setupUi(login) login.show() sys.exit(app.exec_())
sql.py
from configparser import ConfigParser import mysql.connector as mysql # 需要用日志功能就放开下面的导入,没开发完先注释 # import logs config = ConfigParser() config.read('cfg.ini') # 给全局变量设置初始值,避免NameError aMysql = None mydb = None def connect(): global aMysql,mydb mydb = mysql.connect( host=config.get("db","host"), user=config.get("db","user"), password=config.get("db","password"), database=config.get("db","database"), autocommit=True ) aMysql = mydb.cursor() def logincheck(e_username,e_password,_type): print("im here") global aMysql, mydb _sql = "SELECT * FROM users WHERE username = %s AND password = %s" _val = (e_username,e_password) try: # 先判断连接是否存在、是否正常,无效就重连 if not aMysql or not mydb.is_connected(): connect() aMysql.execute(_sql,_val) result = aMysql.fetchall() except Exception as e: print(f"数据库操作报错: {repr(e)}, 尝试重连") connect() aMysql.execute(_sql,_val) result = aMysql.fetchall() if len(result) >= 1: if result[0][0].lower() == e_username and result[0][1] == e_password: if _type == "main": # 确认logs模块导入完成再放开下面一行 # logs.loginlog(e_username,result[0][2]) pass return True,result[0][1],result[0][2] else: return False else: return False
调试PyQt程序时建议给所有槽函数加顶层异常捕获打印,PyQt默认吞掉事件循环内未捕获异常的特性,是这类无提示崩溃问题的核心诱因。
内容的提问来源于stack exchange,提问作者blurryrox
相关产品推荐
相关产品推荐

