Qt Reference Documentation

Writing QML Components: Properties, Methods and Signals

One of the key concepts in QML is the ability to define your own QML components that suit the purposes of your application. The standard QML Elements provide the essential components for creating a QML application; beyond these, you can write your own custom components that can be created and reused, without the use of C++.

Components are the building blocks of a QML project. When writing a QML application, whether large or small, it is best to separate QML code into smaller components that perform specific sets of operations, instead of creating mammoth QML files with large, combined functionality that is more difficult to manage and may contain duplicated code.

Defining New Components

A component is a reusable type with a well-defined interface, built entirely in QML. Any snippet of QML code can become a component, by placing the code in a file "<Name>.qml" where <Name> is the new component name, beginning with an uppercase letter. These QML files automatically become available as new QML element types to other QML components and applications in the same directory.

For example, one of the simplest and most common components you can build in QML is a button-type component. Below, we implement this component as a Rectangle with a clickable MouseArea, in a file named Button.qml:

 // Button.qml
 import QtQuick 1.0

 Rectangle {
     width: 100; height: 100
     color: "red"

     MouseArea {
         anchors.fill: parent
         onClicked: console.log("Button clicked!")
     }
 }

Now this component can be reused by another file within the same directory. Since the file is named Button.qml, the component is referred to as Button:

 // application.qml
 import QtQuick 1.0

 Column {
     Button { width: 50; height: 50 }
     Button { x: 50; width: 100; height: 50; color: "blue" }
     Button { width: 50; height: 50; radius: 8 }
 }

The root object in Button.qml defines the attributes that are available to users of the Button component. In this case, the root object is a Rectangle, so any properties, methods and signals of Rectangle are made available, allowing application.qml to customize the width, height, radius and color properties of Button objects.

If Button.qml was not in the same directory, application.qml would need to load it as a module from a specific filesystem path or plugin. Also, note the letter case of the component file name is significant on some (notably UNIX) filesystems. It is recommended the file name case matches the case of the QML component name exactly - for example, Box.qml and not BoX.qml - regardless of the platform to which the QML component will be deployed.

To write a useful component, it is generally necessary to provide it with custom attributes that store and communicate specific data. This is achieved by adding the following attributes to your components:

  • Properties that can be accessed externally to modify an object (for example, Item has width and height properties) and used in Property Binding
  • Methods of JavaScript code can be invoked internally or externally (for example, Animation has a start() method)
  • Signals to notify other objects when an event has occurred (for example, MouseArea has a clicked signal)

The following sections show how these attributes can be added to QML components.

Adding Properties

A property is a value of a QML component that can be read and modified by other objects. For example, a Rectangle component has width, height and color properties. Significantly, properties be used with Property Binding, where a property value is automatically updated using the value of another property.

The syntax for defining a new property is:

 [default] property <type> <name>[: defaultValue]

A property declaration can appear anywhere within a QML component definition, but it is customary to place it at the top. A component cannot declare more than one property with the same name. (It is possible to have a property name that is the same as an existing property in a type, but this is not recommended as the existing property becomes hidden and inaccessible.)

Below is an example. The ImageViewer component has defined a string type property named currentImage, and its initial value is "default-image.png". This property is used to set the image displayed in the child Image object. Another file, application.qml, can create an ImageViewer object and read or modify the currentImage value:

 // ImageViewer.qml
 import QtQuick 1.0

 Item {
     id: item
     width: 200; height: 200

     property string currentImage: "default-image.png"

     Image { source: item.currentImage }
 }

 import QtQuick 1.0

 ImageViewer {
     id: viewer

     currentImage: "http://qt.nokia.com/logo.png"

     Text { text: viewer.currentImage }
 }

It is optional for a property to have a default value. The default value is a convenient shortcut, and is behaviorally identical to doing it in two steps, like this:

 // Use default value
 property int myProperty: 10

 // Longer, but behaviorally identical
 property int myProperty
 myProperty: 10

