【问题标题】:Why isn't dataChanged emitted after beginInsertRows() and endInsertRows() in a subclass of QAbstractListModel?为什么在 QAbstractListModel 的子类中 beginInsertRows() 和 endInsertRows() 之后没有发出 dataChanged?
【发布时间】:2021-12-26 08:54:59
【问题描述】:

我一直在处理 QAbstractListModel 的子类化问题,但我认为我不明白如何正确地将数据添加到模型中。这是我的脚本和 QML:

import QtQuick
import QtQuick.Controls

ApplicationWindow
{
    id: mainWindow
    visible: true
    title: qsTr("Sample Qt Quick application")
    width: 400
    height: 400
    color: "whitesmoke"

    Component.onCompleted: console.log("Component completed")

    Connections
    {
        target: main.custom_model
        function onDataChanged(topLeft, bottomRight, roles)
        {
            console.log("Custom model data changed")
        }
    }
    
}  // ApplicationWindow

import sys

from random import randint
from pathlib import Path
from PySide6.QtCore import Qt, QObject, QTimer, Property, QAbstractListModel, QModelIndex
from PySide6.QtGui import QGuiApplication
from PySide6.QtQml import QQmlApplicationEngine


class CustomModel(QAbstractListModel):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._my_items = []
        
        self._role1 = Qt.UserRole + 1
        self._role2 = Qt.UserRole + 2
        
        self._roles = {
            self._role1: b"role1",
            self._role2: b"role2"
        }
        
    def append_item(self, arg1, arg2):
        row_count = self.rowCount()
        self.beginInsertRows(QModelIndex(), row_count, row_count)

        self._my_items.append({
            self._roles[self._role1]: arg1,
            self._roles[self._role2]: arg2
        })

        self.endInsertRows()

    def rowCount(self, parent=QModelIndex()):
        """
        Required for subclasses of QAbstractListModels
        """
        return len(self._my_items)

    def data(self, index, role=Qt.DisplayRole):
        """
        Required for subclasses of QAbstractListModels
        """
        try:
            the_item = self._my_items[index.row()]
        except IndexError:
            return QVariant()

        if role in self._roles:
            key = self._roles[role]
            return the_item[key]

        return QVariant()

    def roleNames(self):
        return self._roles


class MainContextClass(QObject):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._model = CustomModel()

    def add_an_item(self):
        thing1 = randint(0, 9)
        thing2 = randint(0, 9)
        print("Adding {0} and {1}".format(thing1, thing2))
        self._model.append_item(thing1, thing2)

    @Property(QObject, constant=True)
    def custom_model(self):
        return self._model


def main():
    app = QGuiApplication(sys.argv)
    qml_app_engine = QQmlApplicationEngine()
    qml_context = qml_app_engine.rootContext()

    main_context = MainContextClass(parent=app)
    qml_context.setContextProperty("main", main_context)
    
    this_file_path = Path(__file__)
    main_qml_path = this_file_path.parent / 'example.qml'
    qml_app_engine.load(str(main_qml_path))

    timer = QTimer()
    timer.setInterval(1000)
    timer.setSingleShot(False)
    timer.timeout.connect(main_context.add_an_item)
    timer.start()

    sys.exit(app.exec())

    
if __name__ == '__main__':
    main()

我的期望是,每次计时器超时时,都会向 listmodel 添加一个新行,因此应该发出 listmodel 的 dataChanged 信号。然后Connections 对象的信号处理程序应该打印一条消息。但它似乎永远不会执行:

$ python example.py
qml: Component completed
Adding 7 and 0
Adding 8 and 5
Adding 4 and 0
...

如果我在endInsertRows() 之后显式添加self.dataChanged.emit(),那么显然信号处理程序会执行。但是在我看到的所有文档和示例代码中,这还没有完成。那么,正确的做法是什么?

【问题讨论】:

  • 那是发出rowsInserted 信号的时间,而不是dataChanged(这是现有项目中的数据发生变化的时间)。

标签: python python-3.x qml pyside6


【解决方案1】:

dataChanged 在项目的信息发生变化时(显式地)发出,在插入行时,您应该监听 rowsAboutToBeInsertedrowsInserted 信号:

Connections {
    target: main.custom_model

    function onRowsAboutToBeInserted(parent, first, last) {
        console.log("before", parent, first, last);
    }

    function onRowsInserted(parent, first, last) {
        console.log("after", parent, first, last);
        /* print data
        let index = main.custom_model.index(first, 0, parent);
        let data1 = main.custom_model.data(index, Qt.UserRole + 1);
        let data2 = main.custom_model.data(index, Qt.UserRole + 2);
        console.log(data1, data2);*/
    }
}

另一方面,在 PySide 中没有QVariant,相反,您必须返回 python 对象,在 null QVariant 的情况下,您必须返回 None(或不一样):

def data(self, index, role=Qt.DisplayRole):
    """
    Required for subclasses of QAbstractListModels
    """
    try:
        the_item = self._my_items[index.row()]
    except IndexError:
        return

    if role in self._roles:
        key = self._roles[role]
        return the_item[key]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-05
    • 1970-01-01
    • 1970-01-01
    • 2016-11-05
    • 1970-01-01
    • 2018-09-29
    • 1970-01-01
    相关资源
    最近更新 更多