PyQt6+SQLite桌游收藏应用执行多类查询后脚本崩溃求助
问题根源与修复方案
核心崩溃原因
你的代码存在几个致命问题,直接导致组合操作崩溃:
- 静态方法误用:
MainWindow里的filter等方法加了@staticmethod却又定义了self参数,这完全错误。静态方法不属于类实例,调用时不会自动传入self,单个操作可能侥幸运行,但组合操作时会因参数不匹配、状态混乱直接崩溃。 - 硬编码操作主窗口UI:
FilterDialog直接操作main_window.table,这种全局式的对象引用极不稳定——主窗口UI状态更新后,引用可能失效,多个操作同时修改UI也会引发冲突。 - 数据更新逻辑分散:每个对话框直接操作表格,没有统一的数据源管理,筛选、排序后的数据仅存在于UI,后续操作无法基于当前状态处理,导致数据库与UI状态脱节。
关于单独类存放load_data的可行性
把load_data移到单独类是完全可行的,这属于数据层与UI层分离的合理思路,能让代码结构更清晰,但仅移动这个方法还不够,需要配合整体逻辑修复才能解决崩溃问题。
具体修复步骤
1. 修复静态方法问题
移除MainWindow中filter、sort等方法的@staticmethod装饰器,改为实例方法,同时把主窗口实例传递给对话框:
def filter(self): dialog = FilterDialog(self) # 将主窗口实例传入对话框 dialog.exec()
2. 对话框通过信号传递条件,由主窗口统一更新UI
禁止对话框直接操作主窗口表格,改为让对话框返回筛选/排序条件,由主窗口调用统一的load_data方法更新UI:
from PyQt6.QtWidgets import QDialog from PyQt6.QtCore import pyqtSignal class FilterDialog(QDialog): filterApplied = pyqtSignal(str, tuple) # 定义信号,传递筛选条件和参数 def __init__(self, parent=None): super().__init__(parent) # 你的对话框布局代码... def filter_game(self): where_clause = "" params = () if id_text: where_clause = "WHERE ID ? ?" params = (id_box_text, id_text) elif duration_text: where_clause = "WHERE Time ? ?" params = (duration_box_text, duration_text) elif released_text: where_clause = "WHERE Released ? ?" params = (released_box_text, released_text) self.filterApplied.emit(where_clause, params) self.accept()
主窗口中连接信号,调用load_data加载对应数据:
def filter(self): dialog = FilterDialog(self) dialog.filterApplied.connect(self.load_data) dialog.exec() # 修改load_data,支持传入筛选条件 def load_data(self, where_clause="", params=()): connection = sqlite3.connect("database.db") query = "SELECT * FROM my_games " + where_clause cursor = connection.cursor() # 参数化查询避免SQL注入 if where_clause: result = cursor.execute(query, params) else: result = cursor.execute(query) self.table.setRowCount(0) for row_number, row_data in enumerate(result): self.table.insertRow(row_number) for column_number, data in enumerate(row_data): self.table.setItem(row_number, column_number, QTableWidgetItem(str(data))) connection.close()
3. 统一数据更新入口
所有操作(添加、编辑、删除、筛选、排序)完成后,都调用主窗口的load_data方法刷新UI,而非各自直接操作表格。比如添加游戏后,直接调用self.load_data(),确保UI与数据库状态完全一致。
4. 修复SQL注入风险
替换当前的f-string拼接SQL方式,改用参数化查询(如代码中的?占位符),既避免注入攻击,也能减少语法错误。
总结
将load_data移到单独类是可行的,甚至可以把所有数据库操作封装到一个专门的GameDatabase类中,让UI层只负责交互与展示,数据层负责数据库操作,进一步优化代码结构。但核心是先解决静态方法误用和UI直接操作的问题,这才是崩溃的直接诱因。
内容的提问来源于stack exchange,提问作者Hans Hinnershitz
相关产品推荐
相关产品推荐

