I. L'article original▲
Le Qt Developer Network est un réseau de développeurs utilisant Qt afin de partager leur savoir sur ce framework. Vous pouvez le consulter en anglais.
Nokia, Qt, Qt Quarterly et leurs logos sont des marques déposées de Nokia Corporation en Finlande et/ou dans les autres pays. Les autres marques déposées sont détenues par leurs propriétaires respectifs.
Cet article est la traduction de Modern Mobile Applications with Qt and QML.
II. Création d'un nouveau projet▲
Si vous n'avez pas déjà installé Qt, consultez la page de téléchargement de Qtpage de téléchargement de Qt, dans la section « Qt SDK: Complete Development Environment« pour télécharger et installer les outils et les exemples pour votre plateforme.
Lancez Qt Creator, faites Fichier Nouveau fichier ou projet. Dans la nouvelle boîte de dialogue, sélectionnez Projet Qt C++ > Application graphique Qt, puis cliquez sur Choisir....
Dans la nouvelle fenêtre, entrez le nom du projet, sélectionnez le chemin du dossier du projet et cliquez sur Suivant.
Dans la fenêtre suivante, décochez l'option Générer l'interface graphique. Nous n'avons pas besoin d'en générer une. Cliquez sur Suivant.
Dans la dernière fenêtre, cliquez juste sur Terminer.
Le squelette de l'application est prêt, nous devons maintenant passer au code pour faire la partie logique et le design de l'interface utilisateur.
III. Le cœur de la logique du code en C++▲
Nous devons tout d'abord ajouter le module qt-declarativeqt-declarative à notre projet. C'est le module qui fournit un widget dans lequel l'interface QML est affichée.
Ouvrez le fichier de projet (4Toddler.pro) et remplacez la ligne :
QT
+=
core gui
par son équivalent avec declarative :
QT
+=
core gui declarative
Nous devons maintenant changer la classe de base pour notre fenêtre principale. Remplacez QMainWindow par QDeclarativeView et incluez QDeclarativeView.
#include
<QDeclarativeView>
class
MainWindow : public
QDeclarativeView
{
...
}
Nous devons également couper QMainWindow(parent) du constructeur de MainWindow ; n'avons donc plus besoin de cette initialisation.
MainWindow::
MainWindow(QWidget
*
parent)
{
Init();
}
Si vous lancez l'application dès maintenant, vous devriez voir une fenêtre vide. C'est parce que nous n'avons pas encore initialisé ou créé notre interface QML.
IV. Ajout de l'interface QML▲
Ajoutons un nouveau fichier à notre projet : faites un clic droit sur le projet dans l'explorateur de projet.
Cliquez sur Ajouter nouveau puis sélectionnez la section Qt et Fichier QML dans la liste des templates. Cliquez alors sur Choisir.
Entrez le nom du fichier dans le champ Nom, cliquez sur Suivant puis sur Terminer dans la fenêtre suivante.
Cet assistant va créer et ouvrir le nouveau fichier QML dans l'éditeur. Dedans se situe uniquement un élément Rectangle. Ce sera l'élément racine de notre interface utilisateur. Ajoutons quelques propriétés à cet élément.
Note : certaines versions de Qt Creator vont ajouter un élément textuel Hello World centré dans le Rectangle. Retirez cet élément textuel avant de continuer.
Rectangle
{
id
:
canvas;
color
:
"black"
anchors.fill
:
parent
focus
:
true
}
Il n'y a rien de spécial pour le moment, juste un arrière-plan noir.
V. Multilinguisme▲
Durant le reste de ce tutoriel, nous allons passer et repasser du développement QML au développement C++.
Nous devons ajouter du code d'initialisation pour notre interface QML en définissant une nouvelle méthode dans le fichier mainwindow.h
void
Init();
et de l'implémenter dans le fichier mainwindow.cpp.
void
MainWindow::
Init()
{
QString
contentPath;
#ifdef QT_DEBUG
contentPath =
"D:/MyProjects/QT/4Toddler"
;
#else
contentPath =
QApplication
::
applicationDirPath();
#endif
setFocusPolicy(Qt
::
StrongFocus);
setResizeMode(QDeclarativeView
::
SizeRootObjectToView);
setSource(QUrl
::
fromLocalFile(contentPath +
"/main.qml"
));
}
Maintenant, nous devons remplacer une ligne dans le fichier main.cpp :
int
main(int
argc, char
*
argv[])
{
...
w.show();
...
}
Par :
int
main(int
argc, char
*
argv[])
{
...
w.showFullScreen();
...
}
Cela va forcer notre fenêtre à s'ouvrir en mode plein écran.
VI. Structure de code avec composants▲
Avant de lancer notre application, ajoutons-y deux boutons. L'un afin d'afficher la boîte de dialogue À propos et le second pour Fermer notre fenêtre. Nous n'avons pas besoin d'implémenter à deux reprises des boutons, nous allons créer un composant et l'utiliser à chaque fois que nous le voudrons en changeant uniquement quelques propriétés.
Ajoutons le fichier QML WindowButton.qml à notre projet. Notez que le nom de fichier commence par une lettre majuscule, ce qui signifie qu'il définit un composant QML.
Image
{
id
:
button
MouseArea
{
anchors.fill
:
parent
id
:
mouseArea
onClicked
:
callback()
}
}
Nous pouvons désormais ajouter deux boutons à l'intérieur de notre fenêtre :
// Place items in row
Row
{
anchors.right
:
parent.right;
anchors.rightMargin
:
4
;
anchors.top
:
parent.top;
anchors.topMargin
:
4
;
spacing
:
4
WindowButton
{
id
:
about;
source
:
"about.png"
;
function
callback()
{
}
}
WindowButton
{
id
:
exit;
source
:
"exit.png"
;
function
callback()
{
}
}
}
VII. Communication entre QML et C++▲
Maintenant, nous devrions également implémenter les méthodes callback(). Pour fermer la fenêtre, nous allons appeler la fonction Quitter de la fenêtre principale. Dès lors, nous allons voir comment Qt et QML communiquent. Les méthodes vont être implémentées à l'intérieur du fichier Qt et être appelées depuis le fichier QML.
Ajoutons une nouvelle fonction au fichier d'en-tête mainwindow.h.
Q_INVOKABLE
void
Quit();
Et l'implémentation dans le fichier mainwindow.cpp :
void
MainWindow::
Quit()
{
QApplication
::
quit();
}
Maintenant, nous devons « prévenir » QML de l'existence de cette méthode. À l'intérieur de Init, nous devons uniquement ajouter une ligne :
rootContext()->
setContextProperty("window"
, this
);
Maintenant, nous pouvons accéder aux fonctions de l'objet window déclarées Q_INVOKABLE depuis notre UI QML. Window est juste là en tant qu'exemple, vous pouvez utiliser n'importe quel nom d'objet.
Ajoutons une implémentation de fonction callback() à notre bouton de fermeture.
function callback()
{
window.Quit();
}
VIII. Visualisation de l'état et ajout d'animations▲
OK, l'application peut être lancée. Lancez-la et cliquez sur le bouton de fermeture. Vous voyez ? L'état du bouton n'est pas changé après un clic ; il semble que le bouton soit juste inactif. Ajoutons des changements d'états pour l'état normal et l'état enfoncé.
Image
{
...
states
:
[
State
{
name
:
"hovered"
;
when
:
mouseArea.pressed;
PropertyChanges
{
target
:
button
; opacity
:
1
;}
}
,
State
{
name
:
"normal"
when
:
mouseArea.pressed ==
false
;
PropertyChanges
{
target
:
button
; opacity
:
0.7; }
}
]
}
L'élément va changer d'état si la condition décrie dans la propriété when est vraie. Vous pourriez aussi changer l'état manuellement en assignant un état à la propriété.
Lançons à nouveau l'application. OK, cette fois, cela semble bien plus actif. Nous pourrions donner un meilleur aspect à notre bouton en ajoutant une 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
}
}
}
Le Behavior est un moyen simple est flexible de créer des animations. Cet élément permet de spécifier une animation par défaut pour un changement de propriété.
Lancez l'application est tentez de cliquer sur les boutons À propos ou Fermer. C'est déjà bien mieux !
Nous allons implémenter la boîte de dialogue À propos uniquement en utilisant QML. La boîte de dialogue va apparaître à l'écran au moment où l'on cliquera sur le bouton À propos et disparaître lorsque l'utilisateur va cliquer à l'intérieur du bouton ou sur l'arrière-plan.
Ajoutons le fichier About.qml à notre projet.
Rectangle
{
id
:
about
function
show()
{
about.opacity =
1
;
}
function
hide()
{
about.opacity =
0
;
}
color
:
"transparent"
opacity
:
0
width
:
parent.width
height
:
parent.height
visible
:
opacity
>
0
Rectangle
{
anchors.fill
:
parent
opacity
:
0.5
color
:
"gray"
}
Rectangle
{
id
:
dialog
width
:
360
height
:
230
x
:
parent.width /
2
-
dialog.width /
2
;
y
:
parent.height /
2
-
dialog.height /
2
;
z
:
10
border.color
:
"gray"
Text
{
text
:
"4 Toddler"
font.bold
:
true
font.pixelSize
:
22
anchors.horizontalCenter
:
parent.horizontalCenter
anchors.verticalCenter
:
parent.verticalCenter
}
}
Behavior
on
opacity
{
NumberAnimation
{
duration
:
100
}
}
MouseArea
{
anchors.fill
:
parent
;
onClicked
:
hide();
}
}
Regardez la ligne :
visible
:
opacity
>
0
Comme vous pouvez le voir, les propriétés peuvent être assignées et être calculées.
Ajoutons la boîte de dialogue À propos et les implémentations de fonction callback() au bouton À propos. Dans le fichier Main.qml, nous devons déclarer le nouvel élément About.
Rectangle
{
id
:
canvas
...
About
{
id
:
aboutDlg
}
}
Et l'implémentation de la fonction callback() :
aboutDlg.show();
À :
WindowButton
{
id
:
about;
...
function
callback()
{
aboutDlg.show();
}
}
Enfin, nous devons implémenter la fonctionnalité principale de notre application.
L'élément à afficher avec une image aléatoire sera un élément Image. Ajoutons un nouveau fichier pour cet élément, Block.qml.
Image
{
id
:
block;
property
bool
remove
:
false
property
bool
show
:
false
opacity
:
0
;
fillMode
:
Image.Stretch;
states
:
[
State
{
name
:
"remove"
; when
:
remove
==
true
;
PropertyChanges
{
target
:
block; opacity
:
0
}
StateChangeScript
{
script
:
block.destroy(1000
); }
}
,
State
{
name
:
"show"
; when
:
show ==
true
;
PropertyChanges
{
target
:
block; opacity
:
1
}
}
]
Behavior
on
opacity
{
NumberAnimation
{
duration
:
300
}
}
}
Maintenant, nous devons implémenter la gestion du clavier. La gestion sera implémentée avec JavaScript. Ajoutons dès lors un fichier main.js à notre projet.
// Template for new elements
var component =
Qt.createComponent
(
"block.qml"
);
var maxBlocksCount =
10
;
var blocksArray =
new Array(
);
function handleKey
(
)
{
var x =
Math.floor
(
Math.random
(
) *
canvas.
width);
var y =
Math.floor
(
Math.random
(
) *
canvas.
height);
createNewBlock
(
x,
y);
}
function createNewBlock
(
x,
y)
{
if(
component.
status
!=
Component.
Ready)
{
return false;
}
if(
blocksArray.
length >
maxBlocksCount)
{
removeAllBlocks
(
);
}
var newBlock =
component.createObject
(
canvas);
if(
newBlock ==
null)
{
return false;
}
var iconFile =
window
.
randomIcon;
newBlock.
source = (
"Icons/"
+
iconFile);
newBlock.
x =
x;
newBlock.
y =
y;
newBlock.
show =
true;
blocksArray.push
(
newBlock);
window
.PlaySound
(
);
return true;
}
function removeAllBlocks
(
)
{
for(
var i =
0
;
i <
blocksArray.
length;
++
i)
{
blocksArray[
i].
remove =
true;
}
while(
blocksArray.
length !=
0
)
{
blocksArray.pop
(
);
}
}
Comme vous le voyez dans le code ci-dessus, nous devons implémenter une nouvelle propriété randomIcon et une méthode PlaySound.
Il est temps d'ajouter la déclaration de propriété et la méthode d'accès à celle-ci à notre fichier mainwindow.h.
Q_PROPERTY
(QString
randomIcon READ
RandomIcon)
QString
RandomIcon();
Implémentation dans le fichier mainwindow.cpp :
QString
MainWindow::
RandomIcon()
{
QStringList
iconFilesList;
QString
searchPath =
m_ContentPath +
"/Icons/"
;
QDir
directory =
QDir
(searchPath);
QStringList
filters;
filters <<
"*.png"
;
directory.setNameFilters(filters);
iconFilesList =
directory.entryList(QDir
::
AllEntries);
int
fileIdx =
qrand
() %
iconFilesList.count();
return
iconFilesList.at(fileIdx);
}
Maintenant, nous devons déclarer une méthode pour jouer un son aléatoire dans le fichier mainwindow.h :
Q_INVOKABLE
void
PlaySound();
Et l'implémenter dans le fichier mainwindow.cpp.
void
MainWindow::
PlaySound()
{
QStringList
soundFilesList;
QDir
directory =
QDir
(m_ContentPath +
"/Sounds/"
);
QStringList
filters;
filters <<
"*.wav"
;
directory.setNameFilters(filters);
soundFilesList =
directory.entryList(QDir
::
AllEntries);
int
fileIdx =
qrand
() %
soundFilesList.count();
QString
soundFile =
m_ContentPath +
"/Sounds/"
+
soundFilesList.at(fileIdx);
QSound
::
play(soundFile);
}
La plupart des choses est faite. Tout ce dont nous avons besoin est d'ajouter la gestion du clavier à notre élément QML parent. Mais tout d'abord, nous devons inclure le fichier main.js au fichier main.qml.
import
Qt
4.7
import
"main.js"
as
Main
Les gestionnaires d'évènements claviers pour les éléments racine :
Rectangle
{
id
:
canvas
...
Keys.onPressed
: {
if(
event
.
isAutoRepeat ==
false) {
Main.handleKey
(
);
}
}
C'est tout ! Maintenant, nous pouvons lancer l'application et tenter de presser l'un des boutons du clavier. Mais on a oublié les effets de feu d'artifice.
Ajoutons une fois de plus un fichier, cette fois-ci appelé Fireworks.qml. Pourquoi avons-nous besoin d'un nouveau fichier ? Parce que ce sera un fichier réutilisable, permettant de gagner du temps à l'avenir.
import
Qt.labs.particles 1.0
Particles
{
id
:
particles
width
:
1
;
height
:
1
;
anchors.centerIn: parent
emissionRate
:
0
lifeSpan
:
700
;
lifeSpanDeviation
:
600
angle
:
0
;
angleDeviation
:
360
;
velocity
:
100
;
velocityDeviation
:
30
;
source
:
randomImage();
function randomImage()
{
var images =
["red.png"
, "blue.png"
, "green.png"
, "white.png"
, "yellow.png"
];
var idx =
Math.floor((Math.random() *
100
)) %
images.length;
return
("Stars/"
+
images[idx]);
}
}
Maintenant, nous devons ajouter notre élément Firework à l'élément Block. Ouvrez le fichier Block.qml et ajoutez la déclaration du nouvel élément :
Image
{
id
:
block;
...
Firework
{
id
:
firework
}
...
}
Pour lancer les feux d'artifice sur l'élément passant à l'état visible, nous devons juste ajouter une ligne de code :
StateChangeScript
{
script
:
firework.burst(50
); }
Pour montrer l'état « show« .
State
{
name
:
"show"
; when
:
show ==
true
;
StateChangeScript
{
script
:
firework.burst(50
); }
PropertyChanges
{
target
:
block; opacity
:
1
}
}
Lancez l'application et appuyez sur n'importe quelle touche. L'image apparaît à l'écran avec des feux d'artifice et un effet sonore.
C'est une simple application, mais c'est un bon moyen de comprendre les principes de QML.
Pour en apprendre plus à propos de QML, vous pouvez étendre cette application en y ajoutant des propriétés. Qui sait, peut-être qu'un jour, de cette petite application sortira une application commerciale ? Petite idée personnelle : les logiciels éducatifs avec des lettres, nombres, formes, couleurs, etc.
IX. Divers▲
Cet article apparaît originellement sur Intel AppUp(SM) developer program blogIntel AppUp(SM) developer program blog. Une version russe est disponible iciici.
Merci à DmitryDmitry de nous avoir autorisé à copier son tutoriel.
X. Remerciements▲
Merci à Thibaut Cuvelier pour sa relecture !