Dlaczego dataChanged nie jest generowany po begininsertrow() i endinsertrow() w podklasie QAbstractListModel?

0

Pytanie

Pracowałem z podklasami QAbstractListModel, i nie sądzę, że rozumiem, jak poprawnie dodawać dane do modelu. Oto mój scenariusz i 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()

Spodziewam się, że za każdym razem, gdy upłynie czas timera, w modelu listy zostanie dodany nowy wiersz, i, w konsekwencji, model listy dataChanged sygnał musi być emituje. To Connections obsługi sygnału obiektu musi następnie wydrukować wiadomość. Ale wygląda na to, że to nigdy nie działa:

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

Jeśli oczywiście dodam self.dataChanged.emit() po endInsertRows(), a następnie, oczywiście, wykonywana jest procedura obsługi sygnału. Ale w całej dokumentacji i przykłady kodu, które ja widzę, tego się nie robi. Więc jaki jest właściwe podejście?

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

Najlepsza odpowiedź

2

dataChanged promieniuje (wyraźnie) w przypadku zmiany informacji o elemencie, przy wstawianiu wierszy, należy słuchaćrowsAboutToBeInserted lubrowsInserted sygnały:

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

Z drugiej strony, w Пайсайде nie QVariantzamiast tego należy zwrócić obiekty pythona, w przypadku zerowego mają postać należy zwrócić None (lub nic, co byłoby tym samym):

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

W innych językach

Ta strona jest w innych językach

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