You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyQt6+SQLite桌游收藏应用执行多类查询后脚本崩溃求助

问题根源与修复方案

核心崩溃原因

你的代码存在几个致命问题,直接导致组合操作崩溃:

  1. 静态方法误用:MainWindow里的filter等方法加了@staticmethod却又定义了self参数,这完全错误。静态方法不属于类实例,调用时不会自动传入self,单个操作可能侥幸运行,但组合操作时会因参数不匹配、状态混乱直接崩溃。
  2. 硬编码操作主窗口UI:FilterDialog直接操作main_window.table,这种全局式的对象引用极不稳定——主窗口UI状态更新后,引用可能失效,多个操作同时修改UI也会引发冲突。
  3. 数据更新逻辑分散:每个对话框直接操作表格,没有统一的数据源管理,筛选、排序后的数据仅存在于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 05:26:20