Qt Quick Tutorial Basics 2: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
Line 1: Line 1:
[[Category:Developing_with_Qt::Qt Quick]]<br />[[Category:Developing_with_Qt::Qt Quick::Tutorial]]<br />[toc align_right=&quot;yes&amp;quot; depth=&quot;3&amp;quot;]
[[Category:Developing_with_Qt::Qt Quick]]<br />[[Category:Developing_with_Qt::Qt Quick::Tutorial]]<br />[toc align_right="yes" depth="3"]


= Qt Quick Tutorial: Module 1 - Basics =
= Qt Quick Tutorial: Module 1 - Basics =
Line 5: Line 5:
== Components and Properties ==
== Components and Properties ==


No, we don't start with a QML program printing &quot;Hello world!&quot;. We start with something much more exciting: a QML program that draws a blue rectangle of 300x300 pixels.
No, we don't start with a QML program printing "Hello world!". We start with something much more exciting: a QML program that draws a blue rectangle of 300x300 pixels.


<code><br />// File: BasicSteps_1.qml
<code><br />// File: BasicSteps_1.qml
Line 11: Line 11:
import QtQuick 1.0
import QtQuick 1.0


Rectangle {<br /> width: 300<br /> height: 300<br /> color: &quot;blue&amp;quot;<br />}<br /></code>
Rectangle {<br /> width: 300<br /> height: 300<br /> color: "blue"<br />}<br /></code>


We run QML viewer to see the result of our work:
We run QML viewer to see the result of our work:


<code>&gt; qmlviewer BasicSteps_1.qml &amp;amp;<code>
<code>> qmlviewer BasicSteps_1.qml &amp;amp;<code>


