4
votes

Suppose there is a Qml type called Test with foo property, it is implemented as follows: Test.qml

// Not necessarily QtObject, but derived from QObject
QtObject {
    // Not necessarily var/property, but must behave like property (i.e. be accessible using "<instance>.foo")
    property var foo
}

And used in the following way: main.qml

import "."

Test {
    id: _test
}

function baz() {
    var x = _test.foo;
    _test.foo = x;
}

What I want is to be notified every time foo property is accessed by getter or setter. For setter perhaps I can use fooChanged signal, but there is no such solution for getter. Also I could implement Test type as a C++ class with Q_PROPERTY macro and emit corresponding signals form property getter/setter, but I would really like to leave most of the code on Qml side.

Is there any other way to hook Qml properties access?

1
Interesting question. AFAIK there's no direct way to do that. Anyhow you can use QtObject to make the variable private and call a custom signal in the setter/getter, much like you proposed to do in C++ but fully implemented in QML. IMO the C++ version feels a little bit more polished. I guess it's a matter of taste. - BaCaRoZzo

1 Answers

6
votes

Ok, after some hours of googling, reading Qml and JS documentation I think I have finally found a solution. It involves some hacks since JS is not fully supported in Qml, but this solution still works. The main idea is to use JS defineProperty method in order to add properties to existing objects dynamically. Now my Test.qml file looks like this:

QtObject {
    // NOTE: .defineProperty does not correctly work for Qml objects, so JS object is used instead
    property var object: { return {}; }

    Component.onCompleted: {
        Object.defineProperty(
            object,
            "foo",
            {
                get: function () {
                    // getter handling here
                },
                set: function (value) {
                    // setter handling here
                }
            }
        );
    }
}

And in main.qml _test instance is declared as follows:

property alias _test: _testDeclaration.object

Test {
    id: _testDeclaration
}

Hope this answer will help other people.