Traduction par Jean-luc Biord, du Site de la communauté
Qt francophone.
English TOC.
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.
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.
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
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())
);
}
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() );
}
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();
}
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
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')
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)) );
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.
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.
This is a part of digitalfanatics.org and is valid XHTML.
Copyright (c) 2002-2004 by Johan Thelin (e8johan -at- digitalfanatics.org). This material may be distributed only subject to the terms and conditions set forth in the Open Publication License, v1.0 (local copy) or later (the latest version is presently available at http://www.opencontent.org/openpub/). Distribution of substantively modified versions of this document is prohibited without the explicit permission of the copyright holder. Distribution of the work or derivative of the work in any standard (paper) book form is prohibited unless prior permission is obtained from the copyright holder.