diff options
Diffstat (limited to 'doc/src/declarative/qmlforcpp.qdoc')
-rw-r--r-- | doc/src/declarative/qmlforcpp.qdoc | 670 |
1 files changed, 670 insertions, 0 deletions
diff --git a/doc/src/declarative/qmlforcpp.qdoc b/doc/src/declarative/qmlforcpp.qdoc new file mode 100644 index 0000000..5838df7 --- /dev/null +++ b/doc/src/declarative/qmlforcpp.qdoc @@ -0,0 +1,670 @@ +/*! + \page qmlforcpp.html + \target qmlforcpp + \title QML for C++ Programmers + + This page describes the QML format and how to use and extend it from C++. + + The QML syntax declaratively describes how to construct an in memory + object tree. QML is usually used to describe a visual scene graph + but it is not conceptually limited to this: the QML format is an abstract + description of \bold any object tree. + + QML also includes property bindings. Bindings are ECMAScript expressions + of a properties value. Whenever the value of the expression changes - + either for the first time at startup or subsequently thereafter - the + property is automatically updated with the new value. + + \section1 Loading and using QML Files + + QmlComponent is used to load a QML file and to create object instances. + + In QML a component is the unit of instantiation, and the most basic unit + of scope. A component is like a template for how to construct an object + tree. One component can create multiple instances of this tree, but the + template remains constant. + + The following code uses the C++ interface to create 100 red rectangles + based on a simple declarative component description. + + \code + QmlEngine engine; + QmlComponent redRectangle(&engine, "Rectangle { color: \"red\"; width: 100; height: 100 }"); + for (int ii = 0; ii < 100; ++ii) { + QObject *rectangle = redRectangle.create(); + // ... do something with the rectangle ... + } + \endcode + + Each independent file describes a QML component, but it is also possible to + create sub-components within a QML file as will be shown later. + + \section1 QML Format 101 + + This is some sample QML code. + + \code + Image { + id: myRect + x: 10 + y: 10 + width: 100 + height: 100 + source: "background.png" + + Text { + height: 50 + width: 100 + color: "white" + font.fontSize: 16 + text: "Hello world!" + } + } + \endcode + + The QML snippet shown above instantiates one \c Image instance and one + \c Text instance and sets properties on both. \bold Everything in QML + ultimately comes down to either instantiating an object instance, or + assigning a property a value. QML relies heavily on Qt's meta object system + and can only instantiate classes that derive from QObject. + + In the above example, each property is placed on its own line. You can + also place multiple properties on one line by separating them with a + semi-colon. The code below is equivalent to the example above. + + \code + Image { + id: myRect + x: 10; y: 10; width: 100; height: 100 + source: "background.png" + Text { height: 50; width: 100; color: "white"; font.fontSize: 16; text: "Hello world!" } + } + \endcode + + QML can set properties that are more complex than just simple types like + integers and strings. Properties can be object pointers or Qt interface + pointers or even lists of object or Qt interface pointers! QML is typesafe, + and will ensure that only the valid types are assigned to properties. + + Assigning an object to a property is as simple as assigning a basic + integer. Attempting to assign an object to a property when type coercian + fails will produce an error. The following shows an example of valid and of + invalid QML and the corresponding C++ classes. + + \table + \row \o + \code + class Image : public QObject + { + ... + Q_PROPERTY(ImageFilter *filter READ filter WRITE setFilter) + }; + + class ImageFilter : public QObject + { + ... + }; + \endcode + \o \code + // OK + Image { + filter: ImageFilter {} + } + + // NOT OK: Image cannot be cast into ImageFilter + Image { + filter: Image {} + } + \endcode + \endtable + + Classes can also define an optional default property. The default property + is used for assignment if no explicit property has been specified. + Any object property can be the default, even complex properties like lists + of objects. The default property of the \c Rect class is the \c children + property, a list of \c Item's. In the following example, as both \c Image + and \c Text inherit from \c Item the \c Image and \c Text instances are + added to the parent's \c children property. + + \code + Rectangle { + Image {} + Text {} + } + \endcode + + Properties that return read-only object pointers can be used recursively. + This can be used, for example, to group properties together. The + \c Text element has a \c font property that returns an object with a number + of sub-properties such as \c family, \c bold, \c italic and \c size. + QML makes it easy to interact with these grouped properties, as the + following shows - everything you would expect to work, just does. + + \table + \row \o + \code + class Text : public ... + { + ... + Q_PROPERTY(Font *font READ font); + }; + class Font : public QObject + { + ... + Q_PROPERTY(QString family READ family WRITE setFamily); + Q_PROPERTY(bool bold READ bold WRITE setBold); + Q_PROPERTY(bool italic READ italic WRITE setItalic); + Q_PROPERTY(int size READ size WRITE setSize); + }; + \endcode + \o + \code + Text { + font.family: "helvetica" + font.pointSize: 12 + font { + bold: true + italic: true + } + } + \endcode + \endtable + + \section1 Defining QML Types + + The QML engine has no intrinsic knowledge of any class types. Instead + the programmer must define the C++ types, their corresponding QML + name, library namespace, and version availability. + + \code + #define QML_DECLARE_TYPE(T) + #define QML_DEFINE_TYPE(URI,VMAJ,VFROM,VTO,QmlName,T) + \endcode + + Adding these macros to your library or executable automatically makes the + C++ type \a T available from the declarative markup language under the + name \a QmlName. Of course there's nothing stopping you using the same + name for both the C++ and the QML name! + Any type can be added to the QML engine using these macros. The only + requirements are that \a T inherits QObject, is not abstract, + and that it has a default constructor. + + \section1 Property Binding + + Assigning constant values and trees to properties will only get you so + far. Property binding allows a property's value to be dependant on the + value of other properties and data. Whenever these dependencies change, + the property's value is automatically updated. + + Property bindings are ECMAScript expressions and can be applied to any + object property. C++ classes don't have to do anything special to get + binding support other than define appropriate properties. When a non-literal + property assignment appears in a QML file, it is automatically treated as a + property binding. + + Here's a simple example that stacks a red, blue and green rectangle. + Bindings are used to ensure that the height of each is kept equal to it's + parent's. Were the root rectangle's height property to change, the child + rectangles height would be updated automatically. + + \code + Rectangle { + color: "red" + width: 100 + Rectangle { + color: "blue" + width: 50 + height: parent.height + Rectangle { + color: "green" + width: 25 + height: parent.height + } + } + } + \endcode + + Binding expressions execute in a context. A context behaves as a scope and + defines how the expression resolves property and variable names. Although + the two expressions in the last example are the same, the value of \c parent + resolves differently because each executes in a different context. Although + QML generally takes care of everything for the programmer, a thorough + understanding of bind contexts is important in some of the more complex QML + structures. + + Every expression is executed in a bind context, encapsulated by the + QmlContext C++ class. As covered in the class documentation, a + bind context contains a map of names to values, and a list of default + objects. When resolving a name, the name to value map is searched first. + If the name cannot be found, the default object's are iterated in turn and + the context attempts to resolve the name as a property of one of the default + objects. + + There are generally two contexts involved in the execution of a binding. + The first is the "object context" - a bind context associated with the + closest instantiated object and containing just one default object, and + that's instantiated object itself. The effect of the object + context is pretty simple - names in the binding expression resolve to + properties on the object first. It is important to note - particularly in + the case of grouped properties - the object context is that of the + instantiated object, the consequences of which are shown below. + + \code + // OK // NOT OK + Text { Text { + font { font { + bold: font.italic bold: italic + } } + } } + \endcode + + The second context is the "component context". Each QML component (and + consequently each QML file) is created in its own unique binding context. + Like the object context, the component context contains just one default + object - but in this case it is the component's root object. An example + will illustrate best - the resultant text will read "background.png". + + \code + Image { + source: "background.png" + Text { + text: source + } + } + \endcode + + If the name is not found in either of these contexts, the context heirarchy + is searched parent-by-parent until the name is either found, or the + heirarchy is exhausted. + + The first property binding example shown involved fixing the height of three + rectangles. It did this by fixing the height of each rectangle to its + parent, rather than fixing them all to a single common point. Here's the + example rewritten to do just that. + + \code + Rectangle { + color: "red" + width: 100 + Rectangle { + color: "blue" + width: 50 + height: parent.height + Rectangle { + color: "green" + width: 25 + height: parent.parent.height + } + } + } + \endcode + + Clearly this sort of fragile relationship is undesirable and unmanageable - + moving the green rectangle to be a sibling of the blue or introducing a + further rectangle between the two would break the example. + + To address this problem, QML includes a way to directly reference any object + within a component (or parent component for that matter), called "ids". + Developers assign an object an id, and can then reference it directly by + name. Developers assign an object an id by setting the special \c id + property. Every object automatically has this magical property (if the + object also has an actual property called \c id, that gets set too). As + an id allows an object to be referenced directly, it must be unique within + a component. By convention, id's should start with an uppercase letter. + + \code + Rectangle { + id: Root + color: "red" + width: GreenRect.width + 75 + height: Root.height + Rectangle { + color: "blue" + width: GreenRect.width + 25 + Rectangle { + id: GreenRect + color: "green" + width: 25 + height: Root.height + } + } + } + \endcode + + To relate id's back to QmlContext, id's exist as properties on the + component context. + + Bind expressions can reference any object property. The QML bind engine + relies on the presence of the NOTIFY signal in the Q_PROPERTY declaration + on a class to alert it that a property's value has changed. If this is + omitted, the bind expression can still access the property's value, but + the expression will not be updated if the value changes. The following is + an example of a QML friendly property declaration. + + \code + class Example : public QObject + { + Q_OBJECT + Q_PROPERTY(int sample READ sample WRITE setSample NOTIFY sampleChanged) + public: + int sample() const; + void setSample(int); + signals: + void sampleChanged(int); + }; + \endcode + + While generally no changes are needed to a C++ class to use property + binding, sometimes more advanced interaction between the binding engine and + an object is desirable. To facilitate this, there is a special exception + in the bind engine for allowing an object to access the binding directly. + + If a binding is assigned to a property with a type of QmlBindableValue + pointer (ie. QmlBindableValue *), each time the binding value changes, + a QmlBindableValue instance is assigned to that property. The + QmlBindableValue instance allows the object to read the binding and to + evaluate the binding's current value. + + \section1 Signal Properties + + In addition to reading and writing regular properties, QML allows you to + easily associate ECMAScript with signals. Consider the following example, + in which Button is a made-up type with a clicked() signal. + + \code + Button { + text: "Hello world!" + onClicked: print(text) + } + \endcode + + Clicking on the button causes "Hello world!" to be printed to the console + (or lost forever if you're running Windows). + + Like properties, signals automatically become available in QML without + any additional work. As illustrated signals are mapped into QML as special + "signal properties", using the name "on<Signal Name>" where the first + character of the signal's name is uppercased. If more than one signal of + the same name is exist on a class, only the first is available (see the + \l Connection element for more general signal connections). + + An important observation to make here is the lack of braces. While both + property bindings and signal properties involve executing ECMAScript code, + property bindings dynamically update the property value (hence the braces), + whereas with signal properties the constant script "value" is actually + assigned to the signal property. Trying to bind a value to a signal + property will not work! + + Signal parameters are also available to the executing script, as shown + below, as long as you remember to name the parameters of your signal + in C++ (see QMetaMethod::parameterNames()). + + \table + \row \o + \code + Example { + onDoSomething: for(var ii = 0; ii < count; ++ii) + print(message) + } + \endcode + \o + \code + class Example : public QObject + { + Q_OBJECT + signals: + void doSomething(int count, const QString &message); + }; + \endcode + \endtable + + Just like property bindings, signal scripts are executed in a context. The + signal script context is identical in scope to the "object context" under + property binding, with the exception that it has the signal parameters + bound in. + + In addition to scripts, it is possible to assign objects to signal properties. + This automatically connects the signal to the object's default method. A + default method is defined just like a default property, though the special + "DefaultMethod" class info. + + \code + Q_CLASSINFO("DefaultMethod", "myMethod(int)"); + \endcode + + This is useful in achieving several use cases, like that below which moves + the button when it is clicked. + + \code + Button { + id: MyButton + onClicked: NumberAnimation { + target: MyButton + property: "x" + to: 100 + } + } + \endcode + + If the class itself actually defines a property called "on<Name>", this will + be assigned the string value and the signal handling behaviour will be + disabled. + + \section1 Attached Properties + + Attached properties allow unrelated types to annotate another type with some + additional properties. Some APIs or operations are inherintly imperative, + and attached properties help out when translating these APIs into the + declarative QML language. + + Qt's QGridLayout is one such example. + + \code + QGridLayout { + QLabel { + QGridLayout.row: 0 + QGridLayout.column: 0 + text: "Name:" + } + QLineEdit { + QGridLayout.row: 0 + QGridLayout.column: 1 + } + + QLabel { + QGridLayout.row: 1 + QGridLayout.column: 0 + text: "Occupation:" + } + QLineEdit { + QGridLayout.row: 1 + QGridLayout.column: 1 + } + } + \endcode + + Attached properties are identified by the use of a type name, in the + case shown \c QGridLayout, as a grouped property specifier. To prevent + ambiguity with actual class instantiations, attached properties must + always be specified to include a period but can otherwise be used just like + regular properties. + + C++ types provide attached properties by declaring the public function \c qmlAttachedProperties like this example. + + \table + \row \o + \code + static QObject *Type::qmlAttachedProperties(QObject *); + \endcode + \o + \code + class Example : public QObject + { + Q_OBJECT + public: + static QObject *qmlAttachedProperties(QObject *); + }; + \endcode + \endtable + + When an attached property is accessed, the QML engine will call this method + to create an attachment object, passing in the object instance that the + attached property applies to. The attachment object should define all + the attached properties, and is generally parented to the provided object + instance to avoid memory leaks. The QML engine does not saves this object, + so it is not necessary for the attached property function to ensure that + multiple calls for the same instance object return the same attached object. + + While conceptually simple, implementing an attachment object is not quite + so easy. The \c qmlAttachedProperties function is static - attachment + objects are not associated with any particular instance. How the values + of the attached properties apply to the behaviour they are controlling is + entirely implementation dependent. An additional consequence of this is + that \bold any object can attach \bold any attached property. The following is + perfectly valid, although the attached property has no actual effect: + + \code + FancyGridLayout { + Item { + Button { + QGridLayout.row: 1 + } + } + } + \endcode + + The property has no effect because the (made-up) FancyGridLayout type defines the meaning + of the \c row attached property only to apply to its direct children. It + is possible that other types may have attached properties that affect + objects that aren't their direct children. + + Attached properties are an advanced feature that should be used with + caution. + + \note We may implement a convenience wrapper that makes using attached + properties easier for the common "attach to children" case. + + \section1 Property Value Sources + + Intrinsically, the QML engine can assign a property either a static value, + such as a number or an object tree, or a property binding. It is possible for + advanced users to extend the engine to assign other "types" of values to + properties. These "types" are known as property value sources. + + Consider the following example. + + \code + Rectangle { + x: NumberAnimation { running: true; repeat; true; from: 0; to: 100; } + } + \endcode + + Here the \c x property of the rectangle will be animated from 0 to 100. + To support this, the NumberAnimation class inherits the + QmlPropertyValueSource class. If a type inherits this class and is assigned + to a property for which type assignment would otherwise fail (ie. the + property itself doesn't have a type of QmlPropertyValueSource *), the QML + engine will automatically set the property as the target of the value + source. + + \section1 Parser Status + + Generally using QML is a breeze - you implement your classes in C++, add + the appropriate properties, signals and slots and off you go. The QML + engine takes care of instantiating your classes and setting the properties + and everything works fine. + + However, sometimes it is helpful to know a little more about the status of + the QML parser. For example, it might be beneficial from a performance + standpoint to delay initializing some data structures until all the + properties have been set. + + To assist with this, the QML engine defines an interface class called + QmlParserStatus. The interface defines a number of virtual methods that are + invoked at various stages of the component instantiation. To receive + these notifications, all a class has to do is to inherit the interface, and + notify the Qt meta system using the Q_INTERFACES() macro. For example, + + \code + class Example : public QObject, public QmlParserStatus + { + Q_OBJECT + Q_INTERFACES(QmlParserStatus) + public: + virtual void componentComplete() + { + qDebug() << "Woohoo! Now to do my costly initialization"; + } + }; + \endcode + + \section1 Extended Type Definitions + + QML requires that types have the appropriate properties and signals to + work well within the declarative environment. In the case of existing + types, it is sometimes necessary to add signals, properties or slots to a + target class to make it more QML friendly but the original type cannot be + modified. For these cases, the QML engine supports extended type + definitions. + + An extended type definition allows the programmer to supply an additional + type - known as the extension type - when registering the target class + whose properties, signals and slots are transparently merged with the + original target class when used from within QML. + + An extension class is a regular QObject, with a constructor that takes a + QObject pointer. When needed (extension classes are delay created + until the first extension attribute is accessed) the extension + class is created and the target object is passed in as the parent. When + an extension attribute on the original is accessed, the appropriate signal, + property or slots on the extension object is used instead. + + When an extended type is installed, the + \code + #define QML_DEFINE_EXTENDED_TYPE(T,QmlName,ExtendedTypeName) + \endcode + macro should be used instead of the regular \c QML_DEFINE_TYPE. + + This example shows the addition of a read-only \c textLength property to + QLabel being implemented as an extension. + + \table + \row + \o + \code + class QLabelExtension : public QObject + { + Q_OBJECT + Q_PROPERTY(int textLength READ textLength) + public: + QWidgetExtension(QObject *parent) : QObject(parent) {} + int textLength() const { + return static_cast<QLabel *>(parent())->text().count(); + } + }; + QML_DEFINE_EXTENDED_TYPE(QLabel,QLabel,QLabelExtension); + \endcode + \o + \code + QLabel { + id: Label1 + text: "Hello World!" + } + QLabel { + text: "Label1 text length: " + Label1.textLength + } + \endcode + \endtable + + Attributes defined through extensions are inherited, just like attributes + defined on a normal class. Any types that inherit from \c QLabel, will + also have the \c textLength property. Derived types can include additional + extensions which are merged together, but only a single extension can be + specified for each single C++ class. + + Extended type definitions can even be used to add an attached properties + function to a type - just declare the \c qmlAttachedProperties function on + the extension object. + +*/ + |