diff options
author | Aaron Kennedy <aaron.kennedy@nokia.com> | 2010-03-24 05:40:05 (GMT) |
---|---|---|
committer | Aaron Kennedy <aaron.kennedy@nokia.com> | 2010-03-24 05:40:05 (GMT) |
commit | d19de14f84e9fca8bb709039d5d0331e6ddfe485 (patch) | |
tree | f01e97c72f21ed6abef881c846825ccef83380ee /doc | |
parent | f59619a3a4de074d0557ce17f9580a242e4e6c16 (diff) | |
download | Qt-d19de14f84e9fca8bb709039d5d0331e6ddfe485.zip Qt-d19de14f84e9fca8bb709039d5d0331e6ddfe485.tar.gz Qt-d19de14f84e9fca8bb709039d5d0331e6ddfe485.tar.bz2 |
Doc
Diffstat (limited to 'doc')
-rw-r--r-- | doc/src/declarative/scope.qdoc | 452 |
1 files changed, 206 insertions, 246 deletions
diff --git a/doc/src/declarative/scope.qdoc b/doc/src/declarative/scope.qdoc index 8ec784f..c588b45 100644 --- a/doc/src/declarative/scope.qdoc +++ b/doc/src/declarative/scope.qdoc @@ -39,344 +39,304 @@ ** ****************************************************************************/ -/*! -\page qdeclarativescope.html -\title QML Scope +/* + + + +and requires extension to +fit naturally with QML. -\tableofcontents -NOTE: This documentation is out of data. +JavaScript has only b +JavaScript has a very simple built in scope is very simple -\l {Property Binding}s and \l {Integrating JavaScript}{JavaScript} are executed in a scope chain +script, and the precede d + +and \l {Integrating JavaScript}{JavaScript} are executed in a scope chain automatically established by QML when a component instance is constructed. QML is a \e {dynamically scoped} language. Different object instances instantiated from the same component can exist in different scope chains. \image qml-scope.png -\section1 JavaScript Variable object -Each binding and script block has its own distinct JavaScript variable object where local -variables are stored. That is, local variables from different bindings and script blocks never -conflict. +*/ -\section1 Element Type Names +/*! +\page qdeclarativescope.html +\title QML Scope -Bindings or script blocks use element type names when accessing \l {Attached Properties} or -enumeration values. The set of available element names is defined by the import list of the -\l {QML Documents}{QML Document} in which the the binding or script block is defined. +\tableofcontents -These two examples show how to access attached properties and enumeration values with different -types of import statements. -\table -\row -\o -\code -import Qt 4.6 +QML property bindings, inline functions and imported JavaScript files all +run in a JavaScript scope. Scope controls which variables an expression can +access, and which variable takes precedence when two or more names conflict. -Text { - id: root - scale: root.PathView.scale - horizontalAlignment: Text.AlignLeft -} -\endcode -\o -\code -import Qt 4.6 as MyQt +As JavaScript's built-in scope mechanism is very simple, QML enhances it to fit +more naturally with the QML language extensions. -Text { - id: root - scale: root.MyQt.PathView.scale - horizontalAlignment: MyQt.Text.AlignLeft -} -\endcode -\endtable +\section1 JavaScript Scope -\section1 QML Local Scope +QML's scope extensions do not interfere with JavaScript's natural scoping. +JavaScript programmers can reuse their existing knowledge when programming +functions, property bindings or imported JavaScript files in QML. -Most variables references are resolved in the local scope. The local scope is controlled by the -QML component in which the binding or script block was defined. The following example shows -three different bindings, and the component that dictates each local scope. +In the following example, the \c {addConstant()} method will add 13 to the +parameter passed just as the programmer would expect irrespective of the +value of the QML object's \c a and \c b properties. -\table -\row -\o \code -// main.qml -import Qt 4.6 +QtObject { + property int a: 3 + property int b: 9 -Rectangle { // Local scope component for binding 1 - id: root - property string text - - Button { - text: root.text // binding 1 + function addConstant(b) { + var a = 13; + return b + a; } - - ListView { - delegate: Component { // Local scope component for binding 2 - Rectangle { - width: ListView.view.width // binding 2 - } - } - } - } \endcode -\o -\code -// Button.qml -import Qt 4.6 -Rectangle { // Local scope component for binding 3 - id: root - property string text +That QML respects JavaScript's normal scoping rules even applies in bindings. +This totally evil, abomination of a binding will assign 12 to the QML object's +\c a property. - Text { - text: root.text // binding 3 - } +\code +QtObject { + property int a + + a: { var a = 12; a; } } \endcode -\endtable -Inside the local scope, four "sub-scopes" exist. Each sub-scope is searched in order when -resolving a name; names in higher sub-scopes shadow those in lower sub-scopes. +Every JavaScript expression, function or file in QML has its own unique +variable object. Local variables declared in one will never conflict +with local variables declared in another. -\section2 IDs +\section1 Element Names and Imported JavaScript Files -IDs present in the component take precendence over other names. The QML engine enforces -uniqueness of IDs within a component, so their names cannot conflict with one another. +\l {QML Document}s include import statements that define the element names +and JavaScript files visible to the document. In addition to their use in the +QML declaration itself, element names are used by JavaScript code when accessing +\l {Attached Properties} and enumeration values. -Here is an example of using IDs within bindings: +The effect of an import applies to every property binding, and JavaScript +function in the QML document, even those in nested inline components. The +following example shows a simple QML file that accesses some enumeration +values and calls an imported JavaScript function. \code -Item { - id: root - width: nested.width - Item { - id: nested - height: root.height - } -} -\endcode - -\section2 Script Methods - -Methods declared in script blocks are searched immediately after IDs. In the case of multiple -script blocks in the one component, the blocks are searched in the order in which they were -declared - the nesting of script blocks within a component is not significant for name -resolution. - -In the following example, \c {Method 1} shadows \c {Method 2} for the bindings, but not for -\c {Method 3}. +import Qt 4.6 +import "code.js" as Code -\code -Item { - Script { - function getValue() { return 10; } // Method 1 - } +ListView { + snapMode: ListView.SnapToItem - Rectangle { - Script { - function getValue() { return 11; } // Method 2 - function getValue2() { return getValue(); } // Method 3 + delegate: Component { + Text { + elide: Text.ElideMiddle + text: "A really, really long string that will require eliding." + color: Code.defaultColor() } - - x: getValue() // Resolves to Method 1, set to 10 - y: getValue2() // Resolves to Method 3, set to 11 } } \endcode -\section2 Scope Object - -A scope object is associated with each binding and script block. Properties and methods of the -scope object appear in the scope chain, immediately after \l {Script Methods}. +\section1 Binding Scope Object -In bindings and script blocks established explicitly in \l {QML Documents}, the scope object is -always the element containing the binding or script block. The following example shows two -bindings, one using grouped properties, and the corresponding scope object. These two bindings -use the scope object to resolve variable references: \c height is a property on \l Rectangle, -and \c parent is a property on \l Text. +Property bindings are the most common use of JavaScript in QML. Property +bindings associate the result of a JavaScript expression with a property of an +object. The object to which the bound property belongs is known as the binding's +scope object. In this QML simple declaration the \l Item object is the +binding's scope object. \code -Item { // Scope object for Script block 1 - Script { // Script block 1 - function calculateValue() { ... } - } - - Rectangle { // Scope object for Binding 1 and Script block 2 - Script { // Script block 2 - function calculateColor() { ... } - } - width: height * 2 // Binding 1 - } - - Text { // Scope object for Binding 2 - font.pixelSize: parent.height * 0.7 // binding 2 - } +Item { + anchors.left: parent.left } \endcode -One notable characteristic of the scope object is its interaction with \l {Attached Properties}. -As attached properties exist on all objects, an attached property reference that is not -explicitly prefixed by an id will \e always resolve to the attached property on the scope -object. - -In the following example, \c {Binding 1} will resolve to the attached properties of the -\l Rectangle element, as intended. However, due to the property search of the scope object, -\c {Binding 2} will resolve to the attached properties of the \l Text element, which -is probably not what was intended. This code can be corrected, by replacing \c {Binding 2} -with this explicit element reference \c {root.ListView.view.width}. +Bindings have access to the scope object's properties without qualification. +In the previous example, the binding accesses the \l Item's \c parent property +directly, without needing any form of object prefix. QML introduces a more +structured, object-oriented approach to JavaScript, and consequently does not +require (although it does support) use of the implicit \c this property. + +Care must be used when accessing \l {Attached Properties} from bindings due +to their interaction with the scope object. Conceptually attached properties +exist on \e all objects, even if they only have an effect on a subset of those. +Consequently unqualified attached property reads will always resolve to an +attached property on the scope object, which is not always what the programmer +intended. + +For example, the \l PathView element attaches interpolated value properties to +its delegates depending on their position in the path. As PathView only +meaningfully attaches these properties to the root element in the delegate, any +sub-element that accesses them must explicitly qualify the root object, as shown +below. \code -import Qt 4.6 - -ListView { - delegate: Rectangle { - id: root - width: ListView.view.width // Binding 1 - Text { - text: contactName - width: ListView.view.width // Binding 2 +PathView { + delegate: Component { + Rectangle { + id: root + Image { + scale: root.PathView.scale + } } } } \endcode -\e TODO - -\list -\o scope object for PropertyChanges -\endlist - -\section2 Root Object +If the \l Image element omitted the \c root prefix, it would inadvertantly access +the unset \c {PathView.scale} attached property on itself. -Properties and methods on the local scope component's root object appear in the scope chain -immediately after the \l {Scope Object}. If the scope object and root object are the same, -this step has no effect. +\section1 Component Scope -This example uses the root object to easily propagate data throughout the component. +Each QML component in a QML document defines a logical scope. Each document +has at least one root component, but can also have other inline sub-components. +The component scope is the union of the object ids within the component and the +component's root element's properties. \code Item { - property string description - property int fontSize + property string title Text { - text: description - font.pixelSize: fontSize + id: titleElement + text: "<b>" + title + "</b>" + font.pixelSize: 22 + anchors.top: parent.top + } + + Text { + text: titleElement.text + font.pixelSize: 18 + anchors.bottom: parent.bottom } } \endcode -\section1 QML Component chain - -When a QML component is instantiated it is given a parent component instance. The parent -component instance is immutable - it is not affected, for example, by changes in the instance's -visual parent (in the case of visual elements). Should name resolution fail within the -\l {QML Local Scope}, this parent chain is searched. +The example above shows a simple QML component that displays a rich text title +string at the top, and a smaller copy of the same text at the bottom. The first +\c Text element directly accesses the component's \c title property when +forming the text to display. That the root element's properties are directly +accessible makes it trivial to distribute data throughout the component. -For each component instance in the chain, the following are examined: +The second \c Text element uses an id to access the first's text directly. IDs +are specified explicitly by the QML programmer so they always take precedence +over other property names (except for those in the \l {JavaScript Scope}). For +example, in the unlikely event that the binding's \l {Binding Scope Object}{scope +object} had a \c titleElement property in the previous example, the \c titleElement +id would still take precedence. -\list 1 -\o IDs -\o Script Methods -\o Root Object -\endlist +\section1 Component Instance Hierarchy -This list is a sub-set of that in the \l {QML Local Scope}. +In QML, component instances connect their component scopes together to form a +scope hierarchy. Component instances can directly access the component scopes of +their ancestors. -A sub-component's parent component instance is set to the component that created it. -In the following example, the two \c Button instances have the -\c main.qml instance as their parent component instance. If the \c Button type was used from -within another QML file, it may have a difference parent component instance, and consequently -the \c buttonClicked() method may resolve differently. +The easiest way to demonstrate this is with inline sub-components whose component +scopes are implicitly scoped as children of the outer component. -\table -\row -\o \code -// main.qml Item { - function buttonClicked(var data) { - print(data + " clicked"); - } + property color defaultColor: "blue" - Button { text: "Button1" } - Button { text: "Button2" } -} -\endcode -\o -\code -// Button.qml -Rectangle { - id: root - property string text - width: 80 - height: 30 - Text { - anchors.centerIn: parent - text: root.text - } - MouseArea { - anchors.fill: parent - onClicked: buttonClicked(text) + ListView { + delegate: Component { + Rectangle { + color: defaultColor + } + } } } \endcode -\endtable -The code above discourages the re-use of the \c Button component, as it has a hard dependency -on the environment in which it is used. Tightly coupling two types together like this should -only be used when the components are within the same module, and the author controls the -implementations of both. +The component instance hierarchy allows instances of the delegate component +to access the \c defaultColor property of the \c Item element. Of course, +had the delegate component had a property called \c defaultColor that would +have taken precedence. -In the following example, the \l ListView sets the parent component instance of each of its -delegates to its own component instance. In this way, the main component can easily pass data -into the \l ListView delegates. +The component instance scope hierarchy extends to out-of-line components, too. +In the following example, the \c TitlePage.qml component creates two +\c TitleText instances. Even though the \c TitleText element is in a separate +file, it still has access to the \c title property when it is used from within +the \c TitlePage. QML is a dynamically scoped language - depending on where it +is used, the \c title property may resolve differently. \code +// TitlePage.qml +import Qt 4.6 Item { - property color delegateColor: "red" + property string title + + TitleText { + size: 22 + anchors.top: parent.top + } - ListView { - delegate: Component { - Rectangle { - color: delegateColor - } - } + TitleText { + size: 18 + anchors.bottom: parent.bottom } } -\endcode -\section1 QDeclarativeContext chain - -The \l QDeclarativeContext chain allows C++ applications to pass data into QML applications. -\l QDeclarativeComponent object instances created from C++ are passed a \l QDeclarativeContext in which they -are created. Variables defined in this context appear in the scope chain. Each QDeclarativeContext -also defines a parent context. Variables in child QDeclarativeContext's shadow those in its parent. +// TitleText.qml +import Qt 4.6 +Text { + property int size + text: "<b>" + title + "</b>" + font.pixelSize: size +} +\endcode -Consider the following QDeclarativeContext tree. +Dynamic scoping is very powerful, but it must be used cautiously to prevent +the behavior of QML code from becoming difficult to predict. In general it +should only be used in cases where the two components are already tightly +coupled in another way. When building reusable components, it is preferable +to use property interfaces, like this: -\image qml-context-tree.png +\code +// TitlePage.qml +import Qt 4.6 +Item { + id: root + property string title + + TitleText { + title: root.title + size: 22 + anchors.top: parent.top + } -The value of \c background in \c {Context 1} would be used if it was instantiated in -\c {Context 1}, where as the value of the \c background in the root context would be used if -the component instance was instantiated in \c {Context 2}. + TitleText { + title: root.title + size: 18 + anchors.bottom: parent.bottom + } +} -\code +// TitleText.qml import Qt 4.6 +Text { + property string title + property int size -Rectangle { - id: myRect - width: 100; height: 100 - color: background + text: "<b>" + title + "</b>" + font.pixelSize: size } \endcode -\section1 QML Global Object +\section1 JavaScript Global Object + +In addition to all the properties that a developer would normally expect on +the JavaScript global object, QML adds some custom extensions to make UI or +QML specific tasks a little easier. These extensions are described in the +\l {QML Global Object} documentation. + +QML disallows element, id and property names that conflict with the properties +on the global object to prevent any confusion. Programmers can be confident +that \c Math.min(10, 9) will always work as expected! -The \l {QML Global Object} contains all the properties of the JavaScript global object, plus some -QML specific extensions. */ |