Traduction par Jean-luc Biord, du Site de la communauté Qt francophone.
English TOC.

6. Une Application Qt faite main

Ce chapitre est un petit exemple présentant comment écrire les signaux et les slots. Le but est de créer une application Qt en utilisant seulement la ligne de commande et un éditeur de texte. L'application résultante est montrée en fonctionnement sur le schéma 6-1.

The resulting application

Schéma 6-1 l'application résultante.

Dans le dernier chapitre des dispositions (layouts) ont été employées pour définir et contrôler la disposition des widgets. Cette approche peut être codée à la main également, mais pour varier un peu les widgets QVBox et QHBox seront employés cette fois. Un QVBox est une boîte disposant ses widgets enfants sur une ligne verticale, alors que le QHBox fonctionne avec une disposition horizontale. Pour mettre en application la disposition exigée les boîtes verticales et horizontales devront être nichées. Référez-vous au schéma 6-2 pour le plan. Notez que les boîtes horizontales et verticales sont identifiées par la direction de la flèche sur le bord de chaque boîte.

The planned layout using QVBox and QHBox

Schéma 6-2 la disposition prévue en utilisant QVBox et QHBox.

L'application entière sera implémentée comme simple widget. C'est convenable parce que c'est seulement un exemple assez petit. Si des dispositions avaient été employées un dialogue aurait été plus approprié. Les différentes approches qui peuvent être employées sont exposées dans le prochain chapitre, continuez avec moi jusque-là.

Puisse-que la boîte extérieure (sur le schéma 6-2) est un QVBox le widget créé est dérivé d'un QVBox. La classe est appelée HandMade et le fichier d'en-tête est enregistré dans handmade.h. Le code est montré dans l'exemple 6-1.

Notez l'entourage par #ifndef, #define, #endif. C'est utilisé pour protéger le fichier d'en-tête contre des déclarations multiples. Il s'assure que la déclaration de classe est vue une seule fois par le compilateur.

La première chose que nous faisons à l'intérieur du secteur protégé est d'inclure la définition de la classe dont nous allons dériver la notre (QVBox). Toutes autres classes utilisées (QHBox et QLCDNumber) sont référencées comme pointeurs, ainsi la seule chose que le compilateur doit savoir c'est que ce sont des classes (puisque les pointeurs ont la même taille en mémoire indépendamment de ce qu'ils pointent). Ainsi, au lieu d'inclure les déclarations de classe une déclaration anticipée est utilisée. Cela réduit le nombre de fichiers d'en-tête qui doivent être traversés et réduit ainsi le temps de compilation. Dès que nous aurons l'intention d'employer des membres des classes (ou les déclarer statiquement) les définitions de classe sont nécessaires, ainsi les en-têtes devront être incluses dans le fichier d'implémentation de notre classe faite main.

Après ces déclarations la déclaration réelle de classe suit. La première chose qu'une classe Qt (c.-à-d. une classe dérivée de QObject) doit inclure est la macro Q_OBJECT. Assurant que les signaux, les slots et d'autres dispositifs spécifiques de Qt fonctionnent correctement.

La classe elle-même contient un constructeur et deux slots. Les paramètres du constructeur sont les paramètres standard de Qt - un parent et un nom. Le parent est employé par le gestionnaire de mémoire de Qt (et autre) et le nom est utilisé en débugant. Ces paramètres seront passés à la classe de base dans l'implémentation. Les deux pointeurs que nous déclarons (lcd et lb) sont employés dans l'implémentation des slots. Ceux d'entre vous qui se rappellent le dernier chapitre et le slot init() au lieu d'un constructeur pourraient se demander quelle approche est employée. Le constructeur généré par Designer (ou réellement, un outil appelé uic) crée les widgets du dialogue et puis appelle init() s'il existe. Cela nous évite de devoir surclasser le dialogue que nous obtenons de Designer pour ajouter notre propre constructeur.

#ifndef HANDMADE_H
#define HANDMADE_H

#include <qvbox.h>

class QLCDNumber;
class QListBox;

class HandMade : public QVBox
{
  Q_OBJECT

public:
  HandMade( QWidget *parent=0, char *name=0 );

protected slots:
  void addNumber();
  void removeNumber();

protected:
  QLCDNumber *lcd;
  QListBox *lb;
};

#endif

Exemple 6-1

La prochaine étape dans la création de notre classe faite main est de l'implémenter. Le code est montré dans l'exemple 6-2 et est stocké dans handmade.cpp.

Le fichier commence par inclure tous les fichiers d'en-tête qui s'imposent - comprenant handmade.h. Puisse que le code est fortement commenté je laisse le lecteur comprendre l'exercice. Il faut noter que les boîtes côte à côte sont dessinées à partir du haut vers le bas ou à partir de la gauche vers la droite. C'est un bon exercice de corréler le schéma 6-2 avec le code. Rappelez-vous que la boîte extérieure est manipulée par la dérivation de QVBox. En outre, notez comment les paramètres parent et nom sont facilement transmis au constructeur de base depuis notre constructeur fait main.

#include <qlcdnumber.h>
#include <qlistbox.h>
#include <qpushbutton.h>
#include <qhbox.h>
#include <qslider.h>

#include "handmade.h"

