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

向QAbstractListModel子类新增行时QML视图未更新如何解决

问题原因
  • 你使用的Python标准库threading.Timer运行在独立于Qt主线程的工作线程中,Qt的模型-视图更新机制强制要求所有修改模型、触发模型通知信号的操作必须在UI主线程执行。跨线程调用addPerson方法时,beginInsertRows和endInsertRows发出的更新信号无法被QML视图正确接收,因此界面不会刷新。
  • 代码中deletePerson方法还存在笔误:调用的是beginRemoveColumns,应该改为beginRemoveRows,否则删除操作也会出现异常。
修复方案

方案1:替换线程定时器为Qt原生QTimer(推荐,适配定时器场景)

Qt的QTimer默认运行在主线程,信号触发的槽函数也会在主线程执行,完美适配视图更新要求,修改model2.py代码如下:

from PyQt5.QtCore import QAbstractListModel, Qt, pyqtSignal, pyqtSlot, QModelIndex, QTimer
# 移除threading.Timer导入

class PersonModel(QAbstractListModel):

    NameRole = Qt.UserRole + 1
    AgeRole = Qt.UserRole + 2

    personChanged = pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)
        self.persons = [
            {'name': 'jon', 'age': 20},
            {'name': 'jane', 'age': 25}
        ]
        # 替换为Qt原生单触发定时器
        self.timer = QTimer(self)
        self.timer.setSingleShot(True)
        self.timer.timeout.connect(self.foo)
        self.timer.start(5000) # 单位为毫秒,5秒对应5000

    # 其余代码不变,修改deletePerson的笔误:
    @pyqtSlot(int)
    def deletePerson(self, row):
        # 将beginRemoveColumns改为beginRemoveRows
        self.beginRemoveRows(QModelIndex(), row, row)
        del self.persons[row]
        self.endRemoveRows()

方案2:子线程更新模型通用方案(适配设备异步返回数据场景)

如果你的实际业务是在独立子线程中接收设备返回的数据,不要直接在子线程调用模型修改方法,通过信号槽中转即可:

from PyQt5.QtCore import QAbstractListModel, Qt, pyqtSignal, pyqtSlot, QModelIndex
import threading
import time

class PersonModel(QAbstractListModel):
    # 定义新增数据的中转信号
    add_person_signal = pyqtSignal(str, int)

    NameRole = Qt.UserRole + 1
    AgeRole = Qt.UserRole + 2

    def __init__(self, parent=None):
        super().__init__(parent)
        self.persons = [
            {'name': 'jon', 'age': 20},
            {'name': 'jane', 'age': 25}
        ]
        # 绑定中转信号到模型新增方法,Qt会自动调度到主线程执行
        self.add_person_signal.connect(self.addPerson)
        # 模拟设备数据接收子线程
        threading.Thread(target=self.device_data_listener, daemon=True).start()

    def device_data_listener(self):
        # 模拟持续接收设备数据
        while True:
            time.sleep(5)
            # 子线程只发信号,不直接操作模型
            self.add_person_signal.emit('oops', 19)

    # 其余代码同之前修改后的版本

内容的提问来源于stack exchange,提问作者ning.wei

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 15:00:04