Supported property types

All QML properties are typed. The examples above show properties with int and string types; notice that the type of the property must be declared. The type is used to determine the property behavior, and how the property is defined in C++.

A number of property types are supported by default. These are listed in the table below, with their default values and the corresponding C++ type:

QML Type NameDefault valueC++ Type Name

int

0

int

bool

false

bool

double

0.0

double

real

0.0

double

string

"" (empty string)

QString

url

"" (empty url)

QUrl

color

#000000 (black)

QColor

date

undefined

QDateTime

variant

undefined

QVariant

QML object types can also be used as property types. This includes custom QML types implemented in C++. Such properties are defined like this:

 property Item itemProperty
 property QtObject objectProperty
 property MyCustomType customProperty

Such object-type properties default to an undefined value.

It is also possible to store a copy of a JavaScript object using the variant property type. This creates some restrictions on how the property should be used; see the variant type documentation for details.

List properties are created with the list<Type> syntax, and default to an empty list:

 property list<Item> listOfItems

Note that list properties cannot be modified like ordinary JavaScript arrays. See the list type documentation for details.

Property change signals

Adding a property to an item automatically adds a value changed signal handler to the item. To connect to this signal, use a signal handler named with the on<Property>Changed syntax, using upper case for the first letter of the property name.

For example, the following onMyNumberChanged signal handler is automatically called whenever the myNumber property changes:

 Item {
     property int myNumber

     onMyNumberChanged: { console.log("myNumber has changed:", myNumber); }

     Component.onCompleted: myNumber = 100
 }

Default properties

The optional default attribute for a property marks it as the default property for a type. This allows other items to specify the default property's value as child elements. For example, the Item element's default property is its children property. This allows the children of an Item to be set like this:

 Item {
     Rectangle {}
     Rectangle {}
 }

If the children property was not the default property for Item, its value would have to be set like this instead:

 Item {
     children: [
         Rectangle {}
         Rectangle {}
     ]
 }

See the TabWidget example for a demonstration of using default properties.

Specifying a default property overrides any existing default property (for example, any default property inherited from a parent item). Using the default attribute twice in the same type block is an error.

Property aliases

Property aliases are a more advanced form of property declaration. Unlike a property definition, which allocates a new, unique storage space for the property, a property alias connects the newly declared property (called the aliasing property) as a direct reference to an existing property (the aliased property). Read operations on the aliasing property act as read operations on the aliased property, and write operations on the aliasing property as write operations on the aliased property.

A property alias declaration looks a lot like an ordinary property definition:

     [default] property alias <name>: <alias reference>

As the aliasing property has the same type as the aliased property, an explicit type is omitted, and the special "alias" keyword is used. Instead of a default value, a property alias includes a compulsory alias reference. The alias reference is used to locate the aliased property. While similar to a property binding, the alias reference syntax is highly restricted.

An alias reference takes one of the following forms:

     <id>.<property>
     <id>

where <id> must refer to an object id within the same component as the type declaring the alias, and, optionally, <property> refers to a property on that object.

For example, below is a Button.qml component with a buttonText aliased property which is connected to the child Text object's text property:

 // Button.qml
 import QtQuick 1.0

 Item {
     property alias buttonText: textItem.text

     width: 200; height: 50

     Text { id: textItem }
 }

The following code would create a Button with a defined text string for the child Text object:

 Button { buttonText: "This is a button" }

Here, modifying buttonText directly modifies the textItem.text value; it does not change some other value that then updates textItem.text.

In this case, the use of aliased properties is essential. If buttonText was not an alias, changing its value would not actually change the displayed text at all, as property bindings are not bi-directional: the buttonText value would change when textItem.text changes, but not the other way around.

