Applications mobiles modernes avec Qt et QML

Qt est un framework flexible et puissant pour la création d'applications multi-plateformes. QML est désormais un élément de Qt, fournissant un langage qui donne une liberté complète dans le développement d'interfaces utilisateur.

Un bon moyen de voir le pouvoir de Qt est de commencer à coder avec lui. Écrivons une simple application utilisant Qt et QML. Ce sera une application que j'ai appelée 4Toddler ; l'application va commencer en mode plein écran et possède juste deux boutons placés dans le coin en haut à droite de la fenêtre : À propos et Fermer. La fonction principale est d'afficher une image aléatoire avec des effets de feu d'artifice et avec un effet sonore aléatoire.

L'interface utilisateur sera écrite avec QML, la colonne vertébrale avec Qt C++.

Commentez Donner une note à l'article (5)

Article lu   fois.

Les deux auteurs

Site personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

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....

Image non disponible

Dans la nouvelle fenêtre, entrez le nom du projet, sélectionnez le chemin du dossier du projet et cliquez sur Suivant.

Image non disponible

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.

Image non disponible

Dans la dernière fenêtre, cliquez juste sur Terminer.

Image non disponible

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 :

 
Sélectionnez
QT += core gui

par son équivalent avec declarative :

 
Sélectionnez
QT += core gui declarative

Nous devons maintenant changer la classe de base pour notre fenêtre principale. Remplacez QMainWindow par QDeclarativeView et incluez QDeclarativeView.

 
Sélectionnez
#include <QDeclarativeView>
class MainWindow : public QDeclarativeView
{
 ...
}

Nous devons également couper QMainWindow(parent) du constructeur de MainWindow ; n'avons donc plus besoin de cette initialisation.

 
Sélectionnez
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.

Image non disponible

Cliquez sur Ajouter nouveau puis sélectionnez la section Qt et Fichier QML dans la liste des templates. Cliquez alors sur Choisir.

Image non disponible

Entrez le nom du fichier dans le champ Nom, cliquez sur Suivant puis sur Terminer dans la fenêtre suivante.

Image non disponible

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.

 
Sélectionnez
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

 
Sélectionnez
void Init();

et de l'implémenter dans le fichier mainwindow.cpp.

 
Sélectionnez
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 :

 
Sélectionnez
int main(int argc, char *argv[])
{
 ...
 w.show();
 ...
}

Par :

 
Sélectionnez
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.

 
Sélectionnez
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 :

 
Sélectionnez
// 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.

 
Sélectionnez
Q_INVOKABLE void Quit();

Et l'implémentation dans le fichier mainwindow.cpp :

 
Sélectionnez
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 :

 
Sélectionnez
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.

 
Sélectionnez
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é.

 
Sélectionnez
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.

 
Sélectionnez
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 !

Image non disponible

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.

 
Sélectionnez
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 :

 
Sélectionnez
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.

 
Sélectionnez
Rectangle
{
 id: canvas
 ...
 About
 {
  id: aboutDlg
 }
}

Et l'implémentation de la fonction callback() :

 
Sélectionnez
aboutDlg.show();

À :

 
Sélectionnez
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.

 
Sélectionnez
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.

 
Sélectionnez
// 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.

 
Sélectionnez
Q_PROPERTY(QString randomIcon READ RandomIcon)
 
Sélectionnez
QString RandomIcon();

Implémentation dans le fichier mainwindow.cpp :

 
Sélectionnez
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 :

 
Sélectionnez
Q_INVOKABLE void PlaySound();

Et l'implémenter dans le fichier mainwindow.cpp.

 
Sélectionnez
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.

 
Sélectionnez
import Qt 4.7
 
import "main.js" as Main

Les gestionnaires d'évènements claviers pour les éléments racine :

 
Sélectionnez
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.

 
Sélectionnez
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 :

 
Sélectionnez
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 :

 
Sélectionnez
StateChangeScript { script: firework.burst(50); }

Pour montrer l'état « show« .

 
Sélectionnez
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.

Image non disponible

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 !

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Copyright © 2011 Developpez.com Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.