使用QSqlQueryModel绑定QListView后,如何更新视图显示新增数据?
解决QSqlQueryModel绑定QListView后新增数据视图不更新的问题
这个问题我碰到过好多次,核心原因是QSqlQueryModel是只读模型,它不会自动监听数据库的变化。你把数据插入数据库后,模型里的数据集还是之前查询得到的旧数据,光发layoutChanged信号根本没用——因为模型本身根本没拿到新数据。另外你的代码里还有两个容易踩的小坑,我一起给你指出来:
先修正代码里的两个小问题
- 列索引错误:你执行的查询是
SELECT path FROM fichiers,结果集只有1列,列索引从0开始,但你设置了self.listview.setModelColumn(1),这会导致列表显示空内容,应该改成0。 - 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
相关产品推荐
相关产品推荐

