What's the recommended way to expose read-only list-like properties to QML from C++ that can change spuriously?



  • Hi,

    I have two C++ classes A and B, both exposed to QML via qmlRegisterType(). A has a read-only list-like property "b" which exposes a number of B's. Internally, that property is stored as a QList<B>. I have a slot, updateB(), that can change that list. Each element of the list is assigned JavaScriptOwnership, and I never delete any of these elements myself.

    When my slot updateB changes the list, it emits the appropriate changed signal.

    In my QML, I'm binding to the "b" property using a Repeater.

    Here's my problem: When I change the b property via updateB(), I see a some strange effects, depending on how quickly updateB is called. Either old elements of B stay around, or I get crashes in various part of QQMlEngine or inside V8 because it seems to be accessing Bs that have been deleted (by the engine itself, not me, mind you).

    So my question is, what is the recommended way to expose a list-like property that can change spuriously? How should I handle ownership?

    Here's the code for class A:

    @
    class A : public QObject
    {
    Q_OBJECT

    Q_PROPERTY(QQmlListProperty<B> b READ b NOTIFY bChanged)
    

    public:
    explicit A(QObject *parent = 0);

    QQmlListProperty<B> b();
    

    public slots:
    void updateB();

    signals:
    void bChanged(const QQmlListProperty<B> &arg);

    private:
    static int count(QQmlListProperty<B> *property);
    static B *at(QQmlListProperty<B> *property, int index);

    QList<B *> _b;
    

    };
    @

    with the implementation

    @
    #include <QQmlEngine>

    A::A(QObject *parent) : QObject(parent)
    {
    updateB();
    }

    QQmlListProperty<B> A::b()
    {
    return QQmlListProperty<B>(this, &_b, &A::count, &A::at);
    }

    int A::count(QQmlListProperty<B> *property)
    {
    const QList<B *> *l = reinterpret_cast<const QList<B *> *>(property->data);
    return l->count();
    }

    B *A::at(QQmlListProperty<B> *property, int index)
    {
    const QList<B *> *l = reinterpret_cast<const QList<B *> *>(property->data);
    return (*l)[index];
    }

    void A::updateB()
    {
    _b.clear();

    for (int i = 0; i < 100; ++i)
    {
        B *b  = new B();
        QQmlEngine::setObjectOwnership(b, QQmlEngine::JavaScriptOwnership);
        _b << b;
    }
    emit bChanged(this->b());
    

    }
    @

    Any insight is greatly appreciated.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.