Qt Quick Tutorial Components

From Qt Wiki
Revision as of 01:18, 24 March 2016 by Wieland (talk | contribs) (Fixed links)
Jump to navigation Jump to search
This article may require cleanup to meet the Qt Wiki's quality standards. Reason: Auto-imported from ExpressionEngine.
Please improve this article if you can. Remove the {{cleanup}} tag and add this page to Updated pages list after it's clean.

Qt Quick Tutorial: Module 2 - Components

Creating a Custom Component

We still have some work left to do from Module 1. If we look at our final QML document BasicSteps_4.qml, we still see too much code duplication. The code for the three photo rectangles is nearly identical. It only differs in the x-position, the image file and the title. In C+, we would introduce a class

Photo

, instantiate it three times and initialize it with the different values of the x-position, image file and title. And, this is actually what we do in QML, too - except that a class is called a component in QML. A component is always defined in a file that has the component's name as its base name and that has the extension .qml. For example, our

Photo

component will be defined in the file Photo.qml. A component name always starts with an uppercase letter and is continued by zero or more letters (uppercase or lowercase), digits or underscores. We perform the following steps to create the

Photo

component.

  • We copy the QML file BasicSteps_4.qml into the file Components.qml.
  • We create a new QML file Photo.qml in the same directory as Components.qml.
  • We copy the
    Rectangle
    
    for photo 1 into Photo.qml.

We are fairly close to the final

Photo

component. We only have to introduce properties for the variable parameters of the

Photo

component: the x-position, image file and image title. We will assign concrete values to these properties in the instantiations of the

Photo

component in Components.qml. We don't have to do anything for the x-position, because a

Rectangle

already has a property

x

. We simply remove the code fragment

x: 0;

. While we are at it, we also remove the code fragment

y: 0

, because the default value for the y-position is 0 anyway. For the image file and title, we introduce two properties

imageFile

and

imageTitle

at the beginning of the

Rectangle

. Finally, we replace the value of

source

in

Image

by

imageFile

and the value of

text

in

Text

by

imageTitle

. With all these changes, the

Photo

component looks as follows.

// File: Photo.qml
import QtQuick 1.0

Rectangle {
 property url imageFile
 property string imageTitle

 width: frameSize; height: frameSize
 color: frameColor

 Image {
 x: leftMargin; y: topMargin
 source: imageFile
 }

 Text {
 x: 0; y: frameSize - bottomMargin
 text: imageTitle
 font.pixelSize: fontSize
 width: frameSize; horizontalAlignment: Text.AlignHCenter
 height: bottomMargin; verticalAlignment: Text.AlignVCenter
 }
}

We can now use our brand new

Photo

component in the main QML document Components.qml (formerly BasicSteps_4.qml), which shows three photos side by side. The resulting code looks as follows.

// File: Components.qml
import QtQuick 1.0

Rectangle {
 property int frameSize: 300
 property int leftMargin: 10
 property int topMargin: 25
 property int bottomMargin: 65
 property int fontSize: 20
 property color frameColor: "#FFF8DC" // cornsilk

 width: 3 * frameSize; height: frameSize

 Photo {
 x: 0
 imageFile: "voringsfossen1.jpg"
 imageTitle: "Voringsfossen"
 }

 Photo {
 x: frameSize
 imageFile: "bergen.jpg"
 imageTitle: "Bergen"
 }

 Photo {
 x: 2 * frameSize
 imageFile: "cotton_grass.jpg"
 imageTitle: "Cotton Grass"
 }
}

In the three instances of the

Photo

component, we only assign values to the three variable parameters: x-position, image file and image title. The values of the other properties like

frameSize

or

leftMargin

are propagated from the root

Rectangle

instance to the

Photo

instances and to their child instances

Image

and

Text

.

We can now admire our work by running QML viewer in the directory of Components.qml and Photo.qml:

qmlviewer Components.qml &<code>

How does QML viewer know where to find the <code>Photo

component? By default, QML viewer looks for a QML file with the same base name as the component and with the extension .qml in the directory, where it is started. In our case, it finds the file Photo.qml.

Property Aliases and Property id

We can still improve the code of the

Photo

component a little bit. The URL of the image file and the image title are stored in two places each. The image file is stored in the newly introduced property

imageFile

and in the property

source

of

Image

. Similarly, the image title is stored in

imageTitle

and in

text

of

Text

. This means that memory is allocated twice for the image file and twice for the image title. It is not a big problem in this example. If, however, the duplicated objects are bigger, it becomes a problem. The other problem is that the we must make sure that the two occurrences of image file and of image title are in sync with each other. Again, it is fairly simple for our little program but it becomes trickier for bigger programs.

Fortunately, property aliases come to our rescue. A property alias says that two properties share the same value and store it at one memory location. The C+ equivalent would be a reference to an existing variable. The syntax of a property alias is

property alias property1: property2
where <code>property1

is the newly introduced alias and

property2

is the already existing property to be aliased. In our

Photo

component, we want to define

imageFile

as an alias for the property

source

of

Image

and

imageTitle

as an alias for the property

text

of

Text

. There is only one little problem: How can we uniquely address the properties

source

and

text

? If there were several

Image

or

Text

components in the

Photo

component (a fairly usual scenario, by the way), we would have no way distinguish them. The special QML property

id

solves this problem. The property

id

is a unique name or identifier for a component instance. Using the notation

instName.propName

we can access the property

propertyName

of the instance, whose

id

property has the value

instName

.

Now, we can finally introduce the two property aliases and use them. In Photo.qml, we replace the two property definitions in lines 5 and 6 by

property alias imageFile: picture.source
property alias imageTitle: title.text
We assign the identifier <code>photo

to the

Image

component and remove the line for the

source

property. Then,

Image

looks as follows:

Image {
id: picture
x: leftMargin; y: topMargin
}
Similarly, we assign the identifier <code>title

to the

Text

component and remove the line for the

text

property. Then,

Text

looks as follows:

Text {
id: title
x: 0; y: frameSize - bottomMargin
font.pixelSize: fontSize
width: frameSize; horizontalAlignment: Text.AlignHCenter
height: bottomMargin; verticalAlignment: Text.AlignVCenter
}
The complete code for the modified <code>Photo

component can be found in Photo.qml. It is important to note that the value of

id

is not enclosed in double quotes. It is not quoted at all because it is an identifier, not a string.

Go back to Module 1 - Basics

Tutorial Main Page