Home · All Classes · All Functions · Overviews

QML Scope

Property Bindings and JavaScript Blocks are executed in a scope chain automatically established by QML when a component instance is constructed. QML is a dynamically scoped language. Different object instances instantiated from the same component can exist in different scope chains.

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.

Element Type Names

Bindings or script blocks use element type names when accessing Attached Properties or enumeration values. The set of available element names is defined by the import list of the QML Document in which the the binding or script block is defined.

These two examples show how to access attached properties and enumeration values with different types of import statements.

 import Qt 4.6

 Text {
     id: root
     scale: root.PathView.scale
     horizontalAlignment: Text.AlignLeft
 }
 import Qt 4.6 as MyQt

 Text {
     id: root
     scale: root.MyQt.PathView.scale
     horizontalAlignment: MyQt.Text.AlignLeft
 }

QML Local Scope

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.

 // main.qml
 import Qt 4.6

 Rectangle { // Local scope component for binding 1
     id: root
     property string text

     Button {
         text: root.text // binding 1
     }

     ListView {
         delegate: Component { // Local scope component for binding 2
             Rectangle {
                 width: ListView.view.width // binding 2
             }
         }
     }

 }
 // Button.qml
 import Qt 4.6

 Rectangle { // Local scope component for binding 3
     id: root
     property string text

     Text {
         text: root.text  // binding 3
     }
 }

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.

IDs

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.

Here is an example of using IDs within bindings:

 Item {
     id: root
     width: nested.width
     Item {
         id: nested
         height: root.height
     }
 }

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, Method 1 shadows Method 2 for the bindings, but not for Method 3.

 Item {
     Script {
         function getValue() { return 10; } // Method 1
     }

     Rectangle {
         Script {
             function getValue() { return 11; }  // Method 2
             function getValue2() { return getValue(); } // Method 3
         }

         x: getValue()   // Resolves to Method 1, set to 10
         y: getValue2()  // Resolves to Method 3, set to 11
     }
 }

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 Script Methods.

In bindings and script blocks established explicitly in 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: height is a property on Rectangle, and parent is a property on Text.

 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
     }
 }

One notable characteristic of the scope object is its interaction with Attached Properties. As attached properties exist on all objects, an attached property reference that is not explicitly prefixed by an id will always resolve to the attached property on the scope object.

In the following example, Binding 1 will resolve to the attached properties of the Rectangle element, as intended. However, due to the property search of the scope object, Binding 2 will resolve to the attached properties of the Text element, which is probably not what was intended. This code can be corrected, by replacing Binding 2 with this explicit element reference root.ListView.view.width.

 import Qt 4.6

 ListView {
     delegate: Rectangle {
         id: root
         width: ListView.view.width // Binding 1
         Text {
             text: contactName
             width: ListView.view.width // Binding 2
         }
     }
 }

TODO

Root Object

Properties and methods on the local scope component's root object appear in the scope chain immediately after the Scope Object. If the scope object and root object are the same, this step has no effect.

This example uses the root object to easily propagate data throughout the component.

 Item {
     property string description
     property int fontSize

     Text {
         text: description
         font.pixelSize: fontSize
     }
 }

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 QML Local Scope, this parent chain is searched.

For each component instance in the chain, the following are examined:

  1. IDs
  2. Script Methods
  3. Root Object

This list is a sub-set of that in the QML Local Scope.

A sub-component's parent component instance is set to the component that created it. In the following example, the two Button instances have the main.qml instance as their parent component instance. If the Button type was used from within another QML file, it may have a difference parent component instance, and consequently the buttonClicked() method may resolve differently.

 // main.qml
 Item {
     function buttonClicked(var data) {
         print(data + " clicked");
     }

     Button { text: "Button1" }
     Button { text: "Button2" }
 }
 // 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)
     }
 }

The code above discourages the re-use of the 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.

In the following example, the 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 ListView delegates.

 Item {
     property color delegateColor: "red"

     ListView {
         delegate: Component {
             Rectangle {
                 color: delegateColor
             }
         }
     }
 }

QDeclarativeContext chain

The QDeclarativeContext chain allows C++ applications to pass data into QML applications. QDeclarativeComponent object instances created from C++ are passed a 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.

Consider the following QDeclarativeContext tree.

The value of background in Context 1 would be used if it was instantiated in Context 1, where as the value of the background in the root context would be used if the component instance was instantiated in Context 2.

 import Qt 4.6

 Rectangle {
     id: myRect
     width: 100; height: 100
     color: background
 }

QML Global Object

The QML Global Object contains all the properties of the JavaScript global object, plus some QML specific extensions.


Copyright © 2010 Nokia Corporation and/or its subsidiary(-ies) Trademarks
Qt 4.7.0