Aliased properties are also useful for allowing external objects to directly modify and access child objects in a component. For example, here is a modified version of the ImageViewer component shown earlier on this page. The currentImage property has been changed to an alias to the child Image object:

 // ImageViewer.qml
 import QtQuick 1.0

 Item {
     id: item
     width: 200; height: 200

     property alias currentImage: image

     Image { id: image }
 }

 // application.qml
 import QtQuick 1.0

 ImageViewer {
     id: viewer

     currentImage.source: "http://qt.nokia.com/logo.png"
     currentImage.width: width
     currentImage.height: height
     currentImage.fillMode: Image.Tile

     Text { text: currentImage.source }
 }

Instead of being limited to setting the Image source, application.qml can now directly access and modify the child Image object and its properties.

Obviously, exposing child objects in this manner should be done with care, as it allows external objects to modify them freely. However, this use of aliased properties can be quite useful in particular situations, such as for the TabWidget example, where new tab items are actually parented to a child object that displays the current tab.

Considerations for property aliases

Aliases are only activated once the component specifying them is completed. The most obvious consequence of this is that the component itself cannot generally use the aliased property directly during creation. For example, this will not work:

     // Does NOT work
     property alias buttonText: textItem.text
     buttonText: "Some text" // buttonText is not yet defined when this value is set

A second, much less significant, consequence of the delayed activation of aliases is that an alias reference cannot refer to another aliasing property declared within the same component. This will not work:

     // Does NOT work
     id: root
     property alias buttonText: textItem.text
     property alias buttonText2: root.buttonText

At the time the component is created, the buttonText value has not yet been assigned, so root.buttonText would refer to an undefined value. (From outside the component, however, aliasing properties appear as regular Qt properties and consequently can be used in alias references.)

It is possible for an aliased property to have the same name as an existing property. For example, the following component has a color alias property, named the same as the built-in Rectangle::color property:

 Rectangle {
     property alias color: childRect.color
     color: "red"

     Rectangle { id: childRect }
 }

Any objects that use this component and refer to its color property will be referring to the alias rather than the ordinary Rectangle::color property. Internally, however, the rectangle can correctly set this property to "red" and refer to the actual defined property rather than the alias.

Adding Methods

A QML component can define methods of JavaScript code. These methods can be invoked either internally or by other objects.

The syntax for defining a method is:

 function <name>([<parameter name>[, ...]]) { <body> }

This declaration may appear anywhere within a type body, but it is customary to include it at the top. Attempting to declare two methods or signals with the same name in the same type block is an error. However, a new method may reuse the name of an existing method on the type. (This should be done with caution, as the existing method may be hidden and become inaccessible.)

Unlike signals, method parameter types do not have to be declared as they default to the variant type. The body of the method is written in JavaScript and may access the parameters by name.

Here is an example of a component with a say() method that accepts a single text argument:

 Rectangle {
     id: rect
     width: 100; height: 100

     function say(text) {
         console.log("You said: " + text);
     }

     MouseArea {
         anchors.fill: parent
         onClicked: rect.say("Mouse clicked")
     }
 }

A method can be connected to a signal so that it is automatically invoked whenever the signal is emitted. See Connecting signals to methods and other signals below.

Also see Integrating JavaScript for more information on using JavaScript with QML.

Adding Signals

Signals provide a way to notify other objects when an event has occurred. For example, the MouseArea clicked signal notifies other objects that the mouse has been clicked within the area.

The syntax for defining a new signal is:

 signal <name>[([<type> <parameter name>[, ...]])]

This declaration may appear anywhere within a type body, but it is customary to include it at the top. Attempting to declare two signals or methods with the same name in the same type block is an error. However, a new signal may reuse the name of an existing signal on the type. (This should be done with caution, as the existing signal may be hidden and become inaccessible.)

Here are three examples of signal declarations:

 Item {
     signal clicked
     signal hovered()
     signal performAction(string action, variant actionArgument)
 }

If the signal has no parameters, the "()" brackets are optional. If parameters are used, the parameter types must be declared, as for the string and variant arguments for the performAction signal above; the allowed parameter types are the same as those listed in the Adding Properties section on this page.