Yes, the above QML code, indeed, produces a blue rectangle. A self-contained piece of QML code as the one above is called a '''QML document''' (see also &quot;QML Documents&amp;quot;:http://doc.qt.nokia.com/4.7-snapshot/qdeclarativedocuments.html). A QML document is a piece of QML code that contains at least one &lt;code&amp;gt;import&amp;lt;/code&amp;gt; statement and exactly one top-level component. In our example, &lt;code&amp;gt;Rectangle&amp;lt;/code&amp;gt; is the single top-level component. Generally, a QML document corresponds to a file, but it could also be text stored in a string or a URL pointing to QML document stored on a remote server.
Yes, the above QML code, indeed, produces a blue rectangle. A self-contained piece of QML code as the one above is called a '''QML document''' (see also "QML Documents":http://doc.qt.nokia.com/4.7-snapshot/qdeclarativedocuments.html). A QML document is a piece of QML code that contains at least one <code>import</code> statement and exactly one top-level component. In our example, <code>Rectangle</code> is the single top-level component. Generally, a QML document corresponds to a file, but it could also be text stored in a string or a URL pointing to QML document stored on a remote server.


The statement &lt;code&amp;gt;import Qt 4.7&amp;lt;/code&amp;gt; makes all the QML components of Qt 4.7 available to our QML document. Qt 4.7 comes with built-in components like Rectangle, Text, ListView, WebView, Flipable, Animation and many more (see &quot;QML Elements&amp;quot;:http://doc.qt.nokia.com/4.7-snapshot/qdeclarativeelements.html for a complete list).
The statement <code>import Qt 4.7</code> makes all the QML components of Qt 4.7 available to our QML document. Qt 4.7 comes with built-in components like Rectangle, Text, ListView, WebView, Flipable, Animation and many more (see "QML Elements":http://doc.qt.nokia.com/4.7-snapshot/qdeclarativeelements.html for a complete list).


'''Components''' are the QML equivalents of C++ classes. They have properties, methods (member functions), signals and slots. The occurrence of &lt;code&amp;gt;Rectangle&amp;lt;/code&amp;gt; in lines 5-9 is an instance of a &lt;code&amp;gt;Rectangle&amp;lt;/code&amp;gt; component: a blue 300x300 pixel instance of a &lt;code&amp;gt;Rectangle&amp;lt;/code&amp;gt; component. In the Qt documentation, '''element''' is often used as a synonym for component. Components with a visual representation like a Rectangle or Text are called '''items'''. Component names always start with an uppercase letter followed by zero or more letters, digits and underscores.
'''Components''' are the QML equivalents of C++ classes. They have properties, methods (member functions), signals and slots. The occurrence of <code>Rectangle</code> in lines 5-9 is an instance of a <code>Rectangle</code> component: a blue 300x300 pixel instance of a <code>Rectangle</code> component. In the Qt documentation, '''element''' is often used as a synonym for component. Components with a visual representation like a Rectangle or Text are called '''items'''. Component names always start with an uppercase letter followed by zero or more letters, digits and underscores.


A instance of a component is characterised by its '''properties''', which are name-value pairs. The &lt;code&amp;gt;Rectangle&amp;lt;/code&amp;gt; instance above has three properties &lt;code&amp;gt;width&amp;lt;/code&amp;gt;, &lt;code&amp;gt;height&amp;lt;/code&amp;gt; and &lt;code&amp;gt;color&amp;lt;/code&amp;gt; with the values &lt;code&amp;gt;300&amp;lt;/code&amp;gt;, &lt;code&amp;gt;300&amp;lt;/code&amp;gt; and &lt;code&amp;gt;blue&amp;lt;/code&amp;gt;, respectively. Property names always start with a lowercase letter followed by zero or more letters, digits and underscores. Properties are type-safe. Hence, the line
A instance of a component is characterised by its '''properties''', which are name-value pairs. The <code>Rectangle</code> instance above has three properties <code>width</code>, <code>height</code> and <code>color</code> with the values <code>300</code>, <code>300</code> and <code>blue</code>, respectively. Property names always start with a lowercase letter followed by zero or more letters, digits and underscores. Properties are type-safe. Hence, the line


</code>width: &quot;Oslo&amp;quot;</code>
</code>width: "Oslo"</code>


would be illegal, because the property &lt;code&amp;gt;width&amp;lt;/code&amp;gt; expects a number of type real. QML supports the following basic types: bool, color, date, font, int, list, point, real, rect, size, string, time, url.
would be illegal, because the property <code>width</code> expects a number of type real. QML supports the following basic types: bool, color, date, font, int, list, point, real, rect, size, string, time, url.


Several properties can be written in one line separated by semicolon:
Several properties can be written in one line separated by semicolon:


<code><br />width: 300; height: 300<br />color: &quot;blue&amp;quot;<br /></code>
<code><br />width: 300; height: 300<br />color: "blue"<br /></code>


The order of properties is irrelevant. We could rewrite the &lt;code&amp;gt;Rectangle&amp;lt;/code&amp;gt; as
The order of properties is irrelevant. We could rewrite the <code>Rectangle</code> as


<code><br />// File: BlueRectangle.qml<br />Rectangle {<br /> height: 300<br /> width: 300<br /> color: &quot;blue&amp;quot;<br />}<br /></code>
<code><br />// File: BlueRectangle.qml<br />Rectangle {<br /> height: 300<br /> width: 300<br /> color: "blue"<br />}<br /></code>


and the result would be the same.
and the result would be the same.


'''Comments''' are marked in QML in the same way as in C++. Comments to the end of the line start with &lt;code&amp;gt;//&amp;lt;/code&amp;gt;. Line 1 of our example contains such a comment. Multi-line comments start with &lt;code&amp;gt;/*&lt;/code&amp;gt; and end with &lt;code&amp;gt;'''/&amp;lt;/code&amp;gt;.
'''Comments''' are marked in QML in the same way as in C++. Comments to the end of the line start with <code>//</code>. Line 1 of our example contains such a comment. Multi-line comments start with <code>/*</code> and end with <code>*/</code>.
<br />h2. Composition of Components
<br />h2. Composition of Components
<br />The excitement about our blue rectangle is wearing off by now, isn't it? So, let us turn the blue rectangle into a photo frame with a photo in the center, a tag line below the photo and a oldlace colored background. We position a QML &lt;code&amp;gt;Image&amp;lt;/code&amp;gt; component for the photo and a &lt;code&amp;gt;Text&amp;lt;/code&amp;gt; component for the title on the &lt;code&amp;gt;Rectangle&amp;lt;/code&amp;gt; component and change the color to &quot;oldlace&amp;quot;. We can use the SVG color names directly in QML.
<br />The excitement about our blue rectangle is wearing off by now, isn't it? So, let us turn the blue rectangle into a photo frame with a photo in the center, a tag line below the photo and a oldlace colored background. We position a QML <code>Image</code> component for the photo and a <code>Text</code> component for the title on the <code>Rectangle</code> component and change the color to "oldlace". We can use the SVG color names directly in QML.
<br /><code><br />// File: PlacingElements.qml<br />import QtQuick 1.0
<br /><code><br />// File: PlacingElements.qml<br />import QtQuick 1.0
<br />Rectangle {<br /> width: 180<br /> height: 135<br /> color: &quot;oldlace&amp;quot;<br /> Image {<br /> x: 10; y: 10<br /> width: 160<br /> height: 100<br /> fillMode: Image.PreserveAspectCrop<br /> source: &quot;images/image01.jpg&amp;quot;<br /> }<br /> Text {<br /> x: 10; y: 115<br /> width: 100<br /> text: &quot;temple&amp;quot;<br /> }<br />}<br /></code>
<br />Rectangle {<br /> width: 180<br /> height: 135<br /> color: "oldlace"<br /> Image {<br /> x: 10; y: 10<br /> width: 160<br /> height: 100<br /> fillMode: Image.PreserveAspectCrop<br /> source: "images/image01.jpg"<br /> }<br /> Text {<br /> x: 10; y: 115<br /> width: 100<br /> text: "temple"<br /> }<br />}<br /></code>
<br />We have chosen a &lt;code&amp;gt;Rectangle&amp;lt;/code&amp;gt; element as the root of our element hierarchy. We place an &lt;code&amp;gt;Image&amp;lt;/code&amp;gt; and &lt;code&amp;gt;Text&amp;lt;/code&amp;gt; element inside. Children in a QML element tree are always placed relative to its parents. The &lt;code&amp;gt;x&amp;lt;/code&amp;gt; and &lt;code&amp;gt;y&amp;lt;/code&amp;gt; coordinate refers to the top-left … etc
<br />We have chosen a <code>Rectangle</code> element as the root of our element hierarchy. We place an <code>Image</code> and <code>Text</code> element inside. Children in a QML element tree are always placed relative to its parents. The <code>x</code> and <code>y</code> coordinate refers to the top-left … etc
<br />As the image is 280x210 pixels, this position centers the image horizontally and vertically within the rectangle. The &lt;code&amp;gt;source&amp;lt;/code&amp;gt; property tells the QML runtime where to look for the image, which is stored in the file &lt;code&amp;gt;&quot;voringsfossen1.jpg&amp;quot;&lt;/code&amp;gt;. The image file is located in the same directory as the QML file &lt;code&amp;gt;BasicSteps.qml&amp;lt;/code&amp;gt;. In general, the &lt;code&amp;gt;source&amp;lt;/code&amp;gt; property takes a URL. The image could be located anywhere in the Internet or our local file system.
<br />As the image is 280x210 pixels, this position centers the image horizontally and vertically within the rectangle. The <code>source</code> property tells the QML runtime where to look for the image, which is stored in the file <code>"voringsfossen1.jpg"</code>. The image file is located in the same directory as the QML file <code>BasicSteps.qml</code>. In general, the <code>source</code> property takes a URL. The image could be located anywhere in the Internet or our local file system.
<br />The &lt;code&amp;gt;Text&amp;lt;/code&amp;gt; is positioned at 10 pixels to the right and 265 pixels down from the top left corner of the rectangle. The displayed text is &quot;Voringsfossen&amp;quot;, which is the name of Norway's most famous and highest waterfall. Again, &lt;code&amp;gt;Text&amp;lt;/code&amp;gt; is a child of &lt;code&amp;gt;Rectangle&amp;lt;/code&amp;gt; .
<br />The <code>Text</code> is positioned at 10 pixels to the right and 265 pixels down from the top left corner of the rectangle. The displayed text is "Voringsfossen", which is the name of Norway's most famous and highest waterfall. Again, <code>Text</code> is a child of <code>Rectangle</code> .
<br />This simple example of a photo frame shows how to compose basic components into a more complex components. The components or strictly speaking the component instances are arranged in a tree. In our example, the &lt;code&amp;gt;Rectangle&amp;lt;/code&amp;gt; is the root of the tree and &lt;code&amp;gt;Image&amp;lt;/code&amp;gt; and &lt;code&amp;gt;Text&amp;lt;/code&amp;gt; are the root's children. The children could again have children of their own and so on. These instance trees mirror the instance trees of Qt's graphics items or widgets.
<br />This simple example of a photo frame shows how to compose basic components into a more complex components. The components or strictly speaking the component instances are arranged in a tree. In our example, the <code>Rectangle</code> is the root of the tree and <code>Image</code> and <code>Text</code> are the root's children. The children could again have children of their own and so on. These instance trees mirror the instance trees of Qt's graphics items or widgets.
<br />The result won't win us a design prize, but it is a good first shot. Let us improve it step by step. As the title shouldn't look crammed into the frame below the photo, we move the photo 20 pixels up. We just change &lt;code&amp;gt;Image&amp;lt;/code&amp;gt;'s property &lt;code&amp;gt;y&amp;lt;/code&amp;gt; to &lt;code&amp;gt;25&amp;lt;/code&amp;gt;.
<br />The result won't win us a design prize, but it is a good first shot. Let us improve it step by step. As the title shouldn't look crammed into the frame below the photo, we move the photo 20 pixels up. We just change <code>Image</code>'s property <code>y</code> to <code>25</code>.
<br /><code><br /> Image {<br /> x: 10; y: 25<br /> source: &quot;voringsfossen1.jpg&amp;quot;<br /> }<br /></code>
<br /><code><br /> Image {<br /> x: 10; y: 25<br /> source: "voringsfossen1.jpg"<br /> }<br /></code>
<br />We want the title to be a bit bigger, say 20 pixels (line 4), and want it to be centered both horizontally (line 5) and vertically (line 6) in the area below the photo.
<br />We want the title to be a bit bigger, say 20 pixels (line 4), and want it to be centered both horizontally (line 5) and vertically (line 6) in the area below the photo.
<br /><code><br /> Text {<br /> x: 0; y: 235<br /> text: &quot;Voringsfossen&amp;quot;<br /> font.pixelSize: 20<br /> width: 300; horizontalAlignment: Text.AlignHCenter<br /> height: 65; verticalAlignment: Text.AlignVCenter<br /> }<br /></code>
<br /><code><br /> Text {<br /> x: 0; y: 235<br /> text: "Voringsfossen"<br /> font.pixelSize: 20<br /> width: 300; horizontalAlignment: Text.AlignHCenter<br /> height: 65; verticalAlignment: Text.AlignVCenter<br /> }<br /></code>
<br />It is important to note that the property &lt;code&amp;gt;horizontalAlignment&amp;lt;/code&amp;gt; only has an effect if a width is specified. Without a width, the QML runtime wouldn't know where to position the text (just try it out). The same is true for the property &lt;code&amp;gt;verticalAlignment&amp;lt;/code&amp;gt;. So, whenever we use &lt;code&amp;gt;horizontalAlignment&amp;lt;/code&amp;gt; and &lt;code&amp;gt;verticalAlignment&amp;lt;/code&amp;gt;, we must give &lt;code&amp;gt;width&amp;lt;/code&amp;gt; and &lt;code&amp;gt;height&amp;lt;/code&amp;gt;, respectively.
<br />It is important to note that the property <code>horizontalAlignment</code> only has an effect if a width is specified. Without a width, the QML runtime wouldn't know where to position the text (just try it out). The same is true for the property <code>verticalAlignment</code>. So, whenever we use <code>horizontalAlignment</code> and <code>verticalAlignment</code>, we must give <code>width</code> and <code>height</code>, respectively.
<br />h2. Custom Properties
<br />h2. Custom Properties
<br />Before we create our own properties, we create a real need for them. Our next goal is to show three photos side by side. We achieve this by simply instantiating the photo from &lt;code&amp;gt;BasicSteps_2.qml&amp;lt;/code&amp;gt; three times and by enclosing these three rectangles by a big rectangle (see [[BasicSteps_3 | BasicSteps_3.qml]] for the complete source code).
<br />Before we create our own properties, we create a real need for them. Our next goal is to show three photos side by side. We achieve this by simply instantiating the photo from <code>BasicSteps_2.qml</code> three times and by enclosing these three rectangles by a big rectangle (see [[BasicSteps_3 | BasicSteps_3.qml]] for the complete source code).
<br /><code>
<br /><code>
<br />// File: BasicSteps_3.qml<br />import QtQuick 1.0
<br />// File: BasicSteps_3.qml<br />import QtQuick 1.0
Line 65: Line 65:
// Photo 3<br /> Rectangle {<br /> x: 2 * 300; y: 0<br /> …<br /> }<br />}<br /></code>
// Photo 3<br /> Rectangle {<br /> x: 2 * 300; y: 0<br /> …<br /> }<br />}<br /></code>


Photo 1, 2 and 3 are identical copies of the &lt;code&amp;gt;Rectangle&amp;lt;/code&amp;gt; from &lt;code&amp;gt;BasicSteps_2.qml&amp;lt;/code&amp;gt; - except for the properties &lt;code&amp;gt;x&amp;lt;/code&amp;gt; and &lt;code&amp;gt;y&amp;lt;/code&amp;gt;. The position of the photo rectangles are relative to the enclosing rectangle, which has three times the width of a single photo rectangle and the same height. The photos are placed at the x-positions 0, 300 and 600 and at y-position 0 such that they appear side by side. As we see in lines 5 and 21, we can use arbitrary JavaScript expressions for the property values. In the example, we use the expressions &lt;code&amp;gt;3 * 300&amp;lt;/code&amp;gt; and &lt;code&amp;gt;2 * 300&amp;lt;/code&amp;gt;.
Photo 1, 2 and 3 are identical copies of the <code>Rectangle</code> from <code>BasicSteps_2.qml</code> - except for the properties <code>x</code> and <code>y</code>. The position of the photo rectangles are relative to the enclosing rectangle, which has three times the width of a single photo rectangle and the same height. The photos are placed at the x-positions 0, 300 and 600 and at y-position 0 such that they appear side by side. As we see in lines 5 and 21, we can use arbitrary JavaScript expressions for the property values. In the example, we use the expressions <code>3 * 300</code> and <code>2 * 300</code>.


With these changes, we see the same photo three times. By changing the properties &lt;code&amp;gt;source&amp;lt;/code&amp;gt; and &lt;code&amp;gt;text&amp;lt;/code&amp;gt;, we can easily change the image and the title of the photos.
With these changes, we see the same photo three times. By changing the properties <code>source</code> and <code>text</code>, we can easily change the image and the title of the photos.


The code isn't well written and smells of heavy code duplication. We'll fix the duplication from the three almost identical photo rectangles in the next module [[Qt_Quick_Tutorial_Components | Components]]. We'll fix the duplication from the magical numbers like 300, 25, 65 or 20 right way - by introducing properties.
The code isn't well written and smells of heavy code duplication. We'll fix the duplication from the three almost identical photo rectangles in the next module [[Qt_Quick_Tutorial_Components | Components]]. We'll fix the duplication from the magical numbers like 300, 25, 65 or 20 right way - by introducing properties.


The worst offender is the magic number 300, which occurs 13 times. So, if we want to change the size of our photo frames to, say, 400, we must perform 13 changes - and will typically forget to change at least one occurrence. The solution is to introduce a property &lt;code&amp;gt;frameSize&amp;lt;/code&amp;gt; at the beginning of the big rectangle and replace every occurrence of 300 by &lt;code&amp;gt;frameSize&amp;lt;/code&amp;gt;. Similarly, we eliminate the magic numbers 10, 25 and 65 by introducing the properties &lt;code&amp;gt;leftMargin&amp;lt;/code&amp;gt;, &lt;code&amp;gt;topMargin&amp;lt;/code&amp;gt; and &lt;code&amp;gt;bottomMargin&amp;lt;/code&amp;gt;, respectively, and by replacing every occurrence of these magic numbers by its properties. We also spot that &lt;code&amp;gt;235 = 300 - 65 = frameSize - bottomMargin&amp;lt;/code&amp;gt; and replace every occurrence of 235 by the expression &lt;code&amp;gt;frameSize - bottomMargin&amp;lt;/code&amp;gt;. While we are on a roll, we also replace the RGB value &lt;code&amp;gt;&quot;#FFF8DC&amp;quot;&lt;/code&amp;gt; by the property &lt;code&amp;gt;frameColor&amp;lt;/code&amp;gt;. After all these modifications, the code for the enclosing rectangle and photo 3 looks as follows (see [[BasicSteps_4 | BasicSteps_4.qml]] for the complete code):
The worst offender is the magic number 300, which occurs 13 times. So, if we want to change the size of our photo frames to, say, 400, we must perform 13 changes - and will typically forget to change at least one occurrence. The solution is to introduce a property <code>frameSize</code> at the beginning of the big rectangle and replace every occurrence of 300 by <code>frameSize</code>. Similarly, we eliminate the magic numbers 10, 25 and 65 by introducing the properties <code>leftMargin</code>, <code>topMargin</code> and <code>bottomMargin</code>, respectively, and by replacing every occurrence of these magic numbers by its properties. We also spot that <code>235 = 300 - 65 = frameSize - bottomMargin</code> and replace every occurrence of 235 by the expression <code>frameSize - bottomMargin</code>. While we are on a roll, we also replace the RGB value <code>"#FFF8DC"</code> by the property <code>frameColor</code>. After all these modifications, the code for the enclosing rectangle and photo 3 looks as follows (see [[BasicSteps_4 | BasicSteps_4.qml]] for the complete code):


<code><br />Rectangle {<br /> property int frameSize: 300<br /> property int leftMargin: 10<br /> property int topMargin: 25<br /> property int bottomMargin: 65<br /> property int fontSize: 20<br /> property color frameColor: &quot;#FFF8DC&amp;quot; // cornsilk
<code><br />Rectangle {<br /> property int frameSize: 300<br /> property int leftMargin: 10<br /> property int topMargin: 25<br /> property int bottomMargin: 65<br /> property int fontSize: 20<br /> property color frameColor: "#FFF8DC" // cornsilk


width: 3 * frameSize; height: frameSize
width: 3 * frameSize; height: frameSize
Line 81: Line 81:
// Photo 3<br /> Rectangle {<br /> x: 2 * frameSize; y: 0<br /> width: frameSize; height: frameSize<br /> color: frameColor
// Photo 3<br /> Rectangle {<br /> x: 2 * frameSize; y: 0<br /> width: frameSize; height: frameSize<br /> color: frameColor


Image {<br /> x: leftMargin; y: topMargin<br /> source: &quot;cotton_grass.jpg&amp;quot;<br /> }
Image {<br /> x: leftMargin; y: topMargin<br /> source: "cotton_grass.jpg"<br /> }


Text {<br /> x: 0; y: frameSize - bottomMargin<br /> text: &quot;Cotton Grass&amp;quot;<br /> font.pixelSize: fontSize<br /> width: frameSize; horizontalAlignment: Text.AlignHCenter<br /> height: bottomMargin; verticalAlignment: Text.AlignVCenter<br /> }<br /> }<br /></code>
Text {<br /> x: 0; y: frameSize - bottomMargin<br /> text: "Cotton Grass"<br /> font.pixelSize: fontSize<br /> width: frameSize; horizontalAlignment: Text.AlignHCenter<br /> height: bottomMargin; verticalAlignment: Text.AlignVCenter<br /> }<br /> }<br /></code>


The general syntax for a '''custom property''' is<br /><code><br /> property &lt;type&amp;gt; &lt;name&amp;gt;[: &lt;value&amp;gt;]<br /></code><br />The keyword &lt;code&amp;gt;property&amp;lt;/code&amp;gt; is followed by the name of the type, &lt;code&amp;gt;&amp;#60;type&amp;amp;#62;&lt;/code&amp;gt;, and the name of the property, &lt;code&amp;gt;&amp;#60;name&amp;amp;#62;&lt;/code&amp;gt;. The default value, &lt;code&amp;gt;&amp;#60;value&amp;amp;#62;&lt;/code&amp;gt;, for the property is optional. For example, the line<br /><code><br /> property int frameSize: 300<br /></code><br />defines a property with name &lt;code&amp;gt;frameSize&amp;lt;/code&amp;gt;, which is of integer type and which has the default value 300.
The general syntax for a '''custom property''' is<br /><code><br /> property <type> <name>[: <value>]<br /></code><br />The keyword <code>property</code> is followed by the name of the type, <code>&amp;#60;type&amp;amp;#62;</code>, and the name of the property, <code>&amp;#60;name&amp;amp;#62;</code>. The default value, <code>&amp;#60;value&amp;amp;#62;</code>, for the property is optional. For example, the line<br /><code><br /> property int frameSize: 300<br /></code><br />defines a property with name <code>frameSize</code>, which is of integer type and which has the default value 300.


So far, we glossed over the '''scoping rules''' for properties, because they worked as expected. The properties of a parent instance are accessible by the child instances, the grandchild instances and so on all the way down the instance tree. This is why, for example, the property &lt;code&amp;gt;leftMargin&amp;lt;/code&amp;gt; can be used in the grandchild &lt;code&amp;gt;Image&amp;lt;/code&amp;gt; of the outermost &lt;code&amp;gt;Rectangle&amp;lt;/code&amp;gt;, where it is defined. For the moment, we can live with this scoping rule, which we'll amend when needed.
So far, we glossed over the '''scoping rules''' for properties, because they worked as expected. The properties of a parent instance are accessible by the child instances, the grandchild instances and so on all the way down the instance tree. This is why, for example, the property <code>leftMargin</code> can be used in the grandchild <code>Image</code> of the outermost <code>Rectangle</code>, where it is defined. For the moment, we can live with this scoping rule, which we'll amend when needed.


&quot;Module 2 - Components&amp;quot;:http://developer.qt.nokia.com/wiki/Qt_Quick_Tutorial_Components
"Module 2 - Components":http://developer.qt.nokia.com/wiki/Qt_Quick_Tutorial_Components


&quot;Tutorial Main Page&amp;quot;:http://developer.qt.nokia.com/wiki/Qt_Quick_Tutorial
"Tutorial Main Page":http://developer.qt.nokia.com/wiki/Qt_Quick_Tutorial

Revision as of 14:32, 24 February 2015



[toc align_right="yes" depth="3"]

Qt Quick Tutorial: Module 1 - Basics

Components and Properties

No, we don't start with a QML program printing "Hello world!". We start with something much more exciting: a QML program that draws a blue rectangle of 300x300 pixels.

<br />// File: BasicSteps_1.qml

import QtQuick 1.0

Rectangle {<br /> width: 300<br /> height: 300<br /> color: "blue"<br />}<br />

We run QML viewer to see the result of our work:

> qmlviewer BasicSteps_1.qml &amp;amp;<code>

Yes, the above QML code, indeed, produces a blue rectangle. A self-contained piece of QML code as the one above is called a '''QML document''' (see also "QML Documents":http://doc.qt.nokia.com/4.7-snapshot/qdeclarativedocuments.html). A QML document is a piece of QML code that contains at least one <code>import

statement and exactly one top-level component. In our example,

Rectangle

is the single top-level component. Generally, a QML document corresponds to a file, but it could also be text stored in a string or a URL pointing to QML document stored on a remote server. The statement

import Qt 4.7

makes all the QML components of Qt 4.7 available to our QML document. Qt 4.7 comes with built-in components like Rectangle, Text, ListView, WebView, Flipable, Animation and many more (see "QML Elements":http://doc.qt.nokia.com/4.7-snapshot/qdeclarativeelements.html for a complete list). Components are the QML equivalents of C++ classes. They have properties, methods (member functions), signals and slots. The occurrence of

Rectangle

in lines 5-9 is an instance of a

Rectangle

component: a blue 300x300 pixel instance of a

Rectangle

component. In the Qt documentation, element is often used as a synonym for component. Components with a visual representation like a Rectangle or Text are called items. Component names always start with an uppercase letter followed by zero or more letters, digits and underscores. A instance of a component is characterised by its properties, which are name-value pairs. The

Rectangle

instance above has three properties

width

,

height

and

color

with the values

300

,

300

and

blue

, respectively. Property names always start with a lowercase letter followed by zero or more letters, digits and underscores. Properties are type-safe. Hence, the line

width: "Oslo"

would be illegal, because the property

width

expects a number of type real. QML supports the following basic types: bool, color, date, font, int, list, point, real, rect, size, string, time, url.

Several properties can be written in one line separated by semicolon:

<br />width: 300; height: 300<br />color: "blue"<br />

The order of properties is irrelevant. We could rewrite the

Rectangle

as

<br />// File: BlueRectangle.qml<br />Rectangle {<br /> height: 300<br /> width: 300<br /> color: "blue"<br />}<br />

and the result would be the same.

Comments are marked in QML in the same way as in C++. Comments to the end of the line start with

//

. Line 1 of our example contains such a comment. Multi-line comments start with

/*

and end with

*/

.


h2. Composition of Components


The excitement about our blue rectangle is wearing off by now, isn't it? So, let us turn the blue rectangle into a photo frame with a photo in the center, a tag line below the photo and a oldlace colored background. We position a QML

Image

component for the photo and a

Text

component for the title on the

Rectangle

component and change the color to "oldlace". We can use the SVG color names directly in QML.

<br />// File: PlacingElements.qml<br />import QtQuick 1.0
<br />Rectangle {<br /> width: 180<br /> height: 135<br /> color: "oldlace"<br /> Image {<br /> x: 10; y: 10<br /> width: 160<br /> height: 100<br /> fillMode: Image.PreserveAspectCrop<br /> source: "images/image01.jpg"<br /> }<br /> Text {<br /> x: 10; y: 115<br /> width: 100<br /> text: "temple"<br /> }<br />}<br />


We have chosen a

Rectangle

element as the root of our element hierarchy. We place an

Image

and

Text

element inside. Children in a QML element tree are always placed relative to its parents. The

x

and

y

coordinate refers to the top-left … etc
As the image is 280x210 pixels, this position centers the image horizontally and vertically within the rectangle. The

source

property tells the QML runtime where to look for the image, which is stored in the file

"voringsfossen1.jpg"

. The image file is located in the same directory as the QML file

BasicSteps.qml

. In general, the

source

property takes a URL. The image could be located anywhere in the Internet or our local file system.
The

Text

is positioned at 10 pixels to the right and 265 pixels down from the top left corner of the rectangle. The displayed text is "Voringsfossen", which is the name of Norway's most famous and highest waterfall. Again,

Text

is a child of

Rectangle

.
This simple example of a photo frame shows how to compose basic components into a more complex components. The components or strictly speaking the component instances are arranged in a tree. In our example, the

Rectangle

is the root of the tree and

Image

and

Text

are the root's children. The children could again have children of their own and so on. These instance trees mirror the instance trees of Qt's graphics items or widgets.
The result won't win us a design prize, but it is a good first shot. Let us improve it step by step. As the title shouldn't look crammed into the frame below the photo, we move the photo 20 pixels up. We just change

Image

's property

y

to

25

.

<br /> Image {<br /> x: 10; y: 25<br /> source: "voringsfossen1.jpg"<br /> }<br />


We want the title to be a bit bigger, say 20 pixels (line 4), and want it to be centered both horizontally (line 5) and vertically (line 6) in the area below the photo.


<br /> Text {<br /> x: 0; y: 235<br /> text: "Voringsfossen"<br /> font.pixelSize: 20<br /> width: 300; horizontalAlignment: Text.AlignHCenter<br /> height: 65; verticalAlignment: Text.AlignVCenter<br /> }<br />


It is important to note that the property

horizontalAlignment

only has an effect if a width is specified. Without a width, the QML runtime wouldn't know where to position the text (just try it out). The same is true for the property

verticalAlignment

. So, whenever we use

horizontalAlignment

and

verticalAlignment

, we must give

width

and

height

, respectively.


h2. Custom Properties


Before we create our own properties, we create a real need for them. Our next goal is to show three photos side by side. We achieve this by simply instantiating the photo from

BasicSteps_2.qml

three times and by enclosing these three rectangles by a big rectangle (see BasicSteps_3.qml for the complete source code).

<br />// File: BasicSteps_3.qml<br />import QtQuick 1.0
<br />Rectangle {<br /> width: 3''' 300; height: 300

// Photo 1<br /> Rectangle {<br /> x: 0; y: 0<br /> …<br /> }

// Photo 2<br /> Rectangle {<br /> x: 300; y: 0<br /> …<br /> }

// Photo 3<br /> Rectangle {<br /> x: 2 * 300; y: 0<br /> …<br /> }<br />}<br />

Photo 1, 2 and 3 are identical copies of the

Rectangle

from

BasicSteps_2.qml

- except for the properties

x

and

y

. The position of the photo rectangles are relative to the enclosing rectangle, which has three times the width of a single photo rectangle and the same height. The photos are placed at the x-positions 0, 300 and 600 and at y-position 0 such that they appear side by side. As we see in lines 5 and 21, we can use arbitrary JavaScript expressions for the property values. In the example, we use the expressions

3 * 300

and

2 * 300

. With these changes, we see the same photo three times. By changing the properties

source

and

text

, we can easily change the image and the title of the photos.

The code isn't well written and smells of heavy code duplication. We'll fix the duplication from the three almost identical photo rectangles in the next module Components. We'll fix the duplication from the magical numbers like 300, 25, 65 or 20 right way - by introducing properties.

The worst offender is the magic number 300, which occurs 13 times. So, if we want to change the size of our photo frames to, say, 400, we must perform 13 changes - and will typically forget to change at least one occurrence. The solution is to introduce a property

frameSize

at the beginning of the big rectangle and replace every occurrence of 300 by

frameSize

. Similarly, we eliminate the magic numbers 10, 25 and 65 by introducing the properties

leftMargin

,

topMargin

and

bottomMargin

, respectively, and by replacing every occurrence of these magic numbers by its properties. We also spot that

235 = 300 - 65 = frameSize - bottomMargin

and replace every occurrence of 235 by the expression

frameSize - bottomMargin

. While we are on a roll, we also replace the RGB value

"#FFF8DC"

by the property

frameColor

. After all these modifications, the code for the enclosing rectangle and photo 3 looks as follows (see BasicSteps_4.qml for the complete code):

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

width: 3 * frameSize; height: frameSize



// Photo 3<br /> Rectangle {<br /> x: 2 * frameSize; y: 0<br /> width: frameSize; height: frameSize<br /> color: frameColor

Image {<br /> x: leftMargin; y: topMargin<br /> source: "cotton_grass.jpg"<br /> }

Text {<br /> x: 0; y: frameSize - bottomMargin<br /> text: "Cotton Grass"<br /> font.pixelSize: fontSize<br /> width: frameSize; horizontalAlignment: Text.AlignHCenter<br /> height: bottomMargin; verticalAlignment: Text.AlignVCenter<br /> }<br /> }<br />

The general syntax for a custom property is

<br /> property <type> <name>[: <value>]<br />


The keyword

property

is followed by the name of the type,

&amp;#60;type&amp;amp;#62;

, and the name of the property,

&amp;#60;name&amp;amp;#62;

. The default value,

&amp;#60;value&amp;amp;#62;

, for the property is optional. For example, the line

<br /> property int frameSize: 300<br />


defines a property with name

frameSize

, which is of integer type and which has the default value 300. So far, we glossed over the scoping rules for properties, because they worked as expected. The properties of a parent instance are accessible by the child instances, the grandchild instances and so on all the way down the instance tree. This is why, for example, the property

leftMargin

can be used in the grandchild

Image

of the outermost

Rectangle

, where it is defined. For the moment, we can live with this scoping rule, which we'll amend when needed.

"Module 2 - Components":http://developer.qt.nokia.com/wiki/Qt_Quick_Tutorial_Components

"Tutorial Main Page":http://developer.qt.nokia.com/wiki/Qt_Quick_Tutorial