Pourquoi n'est-ce pas dataChanged émise après le beginInsertRows() et endInsertRows() dans une sous-classe de QAbstractListModel?

0

La question

J'ai été déconner avec le sous-classement QAbstractListModel, et je ne pense pas que je comprends comment ajouter des données au modèle. Voici mon script et le 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()

Mon attente est que chaque fois que le timer expire, une nouvelle ligne est ajoutée à la listmodel, et par conséquent, le listmodel de l' dataChanged le signal devrait obtenir émis. L' Connections de l'objet gestionnaire de signal devez imprimer un message. Mais il semble qu'il ne s'exécute jamais:

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

Si j'ai ajouter explicitement self.dataChanged.emit() après endInsertRows()puis, évidemment, le gestionnaire de signal s'exécute. Mais dans l'ensemble de la documentation et un exemple de code que je vois, ce n'est pas fait. Alors, quelle est la bonne approche?

pyside6 python python-3.x qml
2021-11-15 04:28:26
1

La meilleure réponse

2

dataChanged est émis (explicitement) lorsque les informations d'un élément change, lors de l'insertion de lignes, alors vous devez écouter l' rowsAboutToBeInserted ou rowsInserted signaux:

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);*/
    }
}

D'autre part, dans PySide il n'y a pas de QVariant, au lieu de cela, vous devez retourner des objets python, dans le cas de null QVariant vous devez retourner None (ou rien de ce qui est la même):

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]
2021-11-15 04:57:20

Dans d'autres langues

Cette page est dans d'autres langues

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................