HandMade::HandMade( QWidget *parent, char *name ) : QVBox( parent, name )
{
  // Une boîte horizontale pour la liste, le slider et le LCD
  QHBox *hb = new QHBox( this );

  // La liste est placée d'abord (c.-à-d. vers la gauche)
  lb = new QListBox( hb );

  // Une boîte verticale pour placer le LCD au-dessus du slider
  // Il est placé à la droite de la liste
  QVBox *vb = new QVBox( hb );

  // Le LCD est créé d'abord et est ainsi affiché au dessus
  lcd = new QLCDNumber( vb );
  // Le slider est crée en deuxième et est placé au-dessous du LCD
  QSlider *s = new QSlider( Horizontal, vb );
  // Nous connectons le signal valueChanged(int) du slider au LCD
  connect( s, SIGNAL(valueChanged(int)), lcd, SLOT(setValue(int)) );

  // Un boîte horizontale pour les boutons, au-dessous de la liste, du slider et du LCD
  hb = new QHBox( this );

  // Le bouton add va être à gauche
  QPushButton *pb = new QPushButton( "Add", hb );
  // Connecté au slot addNumber()
  connect( pb, SIGNAL(clicked()), this, SLOT(addNumber()) );
  // Le bouton remove va être à la droite du bouton add
  pb = new QPushButton( "Remove", hb );
  // Connecté au slot removeNumber
  connect( pb, SIGNAL(clicked()), this, SLOT(removeNumber()) );
}

Exemple 6-2

Après le code de l'exemple 6-2 l'implémentation pour les slots suit. Ce code est montré dans l'exemple 6-3 et est également mis dans handmade.cpp. Ce code est également fortement commenté et ne devrait pas poser de grands problèmes pour l'interpréter (référez-vous à la Documentation de Qt si vous ne comprenez aucune méthode). Notez que nous employons les pointeurs déclarés dans la définition de classe (lcd et lb) par opposition au pointeur pb qui était seulement disponible dans le constructeur.

void HandMade::addNumber()
{
  // Insertion simple du nombre affiché par le LCD
  lb->insertItem( QString::number( lcd->intValue() ) );
}

void HandMade::removeNumber()
{
  // Retour si aucun élément n'est sélectionné
  if( lb->currentItem() < 0 )
    return;

  // Suppression de l'élément sélectionné
  lb->removeItem( lb->currentItem() );
}

Exemple 6-3

Enfin le dernier morceau de code doit être ajouté. Dans le fichier main.cpp une fonction main triviale est implémentée qui crée une instance de la classe faite main et lance la boucle d'événement de Qt. Le code est montré dans l'exemple 6-4.

#include <qapplication.h>

#include "handmade.h"

int main( int argc, char **argv )
{
  QApplication a( argc, argv );

  HandMade *hm = new HandMade();
  a.setMainWidget( hm );
  hm->show();

  return a.exec();
}

Exemple 6-4

Pour créer le fichier Makefile une description de projet est nécessaire. Mettez le code de l'exemple 6-5 dans un fichier appelé handmade.pro. Alors lancez qmake && make && ./handmade à partir d'une console pour créer un fichier Makefile, l'utiliser et exécuter ensuite le résultat (les doubles & s'assure que l'étape précédente a réussie avant de lancer la suivante). Cette tâche peut être faite automatiquement par qmake en appelant qmake -project, mais ceci est censé être une application faite main.

SOURCES = handmade.cpp main.cpp
HEADERS = handmade.h

Exemple 6-5

En exécutant l'application quelque chose semble ne pas fonctionner. L'affichage à cristaux liquides ne change pas quand le slider est déplacé ! L'explication peut être trouvée dans les messages d'erreur affichés dans la console (j'espère que vous l'exécutez depuis la console). Le message d'erreur est montré dans l'exemple 6-6.

QObject::connect: No such slot QLCDNumber::setValue(int)
QObject::connect: (sender name: 'unnamed')
QObject::connect: (receiver name: 'unnamed')

Exemple 6-6

Précédemment j'ai cité les paramètres standard de Qt, parent et nom, et j'ai dit que nom était employé en debugant. Si nous avions donné des noms à chacun des widgets, alors ces noms auraient été présents dans les messages d'erreur au lieu de '"unnamed", facilitant de ce fait pour nous la correction du code. Dans ce petit exemple nous pouvons localiser le problème sans nom. Le slot setValue(int) absent du LCD est appelé display(int) selon la documentation Qt. Corrigez uniquement la connexion dans le constructeur selon l'exemple 6-7.

  // Nous connectons le signal valueChanged(int) du slider au LCD
  connect( s, SIGNAL(valueChanged(int)), lcd, SLOT(display(int)) );

Exemple 6-7

Après une recompilation l'application devrait fonctionner correctement (lancez uniquement make, pas besoin de qmake puisqu'il n'y a aucun nouveau fichier). Essayez de déplacer le slider, d'ajouter quelques nombres à la liste et d'en enlever.

Résumé

L'exemple de ce chapitre montre à quel point il est facile de créer des applications en utilisant Qt, mais sans Qt Designer. Dans des applications réelles les dispositions sont habituellement gérées dans Designer, mais le code joue toujours un grand rôle en fournissant les fonctionnalités.

Vous avez vu comment les problèmes de signaux et de slots sont montrés. Cela présente le problème d'examiner toutes les connexions, mais c'est géré facilement si toutes les connexions sont établies en utilisant Designer.

En outre, vous avez vu à quel point il est facile de créer et d'utiliser des fichiers-projets avec qmake. Comparé aux fichiers makefile écris à la main, cette approche est bien plus facile.

Enfin vous avez vu à quel point elle est facile de combiner les widgets existants dans un widget composé.

Le code d'exemple pour ce chapitre peut être trouvé ici.

Exercices

  1. Faites augmenter la valeur du slider à chaque fois que le bouton add est cliqué.
  2. Créez un widget, LCDSlider comprenant l'afficheur à cristaux liquides et le slider dérivés de QVBox. Fournissez le slot setValue(int) changeant la valeur montrée. Employez le nouveau widget dans le code fourni dans ce chapitre.

Lecture recommandée

This is a part of digitalfanatics.org and is valid XHTML.