Modern mobile applications with Qt and QML: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
 
No edit summary
Line 1: Line 1:
'''English''' [http://qt-devnet.developpez.com/tutoriels/qt-quick/qml/applications-mobiles-modernes/ French] ''[qt-devnet.developpez.com]''
[toc align_right=&quot;yes&amp;quot; depth=&quot;3&amp;quot;]<br />[[Category:Developing_with_Qt::Qt Quick]]<br />[[Category:Learning]]


=Modern Mobile Applications with Qt and <span class="caps">QML</span>=
'''English''' [&quot;French&amp;quot;:http://qt-devnet.developpez.com/tutoriels/qt-quick/qml/applications-mobiles-modernes/]


Qt is a flexible and powerful framework for creating cross-platform applications. <span class="caps">QML</span> is now part of Qt, providing a markup language which gives complete freedom in development of user interfaces.
= Modern Mobile Applications with Qt and QML =


A good way to see the power of Qt is to start coding with it. Let’s write a simple application using Qt and <span class="caps">QML</span>. This will be an application I called 4Toddler; the application will start in full-screen mode and it has just two buttons placed in the top right corner of the window: '''About''' and '''Close'''. The main function is to display a random image with a fireworks effect and with a random sound effect.
Qt is a flexible and powerful framework for creating cross-platform applications. QML is now part of Qt, providing a markup language which gives complete freedom in development of user interfaces.


The User interface will be written with <span class="caps">QML</span>; the backbone is written in Qt C++.
A good way to see the power of Qt is to start coding with it. Let's write a simple application using Qt and QML. This will be an application I called 4Toddler; the application will start in full-screen mode and it has just two buttons placed in the top right corner of the window: '''About''' and '''Close'''. The main function is to display a random image with a fireworks effect and with a random sound effect.


==Create new project==
The User interface will be written with QML; the backbone is written in Qt C+''.
<br />h2. Create new project
<br />If you do not have Qt already installed, visit &quot;Qt download page&amp;quot;:http://qt.nokia.com/downloads/ to download Qt SDK for your platform and install it.
<br />Launch Qt Creator, select '''File''' <s>&gt; '''New File or Project'''. In the new dialog select '''Qt C++ Project'''</s>&gt; '''Qt Gui Application''', and then click '''Choose…'''
<br />[[Image:http://appdeveloper.intel.com/sites/files/1-qt-qml-art.png|screenshot]]
<br />In the new window: type project name, select path to the project folder and then click '''Next'''.
<br />[[Image:http://appdeveloper.intel.com/sites/files/2-qt-qml-art.png|screenshot]]
<br />In the next window: uncheck '''Generate form''' option. We do not need to generate a form. Click '''Next'''
<br />[[Image:http://appdeveloper.intel.com/sites/files/3-qt-qml-art.png|screenshot]]
<br />In the last window: just click '''Finish'''.
<br />[[Image:http://appdeveloper.intel.com/sites/files/4-qt-qml-art.png|http://appdeveloper.intel.com/sites/files/4-qt-qml-art.png]]
<br />The application skeleton is ready, now we can proceed to code the logic and design the UI.
<br />h2. Code core logic in C''+


If you do not have Qt already installed, visit [http://qt.nokia.com/downloads/ Qt download page] ''[qt.nokia.com]'' to download Qt <span class="caps">SDK</span> for your platform and install it.
First we need to add the &quot;''qt-declarative''&quot;:http://doc.qt.nokia.com/4.7/qtdeclarative.html module to our project. This is the module that provides a widget in which a QML interface is displayed.


Launch Qt Creator, select '''File''' -&gt; '''New File or Project'''. In the new dialog select '''Qt C++ Project''' -&gt; '''Qt Gui Application''', and then click '''Choose…'''
Open project file &amp;#40;''4Toddler.pro''&amp;#41; and append the line


[[Image:1-qt-qml-art.png|screenshot]]
<code>QT ''= core gui<code>
<br />with ''declarative''
<br /></code>QT''= core gui declarative</code>


In the new window: type project name, select path to the project folder and then click '''Next'''.
Now we need to change the base class for our main window. Replace ''QMainWindow'' with ''QDeclarativeView'' and include ''QDeclarativeView''


[[Image:2-qt-qml-art.png|screenshot]]
<code><br />#include &lt;QDeclarativeView&amp;gt;<br />class MainWindow : public QDeclarativeView<br />{<br /> …<br />}<br /></code>


In the next window: uncheck '''Generate form''' option. We do not need to generate a form. Click '''Next'''
Also we need to cut off ''QMainWindow(parent)'' from the MainWindow constructor; we do not need this initialization anymore.


[[Image:3-qt-qml-art.png|screenshot]]
<code><br />MainWindow::MainWindow(QWidget *parent)<br />{<br /> Init();<br />}<br /></code>


In the last window: just click '''Finish'''.
If you launch the application right now you will see an empty window. This is because we have not initialized or created our QML interface yet.


[[Image:4-qt-qml-art.png]]
== Add QML interface ==


The application skeleton is ready, now we can proceed to code the logic and design the UI.
Let's add a new file to our project: right click on the project in the projects explorer window.


==Code core logic in C++==
[[Image:http://appdeveloper.intel.com/sites/files/5-qt-qml-art.png|http://appdeveloper.intel.com/sites/files/5-qt-qml-art.png]]


First we need to add the [http://doc.qt.nokia.com/4.7/qtdeclarative.html ''qt-declarative''] ''[doc.qt.nokia.com]'' module to our project. This is the module that provides a widget in which a <span class="caps">QML</span> interface is displayed.
'''Add New''' then select '''Qt''' section and '''Qt QML File''' in the templates list and click '''Choose…'''
 
[[Image:http://appdeveloper.intel.com/sites/files/6-qt-qml-art.png|http://appdeveloper.intel.com/sites/files/6-qt-qml-art.png]]
 
Type the file name in the '''Name''' field, click '''Next''' then '''Finish''' in the next window.


Open project file (''4Toddler.pro'') and append the line
[[Image:http://appdeveloper.intel.com/sites/files/7-qt-qml-art.png|http://appdeveloper.intel.com/sites/files/7-qt-qml-art.png]]


with ''declarative''
The wizard will create and open the new QML file in the editor. There is just one '''Rectangle''' element inside it. This will be the root element for our user interface. Let's add some new properties to this element.


Now we need to change the base class for our main window. Replace ''QMainWindow'' with ''QDeclarativeView'' and include ''QDeclarativeView''
''Note: some versions of Qt Creator will add a Hello World text element centered in the Rectangle. Remove the text element before proceeding.''


Also we need to cut off ''QMainWindow(parent)'' from the MainWindow constructor; we do not need this initialization anymore.
<code><br />Rectangle<br />{<br /> // ID of this element. Using this ID we can access the element and its properties from other elements<br /> id: canvas<br /> // Background color, black in this case<br /> color: &quot;black&amp;quot;<br /> // Change sizes of this element to fill the parent<br /> anchors.fill: parent<br /> // Element can receive focus<br /> focus: true<br />}<br /></code>


If you launch the application right now you will see an empty window. This is because we have not initialized or created our <span class="caps">QML</span> interface yet.
There is nothing special for now, just black background.


==Add <span class="caps">QML</span> interface==
== Multilingual ==


Let’s add a new file to our project: right click on the project in the projects explorer window.
During the remainder of this tutorial we will shift back and forth between QML and C++ development.


[[Image:5-qt-qml-art.png]]
We need to add some initialization code for our QML interface by defining a new method inside the '''mainwindow.h''' file …


'''Add New''' then select '''Qt''' section and '''Qt <span class="caps">QML</span> File''' in the templates list and click '''Choose…'''
<code>void Init();<code>


[[Image:6-qt-qml-art.png]]
.. And implementing it in the '''mainwindow.cpp''' file


Type the file name in the '''Name''' field, click '''Next''' then '''Finish''' in the next window.
</code><br />void MainWindow::Init()<br />{<br /> // Path to the content folder<br /> QString contentPath;


[[Image:7-qt-qml-art.png]]
#ifdef QT_DEBUG<br /> // In the debug version of our project this is a path to the project folder<br /> contentPath = &quot;D:/MyProjects/QT/4Toddler&amp;quot;;<br />#else<br /> // In the release version - path to the application folder<br /> contentPath = QApplication::applicationDirPath();<br />#endif<br /> setFocusPolicy(Qt::StrongFocus);<br /> // Change QML document sizes to fit the main window<br /> setResizeMode(QDeclarativeView::SizeRootObjectToView);<br /> // Load QML file<br /> setSource(QUrl::fromLocalFile&amp;amp;#40;contentPath + &quot;/main.qml&amp;quot;&amp;#41;);<br />}<br /><code>


The wizard will create and open the new <span class="caps">QML</span> file in the editor. There is just one '''Rectangle''' element inside it. This will be the root element for our user interface. Let’s add some new properties to this element.
Now we need to replace one line in the '''main.cpp''' file


''Note: some versions of Qt Creator will add a Hello World text element centered in the Rectangle. Remove the text element before proceeding.''
</code><br />int main(int argc, char *argv[])<br />{<br /> …<br /> w.show();<br /> …<br />}<br /><code>


There is nothing special for now, just black background.
With


==Multilingual==
</code><br />int main(int argc, char *argv[])


During the remainder of this tutorial we will shift back and forth between <span class="caps">QML</span> and C++ development.
{<br /> <br /> w.showFullScreen();<br /> …<br />}<br /><code>


We need to add some initialization code for our <span class="caps">QML</span> interface by defining a new method inside the '''mainwindow.h''' file …
This will force our window to open in full-screen mode.


.. And implementing it in the '''mainwindow.cpp''' file
== Structure code with components ==


Now we need to replace one line in the '''main.cpp''' file
Before we launch our application, let's add two buttons. One is to display '''About''' dialog and the second to '''Close''' our window. We do not need to implement buttons twice, we going to create a &quot;component&amp;quot;:http://doc.qt.nokia.com/4.7-snapshot/qml-extending-types.html and use it every time we need to add a new button by overriding just a few properties.


With
Let's add the new Qml file - '''WindowButton.qml''' to our project. ''Note the filename begins with a capital letter — this signifies it defines a QML component.''


This will force our window to open in full-screen mode.
</code><br />Image<br />{<br /> // ID of this element<br /> id: button<br /> // The MouseArea item enables simple mouse handling<br /> MouseArea<br /> {<br /> anchors.fill: parent<br /> id: mouseArea<br /> // On click call callback() handler<br /> onClicked: callback()<br /> }<br />}<br /><code>


==Structure code with components==
Now we can add two buttons to our window


Before we launch our application, let’s add two buttons. One is to display '''About''' dialog and the second to '''Close''' our window. We do not need to implement buttons twice, we going to create a [http://doc.qt.nokia.com/4.7-snapshot/qml-extending-types.html component] ''[doc.qt.nokia.com]'' and use it every time we need to add a new button by overriding just a few properties.
</code><br />// Place items in row


Let’s add the new Qml file – '''WindowButton.qml''' to our project. ''Note the filename begins with a capital letter — this signifies it defines a <span class="caps">QML</span> component.''
Row<br />{<br /> // Right side of the item is anchored to the right side of the parent element<br /> anchors.right: parent.right<br /> // Right margin<br /> anchors.rightMargin: 4<br /> // Top side of the item is anchored to the top side of the parent element<br /> anchors.top: parent.top<br /> // Top margin<br /> anchors.topMargin: 4<br /> // Margins for children elements<br /> spacing: 4<br /> WindowButton<br /> {<br /> // Button to display the About dialog<br /> id: about<br /> // Path to background picture. This is a relative path to the path of this QML file<br /> source: &quot;about.png&amp;quot;<br /> // Callback method, which will be called on mouse click<br /> // onClicked: callback()<br /> function callback()<br /> {<br /> }<br /> }<br /> WindowButton<br /> {<br /> // Button to close window<br /> id: exit<br /> source: &quot;exit.png&amp;quot;<br /> function callback()<br /> {<br /> }<br /> }<br />}<br /><code>


Now we can add two buttons to our window
== Communicate between QML and C++ ==


==Communicate between <span class="caps">QML</span> and C++==
Now we should implement both '''callback()''' methods. To close the window we will call the '''Quit''' function of the main window. Now we will see how Qt and QML communicate. Methods will be implemented inside Qt and then called from the QML file.


Now we should implement both '''callback()''' methods. To close the window we will call the '''Quit''' function of the main window. Now we will see how Qt and <span class="caps">QML</span> communicate. Methods will be implemented inside Qt and then called from the <span class="caps">QML</span> file.
Let's add a new function to the '''mainwindow.h''' header file


Let’s add a new function to the '''mainwindow.h''' header file
</code>Q_INVOKABLE void Quit();</code>


And implementation in '''mainwindow.cpp''' file
And implementation in '''mainwindow.cpp''' file


Now we need to “tell” <span class="caps">QML</span> about this method. Inside '''Init''' we should to add just one line:
<code><br />void MainWindow::Quit()
 
{
 
QApplication::quit();
 
}<br /></code>


Now we can access '''window''' object’s functions declared as '''Q_INVOKABLE''' from <span class="caps">QML</span>. '''Window''' here is just an example, you could use any object name you want.
Now we need to &quot;tell&amp;quot; QML about this method. Inside '''Init''' we should to add just one line:


Let’s add '''callback()''' function implementation to close button
<code>rootContext()<s>&gt;setContextProperty(&quot;window&amp;quot;, this);<code>
<br />Now we can access '''window''' object's functions declared as '''Q_INVOKABLE''' from QML. '''Window''' here is just an example, you could use any object name you want.
<br />Let's add '''callback()''' function implementation to close button
<br /></code><br />function callback()<br />{<br /> window.Quit();<br />}<br /><code>
<br />h2. Visualize state and add animation
<br />Ok, the application can be launched. Launch it and click the '''Close''' button. You see? State of the button is not changed after click; it looks like the button is just inactive. Let's add state changes for normal and clicked states.
<br /></code><br />Image<br />{<br /> …<br /> states:[<br /> State<br /> {<br /> // Name of the state<br /> name: &quot;hovered&amp;quot;<br /> // When condition. Item will go to this state if condition is true<br /> // In this case on mouse click<br /> when: mouseArea.pressed<br /> // Which properties will be changed in that state<br /> // In this case</s> opacity<br /> PropertyChanges { target: button; opacity: 1}<br /> },


==Visualize state and add animation==
State<br /> {<br /> name: &quot;normal&amp;quot;<br /> // This state will be activated if mouse button is not pressed<br /> when: mouseArea.pressed == false<br /> PropertyChanges { target: button; opacity: 0.7; }<br /> }<br /> ]<br />}<br /><code>


Ok, the application can be launched. Launch it and click the '''Close''' button. You see? State of the button is not changed after click; it looks like the button is just inactive. Let’s add state changes for normal and clicked states.
Item will change state if the condition described in ''when'' property is true. You could change state manually by assigning state property.<br />Let's launch the application again. Ok, this time it looks more active. We can make our button nicer by adding some animation.


Item will change state if the condition described in ''when'' property is true. You could change state manually by assigning state property.<br /> Let’s launch the application again. Ok, this time it looks more active. We can make our button nicer by adding some animation.
</code><br />Image<br />{<br /> …<br /> Behavior on opacity<br /> {<br /> // Animaion step is a 100 milliseconds<br /> // On every iteration opacity will increase or descrease with step equals to 0,1<br /> NumberAnimation { duration: 100 }<br /> }<br />}<br /><code>


The ''Behavior'' is a simple and flexible way to create animations. This element allows you to specify a default animation for a property change.
The ''Behavior'' is a simple and flexible way to create animations. This element allows you to specify a default animation for a property change.
Line 111: Line 141:
Launch the application and try to click on '''About''' or '''Close''' buttons. This looks much better!
Launch the application and try to click on '''About''' or '''Close''' buttons. This looks much better!


[[Image:8-qt-qml-art.png]]
[[Image:http://appdeveloper.intel.com/sites/files/8-qt-qml-art.png|http://appdeveloper.intel.com/sites/files/8-qt-qml-art.png]]


We will implement the '''About''' dialog only using <span class="caps">QML</span>. Dialog will appear on the screen when '''About''' button is clicked and disappear when the user clicks inside the button or on the background.
We will implement the '''About''' dialog only using QML. Dialog will appear on the screen when '''About''' button is clicked and disappear when the user clicks inside the button or on the background.


Let’s add '''About.qml''' file to our project.
Let's add '''About.qml''' file to our project.
 
</code><br />// Parent element for dialog window<br />Rectangle<br />{<br /> id: about<br /> // Function to display dialog window<br /> // This function just changes opacity of the main element to 1<br /> function show()<br /> {<br /> about.opacity = 1<br /> }<br /> // Function to hide dialog window<br /> // This function just changes opacity of the main element to 0<br /> function hide()<br /> {<br /> about.opacity = 0<br /> }<br /> // Transparent background<br /> color: &quot;transparent&amp;quot;<br /> // Opacity is 0 by default, dialog not visible<br /> opacity: 0<br /> // Anchors to parent width and height.<br /> width: parent.width<br /> height: parent.height<br /> // Element is visible if opacity &gt; 0<br /> // opacity &gt; 0<br /> visible: opacity &gt; 0<br /> // Child element to create semitransparent background<br /> Rectangle<br /> {<br /> anchors.fill: parent<br /> opacity: 0.5<br /> color: &quot;gray&amp;quot;<br /> }<br /> // Body of the dialog window<br /> Rectangle<br /> {<br /> id: dialog
 
// Fixed width and height<br /> width: 360<br /> height: 230<br /> // To make dialog centered inside parent we need to calculate its x and y coordinates<br /> x: parent.width / 2 - dialog.width / 2<br /> y: parent.height / 2 - dialog.height / 2<br /> // Place dialog on top of other elements<br /> z: 10<br /> border.color: &quot;gray&amp;quot;<br /> Text<br /> {<br /> text: &quot;4 Toddler&amp;quot;<br /> font.bold: true<br /> font.pixelSize: 22
 
anchors.horizontalCenter: parent.horizontalCenter<br /> anchors.verticalCenter: parent.verticalCenter<br /> }<br /> }<br /> Behavior on opacity<br /> {<br /> NumberAnimation { duration: 100 }<br /> }<br /> MouseArea<br /> {<br /> anchors.fill: parent<br /> // Hide dialog on mouse click<br /> onClicked: hide()<br /> }<br />}<br /><code>


Take a look at the line
Take a look at the line
</code>visible: opacity &gt; 0</code>


As you can see, property can be assigned and can be calculated.
As you can see, property can be assigned and can be calculated.


Let’s add '''About''' dialog and callback() function implementation for the button '''About'''. In ''Main.qml'' file we need to declare the new About element.
Let's add '''About''' dialog and callback() function implementation for the button '''About'''. In ''Main.qml'' file we need to declare the new About element.
 
<code><br />Rectangle<br />{<br /> id: canvas<br /> ..<br /> About<br /> {<br /> id: aboutDlg<br /> }<br />}<br /></code>


And '''callback()''' function implementation
And '''callback()''' function implementation
<code>aboutDlg.show();<code>


to
to
</code><br />WindowButton<br />{<br /> id: about<br /> …<br /> function callback()<br /> {<br /> aboutDlg.show()<br /> }<br />}<br /><code>


Finally we need to implement the main functionality for our application.
Finally we need to implement the main functionality for our application.


The element to display a random icon on the screen will be an '''Image''' element. Let’s add a new file for the new element ''Block.qml''
The element to display a random icon on the screen will be an '''Image''' element. Let's add a new file for the new element - ''Block.qml''


Now we need to implement the keyboard handler. Handler will be implemented with '''JavaScript'''. Let’s add new ''main.js'' to our project.
</code><br />Image<br />{<br /> id: block;<br /> // New custom properties to change visibility of this element<br /> property bool remove: false<br /> property bool show: false<br /> opacity: 0<br /> fillMode: Image.Stretch<br /> states: [<br /> State<br /> {<br /> // State is used to remove element from the screen and destroy it<br /> name: &quot;remove&amp;quot;; when: remove  true
      PropertyChanges &amp;#123; target: block; opacity: 0 &amp;#125;
      StateChangeScript &amp;#123; script: block.destroy(1000) &amp;#125;
    &amp;#125;,
    State
    &amp;#123;
      // State is used to display element
      name: &amp;quot;show&amp;quot;; when: show  true<br /> PropertyChanges { target: block; opacity: 1 }<br /> }<br /> ]<br /> Behavior on opacity { NumberAnimation { duration: 300 } }<br />}<br /><code>


As you see in code above we should implement new property '''randomIcon''' and method '''PlaySound'''.
Now we need to implement the keyboard handler. Handler will be implemented with '''JavaScript'''. Let's add new ''main.js'' to our project.


Let’s add property declaration and method to access it to our ''mainwindow.h'' file.
</code>// Template for new elements<br />var component = Qt.createComponent(&quot;block.qml&amp;quot;)<br />// Max number of items on the screen<br />var maxBlocksCount = 10<br />// Array for the items<br />var blocksArray = new Array()<br />// Keyboard handler<br />function handleKey()<br />{<br /> // x coordinate is a random number from 0 to window with in pixels<br /> var x = Math.floor(Math.random() * canvas.width)<br /> // y coordinate is a random number from 0 to window height in pixels<br /> var y = Math.floor(Math.random() * canvas.height)<br /> // This function will create a new element on each call with random x and y coordinates<br /> createNewBlock(x, y)<br />}<br />// Function to create a new element<br />function createNewBlock(x, y)<br />{<br /> if(component.status != Component.Ready)<br /> {<br /> return false<br /> }<br /> // Remove items if number of items is more than maxBlocksCount<br /> if(blocksArray.length &gt; maxBlocksCount)<br /> {<br /> removeAllBlocks()<br /> }<br /> var newBlock = component.createObject(canvas)<br /> if(newBlock == null)<br /> {<br /> return false<br /> }<br /> // Path to image is available via randomIcon property of the main window<br /> var iconFile = window.randomIcon<br /> newBlock.source = (&quot;Icons/&amp;quot; + iconFile)<br /> newBlock.x = x<br /> newBlock.y = y<br /> // Change state to show<br /> newBlock.show = true<br /> blocksArray.push(newBlock)<br /> // Play random sound effect<br /> window.PlaySound()<br /> return true<br />}<br />// Function do remove all existings items<br />function removeAllBlocks()<br />{<br /> for(var i = 0; i &lt; blocksArray.length; +''i)<br /> {<br /> blocksArray[i].remove = true<br /> }<br /> while(blocksArray.length != 0)<br /> {<br /> blocksArray.pop()<br /> }<br />}<br /><code>
<br />As you see in code above we should implement new property '''randomIcon''' and method '''PlaySound'''.
<br />Let's add property declaration and method to access it to our ''mainwindow.h'' file.
<br /></code>Q_PROPERTY(QString randomIcon READ RandomIcon)</code>
<br /><code>QString RandomIcon();<code>
<br />Implementation in ''mainwindow.cpp'' file
<br /></code><br />QString MainWindow::RandomIcon()<br />{<br /> QStringList iconFilesList;<br /> QString searchPath = m_ContentPath'' &quot;/Icons/&amp;quot;;<br /> QDir directory = QDir(searchPath);<br /> QStringList filters;<br /> filters &lt;&lt; &quot;'''.png&amp;quot;;<br /> directory.setNameFilters(filters);<br /> // Get the list of the png files inside Icons directory<br /> iconFilesList = directory.entryList(QDir::AllEntries);<br /> // Generate random index of the element<br /> int fileIdx = qrand() % iconFilesList.count();
<br /> // Return file name<br /> return iconFilesList.at(fileIdx);<br />}<br /><code>
<br />Now we need to declare the method to play a random sound effect in ''mainwindow.h'' file
<br /></code>Q_INVOKABLE void PlaySound();</code>
<br />And implementation in ''mainwindow.cpp'' file
<br /><code><br />void MainWindow::PlaySound()<br />{<br /> QStringList soundFilesList;<br /> QDir directory = QDir(m_ContentPath + &quot;/Sounds/&amp;quot;);<br /> QStringList filters;<br /> filters &lt;&lt; &quot;'''.wav&amp;quot;;<br /> directory.setNameFilters(filters);<br /> // Wav files list inside Sounds directory<br /> soundFilesList = directory.entryList(QDir::AllEntries);<br /> // Generate random index of the element<br /> int fileIdx = qrand() % soundFilesList.count();<br /> // File name<br /> QString soundFile = m_ContentPath + &quot;/Sounds/&amp;quot; + soundFilesList.at(fileIdx);<br /> // Play file asynchronously<br /> QSound::play(soundFile);<br />}<br /></code>


Implementation in ''mainwindow.cpp'' file
Almost done. All we need is to add the keyboard handler to our parent QML element. But first we should include ''main.js'' file to ''main.qml'' file


Now we need to declare the method to play a random sound effect in ''mainwindow.h'' file
<code><br />import Qt 4.7<br />import &quot;main.js&amp;quot; as Main<br /></code>


And implementation in ''mainwindow.cpp'' file
Keyboard event handler for root element


Almost done. All we need is to add the keyboard handler to our parent <span class="caps">QML</span> element. But first we should include ''main.js'' file to ''main.qml'' file
<code><br />Rectangle<br />{<br /> id: canvas<br /> <br /> Keys.onPressed: {<br /> if(event.isAutoRepeat == false) {<br /> Main.handleKey()<br /> }<br /> }<br />}<br /></code>


Keyboard event handler for root element
That's all! Now you can launch the application and try to press any key on the keyboard. But… I almost forgot about the fireworks effect.


That’s all! Now you can launch the application and try to press any key on the keyboard. But… I almost forgot about the fireworks effect.
Let's add a new file called ''Fireworks.qml''. Why do we need a new file? Because this will be a reusable element, this will save time in the future.


Let’s add a new file called ''Fireworks.qml''. Why do we need a new file? Because this will be a reusable element, this will save time in the future.
<code><br />import Qt.labs.particles 1.0<br />Particles<br />{<br /> id: particles<br /> width: 1<br /> height: 1<br /> anchors.centerIn: parent<br /> emissionRate: 0<br /> lifeSpan: 700<br /> lifeSpanDeviation: 600<br /> angle: 0<br /> angleDeviation: 360<br /> velocity: 100<br /> velocityDeviation: 30<br /> source: randomImage()<br /> // Get random image path<br /> function randomImage()<br /> {<br /> // Array of the image files<br /> var images = [&quot;red.png&amp;quot;, &quot;blue.png&amp;quot;, &quot;green.png&amp;quot;, &quot;white.png&amp;quot;, &quot;yellow.png&amp;quot;]<br /> // Get random index of the array element<br /> var idx = Math.floor((Math.random() * 100)) % images.length<br /> // Return the relative image file path<br /> return (&quot;Stars/&amp;quot; + images[idx])<br /> }<br />}<br /></code>


Now we need to add our Firework element to the Block element. Open ''Block.qml'' file and add declaration of the new element
Now we need to add our Firework element to the Block element. Open ''Block.qml'' file and add declaration of the new element
<code><br />Image<br />{<br /> id: block<br /> …<br /> Firework<br /> {<br /> id: firework<br /> }<br /> …<br />}<br /></code>


To launch fireworks on item going to visible state we need to add just one line of code
To launch fireworks on item going to visible state we need to add just one line of code


to “show” state
<code>StateChangeScript { script: firework.burst(50); }<code>
 
to &quot;show&amp;quot; state
 
</code><br />State<br />{<br /> name: &quot;show&amp;quot;; when: show == true<br /> StateChangeScript { script: firework.burst(50)}<br /> PropertyChanges { target: block; opacity: 1 }<br />}<br /><code>


Launch application and press any key. Image appears on the screen with fireworks and sound effect.
Launch application and press any key. Image appears on the screen with fireworks and sound effect.


[[Image:9-qt-qml-art.png]]
[[Image:http://appdeveloper.intel.com/sites/files/9-qt-qml-art.png|http://appdeveloper.intel.com/sites/files/9-qt-qml-art.png]]
 
This is a simple application, but this is a good playground to understand the principles of <span class="caps">QML</span>.


To learn more about <span class="caps">QML</span> you can extend this application by adding features. Who knows, maybe someday this sample will grow to a commercial app? Idea from me: educational software with letters, numbers, shapes, colors, etc.
This is a simple application, but this is a good playground to understand the principles of QML.


<nowiki>***</nowiki>
To learn more about QML you can extend this application by adding features. Who knows, maybe someday this sample will grow to a commercial app? Idea from me: educational software with letters, numbers, shapes, colors, etc.


This article originally appeared on [http://appdeveloper.intel.com/en-us/blog/2010/12/24/modern-mobile-applications-qt-and-qml the Intel AppUp(SM) developer program blog] ''[appdeveloper.intel.com]''. A Russian version is available [http://habrahabr.ru/blogs/qt_software/110544/ here] ''[habrahabr.ru]''


Thanks to [http://intelloware.com Dmitry] ''[intelloware.com]'' for allowing us to copy his tutorial.
-----


===Categories:===
This article originally appeared on &quot;the Intel AppUp(SM) developer program blog&amp;quot;:http://appdeveloper.intel.com/en-us/blog/2010/12/24/modern-mobile-applications-qt-and-qml. A Russian version is available &quot;here&amp;quot;:http://habrahabr.ru/blogs/qt_software/110544/


* [[:Category:Developing with Qt|Developing_with_Qt]]
Thanks to &quot;Dmitry&amp;quot;:http://intelloware.com for allowing us to copy his tutorial.
** [[:Category:Developing with Qt::Qt Quick|Qt_Quick]]
* [[:Category:Learning|Learning]]

Revision as of 09:24, 24 February 2015

[toc align_right="yes&quot; depth="3&quot;]

English ["French&quot;:http://qt-devnet.developpez.com/tutoriels/qt-quick/qml/applications-mobiles-modernes/]

Modern Mobile Applications with Qt and QML

Qt is a flexible and powerful framework for creating cross-platform applications. QML is now part of Qt, providing a markup language which gives complete freedom in development of user interfaces.

A good way to see the power of Qt is to start coding with it. Let's write a simple application using Qt and QML. This will be an application I called 4Toddler; the application will start in full-screen mode and it has just two buttons placed in the top right corner of the window: About and Close. The main function is to display a random image with a fireworks effect and with a random sound effect.

The User interface will be written with QML; the backbone is written in Qt C+.
h2. Create new project
If you do not have Qt already installed, visit "Qt download page&quot;:http://qt.nokia.com/downloads/ to download Qt SDK for your platform and install it.
Launch Qt Creator, select File > New File or Project. In the new dialog select Qt C++ Project> Qt Gui Application, and then click Choose…
screenshot
In the new window: type project name, select path to the project folder and then click Next.
screenshot
In the next window: uncheck Generate form option. We do not need to generate a form. Click Next
screenshot
In the last window: just click Finish.
http://appdeveloper.intel.com/sites/files/4-qt-qml-art.png
The application skeleton is ready, now we can proceed to code the logic and design the UI.
h2. Code core logic in C+

First we need to add the "qt-declarative":http://doc.qt.nokia.com/4.7/qtdeclarative.html module to our project. This is the module that provides a widget in which a QML interface is displayed.

Open project file &#40;4Toddler.pro&#41; and append the line

QT ''= core gui<code>
<br />with ''declarative''
<br />

QT= core gui declarative

Now we need to change the base class for our main window. Replace QMainWindow with QDeclarativeView and include QDeclarativeView

<br />#include &lt;QDeclarativeView&amp;gt;<br />class MainWindow : public QDeclarativeView<br />{<br /> <br />}<br />

Also we need to cut off QMainWindow(parent) from the MainWindow constructor; we do not need this initialization anymore.

<br />MainWindow::MainWindow(QWidget *parent)<br />{<br /> Init();<br />}<br />

If you launch the application right now you will see an empty window. This is because we have not initialized or created our QML interface yet.

Add QML interface

Let's add a new file to our project: right click on the project in the projects explorer window.

http://appdeveloper.intel.com/sites/files/5-qt-qml-art.png

Add New then select Qt section and Qt QML File in the templates list and click Choose…

http://appdeveloper.intel.com/sites/files/6-qt-qml-art.png

Type the file name in the Name field, click Next then Finish in the next window.

http://appdeveloper.intel.com/sites/files/7-qt-qml-art.png

The wizard will create and open the new QML file in the editor. There is just one Rectangle element inside it. This will be the root element for our user interface. Let's add some new properties to this element.

Note: some versions of Qt Creator will add a Hello World text element centered in the Rectangle. Remove the text element before proceeding.

<br />Rectangle<br />{<br /> // ID of this element. Using this ID we can access the element and its properties from other elements<br /> id: canvas<br /> // Background color, black in this case<br /> color: &quot;black&amp;quot;<br /> // Change sizes of this element to fill the parent<br /> anchors.fill: parent<br /> // Element can receive focus<br /> focus: true<br />}<br />

There is nothing special for now, just black background.

Multilingual

During the remainder of this tutorial we will shift back and forth between QML and C++ development.

We need to add some initialization code for our QML interface by defining a new method inside the mainwindow.h file …

void Init();<code>

.. And implementing it in the '''mainwindow.cpp''' file


void MainWindow::Init()
{
// Path to the content folder
QString contentPath;

  1. ifdef QT_DEBUG
    // In the debug version of our project this is a path to the project folder
    contentPath = "D:/MyProjects/QT/4Toddler&quot;;
    #else
    // In the release version - path to the application folder
    contentPath = QApplication::applicationDirPath();
    #endif
    setFocusPolicy(Qt::StrongFocus);
    // Change QML document sizes to fit the main window
    setResizeMode(QDeclarativeView::SizeRootObjectToView);
    // Load QML file
    setSource(QUrl::fromLocalFile&amp;#40;contentPath + "/main.qml&quot;&#41;);
    }
    Now we need to replace one line in the '''main.cpp''' file
    

    int main(int argc, char *argv[])
    {

    w.show();

    }
    With
    

    int main(int argc, char *argv[])

{

w.showFullScreen();

}

This will force our window to open in full-screen mode.

== Structure code with components ==

Before we launch our application, let's add two buttons. One is to display '''About''' dialog and the second to '''Close''' our window. We do not need to implement buttons twice, we going to create a &quot;component&amp;quot;:http://doc.qt.nokia.com/4.7-snapshot/qml-extending-types.html and use it every time we need to add a new button by overriding just a few properties.

Let's add the new Qml file - '''WindowButton.qml''' to our project. ''Note the filename begins with a capital letter  this signifies it defines a QML component.''


Image
{
// ID of this element
id: button
// The MouseArea item enables simple mouse handling
MouseArea
{
anchors.fill: parent
id: mouseArea
// On click call callback() handler
onClicked: callback()
}
}

Now we can add two buttons to our window


// Place items in row Row
{
// Right side of the item is anchored to the right side of the parent element
anchors.right: parent.right
// Right margin
anchors.rightMargin: 4
// Top side of the item is anchored to the top side of the parent element
anchors.top: parent.top
// Top margin
anchors.topMargin: 4
// Margins for children elements
spacing: 4
WindowButton
{
// Button to display the About dialog
id: about
// Path to background picture. This is a relative path to the path of this QML file
source: "about.png&quot;
// Callback method, which will be called on mouse click
// onClicked: callback()
function callback()
{
}
}
WindowButton
{
// Button to close window
id: exit
source: "exit.png&quot;
function callback()
{
}
}
}

== Communicate between QML and C++ ==

Now we should implement both '''callback()''' methods. To close the window we will call the '''Quit''' function of the main window. Now we will see how Qt and QML communicate. Methods will be implemented inside Qt and then called from the QML file.

Let's add a new function to the '''mainwindow.h''' header file

Q_INVOKABLE void Quit();

And implementation in mainwindow.cpp file

<br />void MainWindow::Quit()

{

QApplication::quit();

}<br />

Now we need to "tell&quot; QML about this method. Inside Init we should to add just one line:

rootContext()<s>&gt;setContextProperty(&quot;window&amp;quot;, this);<code>
<br />Now we can access '''window''' object's functions declared as '''Q_INVOKABLE''' from QML. '''Window''' here is just an example, you could use any object name you want.
<br />Let's add '''callback()''' function implementation to close button
<br />


function callback()
{
window.Quit();
}

<br />h2. Visualize state and add animation
<br />Ok, the application can be launched. Launch it and click the '''Close''' button. You see? State of the button is not changed after click; it looks like the button is just inactive. Let's add state changes for normal and clicked states.
<br />


Image
{

states:[
State
{
// Name of the state
name: "hovered&quot;
// When condition. Item will go to this state if condition is true
// In this case on mouse click
when: mouseArea.pressed
// Which properties will be changed in that state
// In this case opacity
PropertyChanges { target: button; opacity: 1}
}, State
{
name: "normal&quot;
// This state will be activated if mouse button is not pressed
when: mouseArea.pressed == false
PropertyChanges { target: button; opacity: 0.7; }
}
]
}

Item will change state if the condition described in ''when'' property is true. You could change state manually by assigning state property.<br />Let's launch the application again. Ok, this time it looks more active. We can make our button nicer by adding some animation.


Image
{

Behavior on opacity
{
// Animaion step is a 100 milliseconds
// On every iteration opacity will increase or descrease with step equals to 0,1
NumberAnimation { duration: 100 }
}
}

The ''Behavior'' is a simple and flexible way to create animations. This element allows you to specify a default animation for a property change.

Launch the application and try to click on '''About''' or '''Close''' buttons. This looks much better!

[[Image:http://appdeveloper.intel.com/sites/files/8-qt-qml-art.png|http://appdeveloper.intel.com/sites/files/8-qt-qml-art.png]]

We will implement the '''About''' dialog only using QML. Dialog will appear on the screen when '''About''' button is clicked and disappear when the user clicks inside the button or on the background.

Let's add '''About.qml''' file to our project.


// Parent element for dialog window
Rectangle
{
id: about
// Function to display dialog window
// This function just changes opacity of the main element to 1
function show()
{
about.opacity = 1
}
// Function to hide dialog window
// This function just changes opacity of the main element to 0
function hide()
{
about.opacity = 0
}
// Transparent background
color: "transparent&quot;
// Opacity is 0 by default, dialog not visible
opacity: 0
// Anchors to parent width and height.
width: parent.width
height: parent.height
// Element is visible if opacity > 0
// opacity > 0
visible: opacity > 0
// Child element to create semitransparent background
Rectangle
{
anchors.fill: parent
opacity: 0.5
color: "gray&quot;
}
// Body of the dialog window
Rectangle
{
id: dialog

// Fixed width and height
width: 360
height: 230
// To make dialog centered inside parent we need to calculate its x and y coordinates
x: parent.width / 2 - dialog.width / 2
y: parent.height / 2 - dialog.height / 2
// Place dialog on top of other elements
z: 10
border.color: "gray&quot;
Text
{
text: "4 Toddler&quot;
font.bold: true
font.pixelSize: 22

anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
}
}
Behavior on opacity
{
NumberAnimation { duration: 100 }
}
MouseArea
{
anchors.fill: parent
// Hide dialog on mouse click
onClicked: hide()
}
}

Take a look at the line

visible: opacity > 0

As you can see, property can be assigned and can be calculated.

Let's add About dialog and callback() function implementation for the button About. In Main.qml file we need to declare the new About element.

<br />Rectangle<br />{<br /> id: canvas<br /> ..<br /> About<br /> {<br /> id: aboutDlg<br /> }<br />}<br />

And callback() function implementation

aboutDlg.show();<code>

to


WindowButton
{
id: about

function callback()
{
aboutDlg.show()
}
}

Finally we need to implement the main functionality for our application.

The element to display a random icon on the screen will be an '''Image''' element. Let's add a new file for the new element - ''Block.qml''


Image
{
id: block;
// New custom properties to change visibility of this element
property bool remove: false
property bool show: false
opacity: 0
fillMode: Image.Stretch
states: [
State
{
// State is used to remove element from the screen and destroy it
name: "remove&quot;; when: remove true

     PropertyChanges &#123; target: block; opacity: 0 &#125;
     StateChangeScript &#123; script: block.destroy(1000) &#125;
   &#125;,
   State
   &#123;
     // State is used to display element

name: &quot;show&quot;; when: show true
PropertyChanges { target: block; opacity: 1 }
}
]
Behavior on opacity { NumberAnimation { duration: 300 } }
}

Now we need to implement the keyboard handler. Handler will be implemented with '''JavaScript'''. Let's add new ''main.js'' to our project.

// Template for new elements
var component = Qt.createComponent("block.qml&quot;)
// Max number of items on the screen
var maxBlocksCount = 10
// Array for the items
var blocksArray = new Array()
// Keyboard handler
function handleKey()
{
// x coordinate is a random number from 0 to window with in pixels
var x = Math.floor(Math.random() * canvas.width)
// y coordinate is a random number from 0 to window height in pixels
var y = Math.floor(Math.random() * canvas.height)
// This function will create a new element on each call with random x and y coordinates
createNewBlock(x, y)
}
// Function to create a new element
function createNewBlock(x, y)
{
if(component.status != Component.Ready)
{
return false
}
// Remove items if number of items is more than maxBlocksCount
if(blocksArray.length > maxBlocksCount)
{
removeAllBlocks()
}
var newBlock = component.createObject(canvas)
if(newBlock == null)
{
return false
}
// Path to image is available via randomIcon property of the main window
var iconFile = window.randomIcon
newBlock.source = ("Icons/&quot; + iconFile)
newBlock.x = x
newBlock.y = y
// Change state to show
newBlock.show = true
blocksArray.push(newBlock)
// Play random sound effect
window.PlaySound()
return true
}
// Function do remove all existings items
function removeAllBlocks()
{
for(var i = 0; i < blocksArray.length; +i)
{
blocksArray[i].remove = true
}
while(blocksArray.length != 0)
{
blocksArray.pop()
}
}

<br />As you see in code above we should implement new property '''randomIcon''' and method '''PlaySound'''.
<br />Let's add property declaration and method to access it to our ''mainwindow.h'' file.
<br />

Q_PROPERTY(QString randomIcon READ RandomIcon)

QString RandomIcon();<code>
<br />Implementation in ''mainwindow.cpp'' file
<br />


QString MainWindow::RandomIcon()
{
QStringList iconFilesList;
QString searchPath = m_ContentPath "/Icons/&quot;;
QDir directory = QDir(searchPath);
QStringList filters;
filters << "'
.png&quot;;
directory.setNameFilters(filters);
// Get the list of the png files inside Icons directory
iconFilesList = directory.entryList(QDir::AllEntries);
// Generate random index of the element
int fileIdx = qrand() % iconFilesList.count();
// Return file name
return iconFilesList.at(fileIdx);
}

<br />Now we need to declare the method to play a random sound effect in ''mainwindow.h'' file
<br />

Q_INVOKABLE void PlaySound();


And implementation in mainwindow.cpp file


<br />void MainWindow::PlaySound()<br />{<br /> QStringList soundFilesList;<br /> QDir directory = QDir(m_ContentPath + &quot;/Sounds/&amp;quot;);<br /> QStringList filters;<br /> filters &lt;&lt; &quot;'''.wav&amp;quot;;<br /> directory.setNameFilters(filters);<br /> // Wav files list inside Sounds directory<br /> soundFilesList = directory.entryList(QDir::AllEntries);<br /> // Generate random index of the element<br /> int fileIdx = qrand() % soundFilesList.count();<br /> // File name<br /> QString soundFile = m_ContentPath + &quot;/Sounds/&amp;quot; + soundFilesList.at(fileIdx);<br /> // Play file asynchronously<br /> QSound::play(soundFile);<br />}<br />

Almost done. All we need is to add the keyboard handler to our parent QML element. But first we should include main.js file to main.qml file

<br />import Qt 4.7<br />import &quot;main.js&amp;quot; as Main<br />

Keyboard event handler for root element

<br />Rectangle<br />{<br /> id: canvas<br /> <br /> Keys.onPressed: {<br /> if(event.isAutoRepeat == false) {<br /> Main.handleKey()<br /> }<br /> }<br />}<br />

That's all! Now you can launch the application and try to press any key on the keyboard. But… I almost forgot about the fireworks effect.

Let's add a new file called Fireworks.qml. Why do we need a new file? Because this will be a reusable element, this will save time in the future.

<br />import Qt.labs.particles 1.0<br />Particles<br />{<br /> id: particles<br /> width: 1<br /> height: 1<br /> anchors.centerIn: parent<br /> emissionRate: 0<br /> lifeSpan: 700<br /> lifeSpanDeviation: 600<br /> angle: 0<br /> angleDeviation: 360<br /> velocity: 100<br /> velocityDeviation: 30<br /> source: randomImage()<br /> // Get random image path<br /> function randomImage()<br /> {<br /> // Array of the image files<br /> var images = [&quot;red.png&amp;quot;, &quot;blue.png&amp;quot;, &quot;green.png&amp;quot;, &quot;white.png&amp;quot;, &quot;yellow.png&amp;quot;]<br /> // Get random index of the array element<br /> var idx = Math.floor((Math.random() * 100)) % images.length<br /> // Return the relative image file path<br /> return (&quot;Stars/&amp;quot; + images[idx])<br /> }<br />}<br />

Now we need to add our Firework element to the Block element. Open Block.qml file and add declaration of the new element

<br />Image<br />{<br /> id: block<br /> <br /> Firework<br /> {<br /> id: firework<br /> }<br /> <br />}<br />

To launch fireworks on item going to visible state we need to add just one line of code

StateChangeScript { script: firework.burst(50); }<code>

to &quot;show&amp;quot; state


State
{
name: "show&quot;; when: show == true
StateChangeScript { script: firework.burst(50)}
PropertyChanges { target: block; opacity: 1 }
}

Launch application and press any key. Image appears on the screen with fireworks and sound effect.

http://appdeveloper.intel.com/sites/files/9-qt-qml-art.png

This is a simple application, but this is a good playground to understand the principles of QML.

To learn more about QML you can extend this application by adding features. Who knows, maybe someday this sample will grow to a commercial app? Idea from me: educational software with letters, numbers, shapes, colors, etc.



This article originally appeared on "the Intel AppUp(SM) developer program blog&quot;:http://appdeveloper.intel.com/en-us/blog/2010/12/24/modern-mobile-applications-qt-and-qml. A Russian version is available "here&quot;:http://habrahabr.ru/blogs/qt_software/110544/

Thanks to "Dmitry&quot;:http://intelloware.com for allowing us to copy his tutorial.