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

如何在PyQt5中用QTableView展示SQLite数据并实时更新

PyQt5+SQLite:批量删除条目与线程安全数据更新方案

我来帮你搞定这两个问题,先看一次性删除所有条目的实现,再聊聊如何用QThread保证UI响应性:


一、一次性删除所有条目

这里有两种实用方案,根据你的数据量选择:

方案1:通过QSqlTableModel批量删除(适合小数据量)

利用模型自带的removeRows方法一次性删除所有行,因为你的模型设置了OnFieldChange的编辑策略,删除操作会自动提交到数据库,UI也会实时更新:

def deleteAllRows():
    # 从第0行开始,删除所有行
    model.removeRows(0, model.rowCount())
    # 如果编辑策略不是即时提交,需要额外调用 model.submitAll()

方案2:直接执行SQL语句(适合大数据量)

如果数据量很大,逐行删除效率很低,直接执行SQL DELETE语句会更快,之后手动刷新模型即可:

def deleteAllRows():
    query = QtSql.QSqlQuery()
    # 执行删除所有条目的SQL
    if query.exec_("DELETE FROM sportsmen"):
        # 刷新模型,让QTableView同步显示最新数据
        model.select()
    else:
        print(f"删除失败:{query.lastError().text()}")

二、验证QThread与SQLite结合的响应性

⚠️ 重要提醒:QSqlTableModel是线程不安全的,绝对不能在子线程中直接操作模型!正确的做法是:子线程只负责执行纯SQL操作(比如批量插入、更新),完成后通过信号通知主线程刷新模型,这样UI就不会被阻塞。

下面是修改后的完整代码,包含批量删除按钮、后台批量插入任务(用来验证响应性):

import sys
from PyQt5 import QtCore, QtWidgets, QtSql

class DBWorker(QtCore.QThread):
    # 定义信号,任务完成后通知主线程
    taskFinished = QtCore.pyqtSignal()

    def run(self):
        # 子线程中执行批量插入操作(模拟耗时任务)
        query = QtSql.QSqlQuery()
        query.prepare("INSERT INTO sportsmen (first_name, last_name) VALUES (?, ?)")
        # 批量插入1000条数据,模拟耗时操作
        for i in range(1000):
            query.addBindValue(f"First_{i}")
            query.addBindValue(f"Last_{i}")
            query.exec_()
        # 任务完成,发出信号
        self.taskFinished.emit()

def initializeModel(model):
    model.setTable('sportsmen')
    model.setEditStrategy(QtSql.QSqlTableModel.OnFieldChange)
    model.select()
    model.setHeaderData(0, QtCore.Qt.Horizontal, "ID")
    model.setHeaderData(1, QtCore.Qt.Horizontal, "First name")
    model.setHeaderData(2, QtCore.Qt.Horizontal, "Last name")

def createView(title, model):
    view = QtWidgets.QTableView()
    view.setModel(model)
    view.setWindowTitle(title)
    return view

def addrow():
    ret = model.insertRows(model.rowCount(), 1)
    print(f"添加行结果:{ret}")

def editrow():
    model.setData(model.index(1, 1), "LEL")

def deleteAllRows():
    # 这里用方案2,适合大数据量
    query = QtSql.QSqlQuery()
    if query.exec_("DELETE FROM sportsmen"):
        model.select()
        print("所有条目已删除")
    else:
        print(f"删除失败:{query.lastError().text()}")

def startBatchInsert():
    # 启动后台线程执行批量插入
    worker = DBWorker()
    worker.taskFinished.connect(lambda: model.select())  # 完成后刷新模型
    worker.start()
    print("后台批量插入任务已启动,UI可正常操作")

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    db = QtSql.QSqlDatabase.addDatabase('QSQLITE')
    db.setDatabaseName('sports.db')
    # 确保数据库连接成功
    if not db.open():
        print(f"数据库连接失败:{db.lastError().text()}")
        sys.exit(1)
    
    # 初始化表(如果不存在的话)
    query = QtSql.QSqlQuery()
    query.exec_("""
        CREATE TABLE IF NOT EXISTS sportsmen (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            first_name TEXT,
            last_name TEXT
        )
    """)

    model = QtSql.QSqlTableModel()
    initializeModel(model)
    view1 = createView("Table Model (View 1)", model)

    dialog = QtWidgets.QDialog()
    layout = QtWidgets.QVBoxLayout()
    layout.addWidget(view1)

    # 添加行按钮
    addBtn = QtWidgets.QPushButton("Add a row")
    addBtn.clicked.connect(addrow)
    layout.addWidget(addBtn)

    # 编辑行按钮
    editBtn = QtWidgets.QPushButton("Edit a row")
    editBtn.clicked.connect(editrow)
    layout.addWidget(editBtn)

    # 删除单行按钮
    delBtn = QtWidgets.QPushButton("Delete selected row")
    delBtn.clicked.connect(lambda: model.removeRow(view1.currentIndex().row()))
    layout.addWidget(delBtn)

    # 删除所有行按钮
    delAllBtn = QtWidgets.QPushButton("Delete ALL rows")
    delAllBtn.clicked.connect(deleteAllRows)
    layout.addWidget(delAllBtn)

    # 后台批量插入按钮(验证响应性)
    batchInsertBtn = QtWidgets.QPushButton("Start batch insert (1000 rows)")
    batchInsertBtn.clicked.connect(startBatchInsert)
    layout.addWidget(batchInsertBtn)

    dialog.setLayout(layout)
    dialog.setWindowTitle("Database Demo")
    dialog.show()
    sys.exit(app.exec_())

响应性验证方法:

点击「Start batch insert (1000 rows)」按钮后,你可以尝试拖动窗口、点击其他按钮(比如删除行),UI依然能正常响应,说明子线程的耗时操作没有阻塞主线程。这是因为所有模型操作都在主线程完成,子线程只负责执行SQL,完全符合Qt的线程安全要求。


内容的提问来源于stack exchange,提问作者n00p

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:11:32