Adding a signal to an item automatically adds a signal handler as well. The signal hander is named on<SignalName>, with the first letter of the signal being upper cased. The above example item would now have the following signal handlers:

  • onClicked
  • onHovered
  • onPerformAction

To emit a signal, simply invoke it in the same way as a method. Below left, when the MouseArea is clicked, it emits the parent buttonClicked signal by invoking rect.buttonClicked(). The signal is received by application.qml through an onButtonClicked signal handler:

 // Button.qml
 import QtQuick 1.0

 Rectangle {
     id: rect
     width: 100; height: 100

     signal buttonClicked

     MouseArea {
         anchors.fill: parent
         onClicked: rect.buttonClicked()
     }
 }

 // application.qml
 import QtQuick 1.0

 Button {
     width: 100; height: 100
     onButtonClicked: console.log("Mouse was clicked")
 }

If the signal has parameters, they are accessible by parameter name in the signal handler. In the example below, buttonClicked is emitted with xPos and yPos parameters instead:

 // Button.qml
 Rectangle {
     id: rect
     width: 100; height: 100

     signal buttonClicked(int xPos, int yPos)

     MouseArea {
         anchors.fill: parent
         onClicked: rect.buttonClicked(mouse.x, mouse.y)
     }
 }

 // application.qml
 Button {
     width: 100; height: 100
     onButtonClicked: {
         console.log("Mouse clicked at " + xPos + "," + yPos)
     }
 }

Connecting signals to methods and other signals

Signal objects have a connect() method that can be used to a connect a signal to a method or another signal. When a signal is connected to a method, the method is automatically invoked whenever the signal is emitted. (In Qt terminology, the method is a slot that is connected to the signal; all methods defined in QML are created as Qt slots.) This enables a signal to be received by a method instead of a signal handler.

For example, the application.qml above could be rewritten as:

 Item {
     id: item
     width: 200; height: 200

     function myMethod() {
         console.log("Button was clicked!")
     }

     Button {
         id: button
         anchors.fill: parent
         Component.onCompleted: buttonClicked.connect(item.myMethod)
     }
 }

The myMethod() method will be called whenever the buttonClicked signal is received.

In many cases it is sufficient to receive signals through signal handlers rather than using the connect() function; the above example does not provide any improvements over using a simple onButtonClicked handler. However, if you are creating objects dynamically, or integrating JavaScript code, then you will find the connect() method useful. For example, the component below creates three Button objects dynamically, and connects the buttonClicked signal of each object to the myMethod() function:

 Item {
     id: item
     width: 300; height: 100

     function myMethod() {
         console.log("Button was clicked!")
     }

     Row { id: row }

     Component.onCompleted: {
         var component = Qt.createComponent("Button.qml")
         for (var i=0; i<3; i++) {
             var button = component.createObject(row)
             button.border.width = 1
             button.buttonClicked.connect(myMethod)
         }
     }
 }

In the same way, you could connect a signal to methods defined in a dynamically created object, or connect a signal to a JavaScript method.

There is also a corresponding disconnect() method for removing connected signals. The following code removes the connection created in application.qml above:

 // application.qml
 Item {
     ...

     function removeSignal() {
         button.clicked.disconnect(item.myMethod)
     }
 }

Forwarding signals

The connect() method can also connect a signal to other signals. This has the effect of "forwarding" a signal: it is automatically emitted whenever the relevant signal is emitted. For example, the MouseArea onClicked handler in Button.qml above could have been replaced with a call to connect():

 MouseArea {
     anchors.fill: parent
     Component.onCompleted: clicked.connect(item.buttonClicked)
 }

Whenever the MouseArea clicked signal is emitted, the rect.buttonClicked signal will automatically be emitted as well.

X

Thank you for giving your feedback.

Make sure it is related to this specific page. For more general bugs and requests, please use the Qt Bug Tracker.