[ fromfile: reflection.xml id: qproperty ]
The property facility gives us a choice of ways to access data members:
Directly, through the classic getters/setters (faster, more efficient)
Indirectly, through the QObject/QMetaObject interface (enables more reusable code)
You can specify read-only access to some properties, by leaving out a WRITE
function.
In addition, you can provide a NOTIFY
signal to emit when the property is changed.
In Example 12.3, we have a customer class with a Qt property defined for each data member.
The possible types for a property are those listed in QVariant::Type
, plus user types added with Q_DECLARE_METATYPE (see Section 12.6).
We have adopted the common practice of basing the name of each property that corresponds to a data member on the corresponding member name.
For the member m_DataItem
we named the corresponding property dataItem
.
Example 12.3. src/properties/customer-props.h
[ . . . . ] class Customer : public QObject { Q_OBJECT /* Each property declaration has the following syntax: Q_PROPERTY( type name READ getFunction [WRITE setFunction] [RESET resetFunction] [NOTIFY notifySignal] [DESIGNABLE bool] [SCRIPTABLE bool] [STORED bool] ) */ Q_PROPERTY( QString id READ getId WRITE setId NOTIFY valueChanged); Q_PROPERTY( QString name READ getName WRITE setName NOTIFY valueChanged); Q_PROPERTY( QString address READ getAddress WRITE setAddress NOTIFY addressChanged); Q_PROPERTY( QString phone READ getPhone WRITE setPhone NOTIFY phoneChanged); Q_PROPERTY( QDate dateEstablished READ getDateEstablished ); Q_PROPERTY( CustomerType type READ getType WRITE setType NOTIFY valueChanged); public: enum CustomerType { Corporate, Individual, Educational, Government }; Q_ENUMS( CustomerType ) ; explicit Customer(const QString name = QString(), QObject* parent = 0); QString getId() const { return m_id; } [ . . . . ] // Overloaded, so we can set the type 2 different ways: void setType(CustomerType newType); void setType(QString newType); signals: void addressChanged(QString newAddress); void phoneChanged(QString newPhone); void typeChanged(CustomerType type); void valueChanged(QString propertyName, QVariant newValue, QVariant oldValue = QVariant()); private: QString m_id, m_name, m_address, m_phone; QDate m_date; CustomerType m_type; }; [ . . . . ]
Macro required for moc to preprocess class. | |
Read-only property | |
The enum type definition must be in the same class definition as the Q_ENUMS macro. | |
Special macro to generate string-to-enum conversion functions; must be in same class. | |
Declared explicit because we do not want accidental conversions from QString to Customer. |
<include src="src/properties/customer-props.h" href="src/properties/customer-props.h" id="customerpropsh" mode="cpp"/>
Notice the enum CustomerType
defined in the public
section of the class Customer
.
Just above that definition, the Q_ENUMS
macro tells moc
to generate some functions for this property in the QMetaProperty to aid in string conversions for enum
values.
The setters and getters, defined in Example 12.4, are implemented in the usual way.
Example 12.4. src/properties/customer-props.cpp
[ . . . . ] Customer::Customer(const QString name, QObject* parent) :QObject(parent) { setObjectName(name); } void Customer::setId(const QString &newId) { if (newId != m_id) { QString oldId = m_id; m_id = newId; emit valueChanged("id", newId, oldId); } } [ . . . . ] void Customer::setType(CustomerType theType) { if (m_type != theType) { CustomerType oldType = m_type; m_type = theType; emit valueChanged("type", theType, oldType); } } /* Method for setting enum values from Strings. */ void Customer::setType(QString newType) { static const QMetaObject* meta = metaObject(); static int propindex = meta->indexOfProperty("type"); static const QMetaProperty mp = meta->property(propindex); QMetaEnum menum = mp.enumerator(); const char* ntyp = newType.toAscii().data(); CustomerType theType = static_cast<CustomerType>(menum.keyToValue(ntyp)); if (theType != m_type) { CustomerType oldType = m_type; m_type = theType; emit valueChanged("type", theType, oldType); } } QString Customer::getTypeString() const { return property("type").toString(); } [ . . . . ]
<include src="src/properties/customer-props.cpp" href="src/properties/customer-props.cpp" id="customerpropscpp" mode="cpp"/>
The implementation of the overloaded function setType(QString)
takes advantage of QMetaProperty's Q_ENUMS
macro to convert the QString to the proper enumerated value.
To obtain the correct QMetaProperty object for an enum
, you first get the QMetaObject and call indexOfProperty()
and property()
to find it.
QMetaProperty has a function called enumerator()
that returns an object we can use to convert strings to enums.
If the given QString argument does not match one of the enumerators, the keyToValue()
function returns –1
.
[90] Of course, this depends on how expensive creating the objects are and how often the function is called.
Generated: 2012-03-02 | © 2012 Alan Ezust and Paul Ezust. |