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

使用QSqlQueryModel绑定QListView后,如何更新视图显示新增数据?

解决QSqlQueryModel绑定QListView后新增数据视图不更新的问题

这个问题我碰到过好多次,核心原因是QSqlQueryModel是只读模型,它不会自动监听数据库的变化。你把数据插入数据库后,模型里的数据集还是之前查询得到的旧数据,光发layoutChanged信号根本没用——因为模型本身根本没拿到新数据。另外你的代码里还有两个容易踩的小坑,我一起给你指出来:

先修正代码里的两个小问题

  1. 列索引错误:你执行的查询是SELECT path FROM fichiers,结果集只有1列,列索引从0开始,但你设置了self.listview.setModelColumn(1),这会导致列表显示空内容,应该改成0。
  2. SQL注入风险:直接用字符串拼接生成INSERT语句非常危险,如果用户选择的路径里包含单引号,会直接导致SQL执行失败,甚至被注入恶意代码,必须用参数绑定的方式。

修复方案一:重新执行查询刷新模型

这是最简单直接的方式,插入数据后重新调用setQuery,让模型从数据库重新获取最新数据:

class MainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        self.setGeometry(900,180,800,600)
        self.setWindowTitle("Media Display")
        self.setWindowIcon(QIcon('favicon.png'))
        self.model = QSqlQueryModel()
        # 把查询逻辑抽出来,方便复用
        self.refresh_model()
        self.listview = QListView()
        self.listview.setModel(self.model)
        self.listview.setModelColumn(0)  # 修正列索引为0

    def refresh_model(self):
        self.model.setQuery("SELECT path FROM fichiers")

    def addImage(self):
        fichier_base, _ = QFileDialog.getOpenFileName(self, 'select video', QDir.homePath(),"Images (*.png *.xpm *.jpg *.jpeg)")
        if not fichier_base:  # 处理用户取消选择的情况
            return
        query = QSqlQuery()
        # 使用参数绑定避免SQL注入
        query.prepare("INSERT INTO fichiers (path) VALUES (:path)")
        query.bindValue(":path", fichier_base)
        if query.exec():
            print('Added path:', fichier_base)
            # 重新查询刷新模型
            self.refresh_model()
        else:
            print('Insert failed:', query.lastError().text())

修复方案二:改用QSqlTableModel(更推荐)

如果你的场景需要更灵活的模型操作(比如编辑、自动同步),QSqlTableModel是更好的选择——它不需要手动写SELECT语句,调用select()就能轻松刷新数据:

class MainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        self.setGeometry(900,180,800,600)
        self.setWindowTitle("Media Display")
        self.setWindowIcon(QIcon('favicon.png'))
        # 改用QSqlTableModel
        self.model = QSqlTableModel()
        self.model.setTable("fichiers")
        self.model.select()  # 加载初始数据
        self.listview = QListView()
        self.listview.setModel(self.model)
        # 通过字段名指定列,比索引更可靠
        self.listview.setModelColumn(self.model.fieldIndex("path"))

    def addImage(self):
        fichier_base, _ = QFileDialog.getOpenFileName(self, 'select video', QDir.homePath(),"Images (*.png *.xpm *.jpg *.jpeg)")
        if not fichier_base:
            return
        # 用模型的内置方法插入数据
        row = self.model.rowCount()
        self.model.insertRow(row)
        self.model.setData(self.model.index(row, self.model.fieldIndex("path")), fichier_base)
        if self.model.submitAll():
            print('Added path:', fichier_base)
            # 提交后自动同步,也可以手动调用self.model.select()确保数据最新
        else:
            print('Insert failed:', self.model.lastError().text())
            self.model.revertAll()  # 插入失败回滚

为什么layoutChanged.emit()没用?

layoutChanged信号是告诉视图「模型的布局(比如列数、行数结构)变了」,但你的模型里的实际数据并没有更新,所以视图还是会显示旧内容。只有当模型的数据集本身更新后,视图才会同步显示新数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 07:48:18