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. -
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.
-
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).
-
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 failsQVariant 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 :)