[ fromfile: reflection.xml id: dynamicproperties ]
It is possible to load and store properties in a QObject without
having to define them on the class with Q_PROPERTY
.
Up to this point we have been dealing exclusively with properties that are defined with the Q_PROPERTY
macro.
These properties are known to the QMetaObject of that class,
and have a QMetaProperty defined.
All objects of the same class share the same metaObject
and thus have the same set
of meta properties.
Dynamic properties, on the other hand, are acquired at
runtime and are specific to the object that acquired them.
In other words, two objects of the same class have the same meta property list, but they can have different
lists of dynamic properties.
In Example 12.8, we define a class with a single
Q_PROPERTY
, which we name someString
.
Example 12.8. src/properties/dynamic/dynoprops.h
[ . . . . ] class DynoProps : public QObject { Q_OBJECT Q_PROPERTY(QString someString READ someString WRITE setSomeString); public: friend QDataStream& operator<<(QDataStream& os, const DynoProps& dp); friend QDataStream& operator>>(QDataStream& is, DynoProps& dp); QString someString() { return m_someString; } void setSomeString(QString ss) { m_someString = ss; } QString propsInventory(); private: QString m_someString; }; [ . . . . ]
In Example 12.9, the implementation of propsInventory()
shows a way to display fixed and dynamic properties.
The list of the fixed properties comes from the QMetaObject.
You can access property values using QMetaProperty::read()
or QObject::property()
.
The propertyCount()
function sets a limit for iteration through the QMetaProperty list.
The dynamic properties are not known by the QMetaObject.
Instead, you must use QObject methods.
You can iterate through the QList returned by QObject::dynamicPropertyNames()
for the list of names,
and use QObject::property()
to obtain values.
Example 12.9. src/properties/dynamic/dynoprops.cpp
[ . . . . ] QString DynoProps::propsInventory() { static const QMetaObject* meta = metaObject(); QStringList res; res << "Fixed Properties:"; QString propData; for(int i = 0; i < meta->propertyCount(); ++i) { res << QString("%1\t%2").arg(QString(meta->property(i).name())) .arg(meta->property(i).read(this).toString()); } res << "Dynamic Properties:"; foreach(QByteArray dpname, dynamicPropertyNames()) { res << QString("%1\t%2").arg(QString(dpname)) .arg(property(dpname).toString()); } return res.join("\n"); }
Aside from the slight awkwardness of accessing them, dynamic properties can be used in much the same way as
fixed properties; for example, they can be serialized.
The implementations of the two serialization operators are shown in Example
12.10
We employ a similar technique for serialization that we used for the propsInventory()
function.
Example 12.10. src/properties/dynamic/dynoprops.cpp
[ . . . . ] QDataStream& operator<< (QDataStream& os, const DynoProps& dp) { static const QMetaObject* meta = dp.metaObject(); for(int i = 0; i < meta->propertyCount(); ++i) { const char* name = meta->property(i).name(); os << QString::fromLocal8Bit(name) << dp.property(name); } qint32 N(dp.dynamicPropertyNames().count()); os << N; foreach(QByteArray propname, dp.dynamicPropertyNames()) { os << QString::fromLocal8Bit(propname) << dp.property(propname); } return os; } QDataStream& operator>> (QDataStream& is, DynoProps& dp) { static const QMetaObject* meta = dp.metaObject(); QString propname; QVariant propqv; int propcount(meta->propertyCount()); for(int i = 0; i < propcount; ++i) { is >> propname; is >> propqv; dp.setProperty(propname.toLocal8Bit(), propqv); } qint32 dpcount; is >> dpcount; for(int i = 0; i < dpcount; ++i) { is >> propname; is >> propqv; dp.setProperty(propname.toLocal8Bit(), propqv); } return is; }
Client code to demonstrate the use of dynamic properties is shown in Example 12.11.
Example 12.11. src/properties/dynamic/dynoprops-client.cpp
#include <QtCore> #include "dynoprops.h" int main() { QTextStream cout(stdout); DynoProps d1, d2; d1.setObjectName("d1"); d2.setObjectName("d2"); d1.setSomeString("Washington"); d1.setProperty("AcquiredProp", "StringValue"); d2.setProperty("intProp", 42); d2.setProperty("realProp", 3.14159); d2.setProperty("dateProp", QDate(2012, 01, 04)); cout << d1.propsInventory() << endl; cout << d2.propsInventory() << endl; cout << "\nNow we save both objects to a file, close the file,\n" "reopen the file, read the data from the file, and use it\n" "to create new DynoProps objects.\n" << endl; QFile file("file.dat"); file.open(QIODevice::WriteOnly); QDataStream out(&file); out << d1 << d2; file.close(); DynoProps nd1, nd2; file.open(QIODevice::ReadOnly); QDataStream in(&file); in >> nd1 >> nd2; file.close(); cout << "Here are the property inventories for the new objects.\n"; cout << nd1.propsInventory() << endl; cout << nd2.propsInventory() << endl; }
Example 12.12 shows the output of the program.
Example 12.12. src/properties/dynamic/output.txt
Fixed Properties: objectName d1 someString Washington Dynamic Properties: AcquiredProp StringValue Fixed Properties: objectName d2 someString Dynamic Properties: intProp 42 realProp 3.14159 dateProp 2012-01-04 Now we save both objects to a file, close the file, reopen the file, read the data from the file, and use it to create new DynoProps objects. Here are the property inventories for the new objects. Fixed Properties: objectName d1 someString Washington Dynamic Properties: AcquiredProp StringValue Fixed Properties: objectName d2 someString Dynamic Properties: intProp 42 realProp 3.14159 dateProp 2012-01-04
Generated: 2012-03-02 | © 2012 Alan Ezust and Paul Ezust. |