Q_PROPERTY and null QVariant



  • I think that this topic might be somehow relevant to my "old one":http://qt-project.org/forums/viewthread/10662/ .

    Here is code:
    @#include <QDebug>
    #include <QtCore>

    class Test : public QObject
    {
    Q_OBJECT
    Q_PROPERTY( bool test READ test WRITE setTest )

    bool test_;
    

    public:
    Test() :
    test_( true )
    {}

    bool test() const { return test_; }
    void setTest( bool test ) { test_ = test; }
    

    };

    int main( int argc, char* argv[] )
    {
    Test t;
    qDebug() << t.property( "test" ) << QVariant( QString() ).isNull();
    qDebug() << "set" << t.setProperty( "test", QVariant( QString() ) );
    qDebug() << "test" << t.test();
    qDebug() << "set" << t.setProperty( "test", QVariant( QString( "true" ) ) );
    qDebug() << "test" << t.test();
    qDebug() << "set" << t.setProperty( "test", QVariant( QString() ) );
    qDebug() << "test" << t.test();

    return 0;
    

    }

    #include "main.moc"
    @

    And here is output:
    @QVariant(bool, true) true
    set false
    test true
    set true
    test true
    set false
    test true @

    So assigning of a null QVariant is not successful. Why is it so?
    It would be very convenient to assign default-constructed values to properties instead.



  • setProperty would eventually call convert() on the QVariant. The conversion always fails for a null QVariant.



  • Thanks for the answer.
    Documentation says:

    bq. bool QVariant::convert ( Type t )
    Casts the variant to the requested type, t. If the cast cannot be done, the variant is cleared. Returns true if the current type of the variant was successfully cast; otherwise returns false.
    Warning: For historical reasons, converting a null QVariant results in a null value of the desired type (e.g., an empty string for QString) and a result of false.

    As I can understand from warning setProperty should set property to a null value of the desired type (and I understand it as a default-constructed value) when the QVariant is null.



  • I think the behavior is correct, because there is no such thing as a default constructed boolean. There is no standard value for a boolean (which is why you need to initialize it yourself explicitly).

    Considder this:
    @
    bool test;
    qDebug() << test;
    @
    Will the output be 'true' or 'false'? There is no way to tell.



  • Sorry I haven't wrote it before: I meant "these":http://qt-project.org/doc/qt-4.8/containers.html#default-constructed-values default-constructed values.



  • That documentation refers to the container classes. QVariant isn't such a container class.



  • Yes, I know. But "this":http://qt-project.org/doc/qt-4.8/qvariant.html#value says about default-constructed values as well.
    I think it's strange that QVariant::value() returnes default-constructed value if this QVariant is null but QObject::setProperty() returnes false. As I think either QVariant::value() should accept a pointer to a bool (as QVariant::toInt(bool *)) or QObject::setProperty() should set property to a default-constructed value if QVariant is null.



  • You are right, and it is weird that the QVariant documentation actually points to the documentation for the containers on this. I did not see that before. Sorry, I think you'd best talk with someone more into the details of QVariant than I am. Perhaps you can discuss this on IRC in the #qt-labs channel (freenode network).



  • Thanks for advice!



  • The Qt meta object system tries to convert the QVariant passed to setProperty() to the type of the property. So, what's called in the end is

    @
    QVariant v;
    bool ok = v.convert(QVariant::Bool);
    if(!ok)
    return false; // from setProperty()
    @

    Thus, if the QVariant passed in cannot be converted to the type of the property, the setProperty call will fail eventually. Also note that QVariant::convert() will return false in case you pass it a Null QVariant - which is the case here:

    @
    QVariant v1 = QString(); // null - convert fails

    QVariant v2 = QString(""); // NOT null, convert succeeds
    QVariant v3 = ""; // NOT null, convert succeeds
    @

    Alltogether, this is good™. You don't want to set a bool property from a QColor or a QVariantMap value, but get an error condition in theses cases.

    Also, QVariant::value() is not involved in this game at all. Thus, applying its documentation to setProperty() is invalid.

    References:

    • Implementation of QObject::setProperty()
    • Implementation of QMetaProperty::write()
    • API docs of QVariant::convert()


  • Thanks, Volker. I've read that "For historical reasons, converting a null QVariant results in a null value of the desired type (e.g., an empty string for QString) and a result of false." and now everything is clear.
    Though I don't like that historical reasons. They forced me to write another three lines of code :)


Log in to reply
 

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