Weird binding behaviour: Unable to assign QObject* to XYZ_QMLTYPE_123



  • Hello,

    i just try to understand a problem I have with my code and maybe someone in the community can explain to me what is wrong with it, or if this is maybe even a bug in Qt.
    For this post I have to add some (simplified) code samples to somehow clearly explain what's it all about:

    At first I have a C++ class:
    @class MyClass : public QObject
    {
    Q_OBJECT
    Q_PROPERTY(QString name READ name WRITE setName NOTIFY signalNameChanged )
    Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY signalValueChanged)
    // some other properties and accessors skipped
    }@

    This class is then registered to QML:
    @qmlRegisterType<MyClass>("MyComponents, 1, 0, "MyClassBase");@

    Then I create a QML component "MyClass.qml" from this to be able to change some properties outside of the C++ code:
    @import QtQuick 1.1
    import MyComponents 1.0

    MyClassBase {
    value: 10
    // property bool valid // attention! new property!
    }@

    This component is afterwards used in some sort of config-file like this:
    @import QtQuick 1.1
    import components.base 1.0 // this is in respect to the file structure

    QtObject {
    property QtObject domain1: QtObject {
    id: domain1
    property MyClass binding1: MyClass { name: "prop1" }
    property MyClass binding2: MyClass { name: "prop2" }
    property MyClass binding3: MyClass { name: "prop3" }
    }
    property QtObject domain2: QtObject {
    id: domain2
    property MyClass binding1: MyClass { name: "prop4" }
    property MyClass binding2: MyClass { name: "prop5" }
    property MyClass binding3: MyClass { name: "prop6" }
    }
    }@

    Now it gets a bit tricky. :)
    I load this file through QDeclarativeComponent and set it as context property "myParams" in my main view.

    On the other side I have a component like this:
    @// "MyClassUser.qml"
    import QtQuick 1.1
    import components.base 1.0 // this is in respect to the file structure

    Item {
    property MyClass test1
    property MyClass test2
    property MyClass test3
    }@

    And in my view I use it like this:
    @// skipped imports, etc.
    Item {
    //... components
    MyClassUser {
    test1: myParams.domain1.binding1
    test2: myParams.domain2.binding1
    test3: myParams.domain2.binding3
    }
    //... more components
    }@

    Everything until here works like a charm!

    But if I try to add a new property to the MyClass QML Component like e.g. the boolean "valid" property commented in the component, the bindings in the last code snippet do not work anymore!
    The error message is then the one from the subject of this post:
    @Unable to assign QObject* to MyClass_QMLTYPE_2*@

    And here are some interesting side notes:
    If I do it as an assignment like:
    @Component.onCompleted: {
    test1 = myParams.domain1.binding1
    test2 = myParams.domain2.binding1
    test3 = myParams.domain2.binding3
    }@

    it still works!

    Also if I do a
    @console.log(myParams.domain2.binding3)
    @

    it logs that it is a @MyClass_QMLTYPE_2*@

    In fact the C++ class seems to have nothing to do with it, because if I change the MyClass component to be only QtObject derived instead of a MyClassBase the same thing happens. I may not assign any property at all.

    What do you think about this? Is this intended behaviour or is it a bug? Am I missing something? What could be the reason for this to happen?

    I hope I explained it in a way that everybody is able to understand the construct. Otherwise just ask for details.

    Greets and thanks in advance for any helpful input,
    Bernhard



  • This sounds like a bug.
    Does the same behaviour occur in QtQuick2.0?

    The fact that assignment works but the binding does not, suggests that somehow the type information / metatype lookup in the writeBinding codepath is wrong.

    As a mostly unrelated note, I'm not sure how your import components.base thing works (or how you're making the MyClass qml document available to the QML typesystem, which may have some impact -- for example, if it is loaded twice for some reason (instead of reusing the cached typedata, due to, say, import version mismatch or something), the type name will not match as it will be generated twice -- so assignments would fail even if the types are actually identical in layout).

    But since assignment works and binding fails, I think this is simply a bug (since the semantics of those should be identical, assuming the value returned/resolved by the binding expression is identical to the value assigned in the assignment case).

    Cheers,
    Chris.



  • At the moment I have no possibility to test the code agains QtQuick2.0.

    I'm not sure if the issue is related to "QTBUG-15641":https://bugreports.qt-project.org/browse/QTBUG-15641 but the solution described in the comment section also works in my case: replacing the usages of MyClass properties in MyClassUser.qml properties with variant properties.

    Altough it works I don't consider it a very clean solution as I strongly prefer the type aware version.

    The components.base thing are "installed modules":http://doc.qt.nokia.com/4.7-snapshot/qdeclarativemodules.html#installed-modules, very practical for larger projects to keep things sturctured. Everything is loaded through the same declarative engine, so that should'nt be the problem I think.

    If this is really related to the bug mentioned above I won't file it because it won't get fixed anyway before Qt5 (which is rather sad because not everyone is able to ship based on Qt5 at the moment 5.0 gets available).

    Thanks for your input.

    Have a nice weekend,
    Bernhard



  • Yes, the typed version is definitely better in my opinion too. I'd say that you're right, and that QTBUG-15641 is related (although I can't remember enough of the QtQuick1.x code to say why the cached typedata resolution could fail for inline components, or how that might be reproduced in your use-case).

    Unfortunately, we're focusing purely on Qt 5 at the moment, and that bug in QtQuick1.x is unlikely to get fixed soon.

    Another possibility is to use "property QtObject propname", instead of "property variant propname" -- at least then you get the typechecking for QObject-derivedness, so attempting to assign integers or strings etc will fail. It's not perfect, but it's better than nothing, I guess.

    Cheers,
    Chris.


Log in to reply
 

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