Page suivante Page précédente Table des matières
La société norvégienne Troll Tech ( http://www.troll.no) fournit une boîte à outils graphique (NdT : GUI toolkit) nommée Qt. Ici, graphique doit être pris au sens d'"Interface Utilisateur Graphique" (NdT : GUI signifie littéralement Graphical User Interface). Les applications basées sur Qt sont donc représentées par des boutons, des fenêtres, etc, permettant ainsi à l'utilisateur de visualiser les fonctions fournies par l'application. Une telle boîte à outils est nécessaire pour développer des applications graphiques qui s'exécutent sur l'interface X-Window des Systèmes Unix car X ne contient pas en lui-même d'interface utilisateur prédéfinie. Bien que d'autres boîtes à outils soient aussi disponibles pour créer des Interfaces Utilisateur, Qt offre des avantages techniques qui rendent la conception d'applications vraiment simple. En plus, Qt est aussi disponible pour les systèmes Microsoft Windows, ce qui permet aux développeurs de fournir leurs applications pour les deux plates-formes.
L'équipe KDE ( http://www.kde.org) dont le but est de rendre l'utilisation des Systèmes Unix plus conviviale a décidé d'utiliser la boîte à outils Qt pour le développement d'un gestionnaire de fenêtres basé sur X-Window, et la réalisation d'un grand nombre d'outils inclus dans les paquetages de KDE. Les composants principaux de l'Environnement de Bureau KDE sont le gestionnaire de fenêtres kwm, le gestionnaire de fichiers kfm et le tableau de bord kpanel ainsi que d'autres outils et applications de premier plan. Après la sortie de KDE, beaucoup de développeurs se sont intéressés à ce nouvel environnement et ce qu'il avait à leur offrir. Les bibliothèques de KDE fournissent les classes et les méthodes essentielles pour donner à vos applications une apparence similaire et homogène. Ainsi, l'utilisateur a l'énorme avantage de ne pas avoir besoin de s'accoutumer au comportement spécifique de chaque application ou à la façon de gérer les boîtes de dialogue ou les boutons. En plus, les programmes KDE s'intègrent eux-mêmes dans le bureau, sont capables d'interagir avec le gestionnaire de fichiers par glisser-déposer, autorisent la gestion de session et bien plus si toutes les fonctionnalités offertes par les bibliothèques de KDE sont utilisées.
La boîte à outils Qt et les bibliothèques de KDE sont toutes implantées dans le langage de programmation C++ ; aussi, les applications qui les utilisent sont généralement écrites en C++. Dans le chapitre suivant, nous survolerons les bibliothèques pour voir ce qui est déjà disponible et comment les applications KDE et Qt sont créées, en général.
Comme mentionné précédemment, la bibliothèque Qt est une boîte à outils qui fournit des éléments graphiques qui sont utilisés pour créer des applications graphiques (NdT : GUI applications) et sont nécessaires pour programmer X-Window. De plus, cette boîte à outils offre :
Il apparaît donc essentiel de connaître les classes de Qt, même si vous voulez seulement programmer des applications KDE. Pour avoir un aperçu de la façon dont les applications graphiques sont compilées et construites, nous allons d'abord jeter un oeil à un exemple de programme basé uniquement sur Qt ; ensuite, nous en ferons un programme KDE.
Comme d'habitude, les programmes écrits en C++ doivent contenir une fonction
main()
qui est le point de départ de l'exécution de l'application. Comme
nous voulons qu'ils soient affichés
graphiquement dans des fenêtres et qu'ils permettent d'interagir avec
l'utilisateur, nous devons d'abord savoir comment ils peuvent s'afficher
eux-mêmes à l'utilisateur. À titre d'exemple, nous allons regarder le premier
tutoriel inclus dans la Documentation de Référence en ligne de Qt,
expliquer les étapes de base de l'exécution et voir pourquoi et comment la
fenêtre de l'application apparaît :
#include <qapplication.h>
#include <qpushbutton.h>
int main( int argc, char **argv )
{
QApplication a( argc, argv );
QPushButton hello( "Hello world!" );
hello.resize( 100, 30 );
a.setMainWidget( &hello );
hello.show();
return a.exec();
}
Globalement, l'application dessine une fenêtre contenant un bouton dont le
texte est "Hello world". Comme pour toute application basée sur Qt,
vous devez d'abord créer une instance de la classe QApplication
,
ici représentée par a
.
Ensuite, le programme crée une instance de la classe QPushButton
appelée
hello
, ce sera le bouton. Le constructeur de hello
prend en paramètre
une chaîne de caractères qui est le contenu de la partie visible du widget,
c'est-à-dire le texte du bouton.
Ensuite, la méthode resize()
est appelée pour le bouton hello
. Cela
remplace la taille par défaut qu'un widget (ici, c'est un QPushButton) a lorsqu'il
est créé par une longueur de 100 pixels et une hauteur de 30 pixels. Enfin, la
méthode setMainWidget()
est appelée pour a
et la méthode show()
pour hello
. La QApplication
est enfin exécutée par le a.exec()
,
entre dans la boucle principale d'événements et attend jusqu'à devoir retourner
une valeur entière au Système d'Exploitation sous-jacent pour lui signaler que
l'application s'est terminée.
Maintenant, regardons rapidement le manuel de référence de la
bibliothèque Qt. Pour cela, lançons KDevelop et choisissons
"Bibliothèque Qt" dans le menu "Aide" de la barre de menus. Le navigateur
de documentation s'ouvre et affiche la page d'accueil de la référence de Qt.
Ce sera votre source d'information privilégiée sur Qt, ses classes et les
fonctions disponibles. D'ailleurs, le programme ci-dessus est le premier qui
est inclus dans la section des tutoriels. Pour accéder aux classes qui nous
intéressent (QApplication
et QPushButton
), sélectionnez
"Alphabetical Class List" et cherchez les noms correspondants. Cliquez sur le
lien pour consulter la documentation de la classe.
Pour QApplication
, vous verrez le constructeur et toutes les autres
méthodes que fournit cette classe. Si vous suivez le lien, vous obtiendrez plus
d'informations sur l'utilisation et la signification des méthodes, ce qui est
très utile quand vous ne devinez pas l'utilisation appropriée ou que vous voulez
un exemple. Cela s'applique aussi à la documentation des bibliothèques de KDE
qui utilise un type de documentation similaire ; c'est donc presque tout ce que
vous avez à savoir sur l'utilisation des références (croisées) de classes dans
le navigateur de documentation.
En commençant par QApplication
, vous trouverez toutes les méthodes
utilisées dans notre premier exemple :
QApplication()
setMainWidget()
etexec()
. Disséquons l'utilisation de ces méthodes :
QApplication
avec le
constructeur afin de pouvoir utiliser les éléments graphiques fournis par Qt a
a
de QApplication
. Le second objet de notre programme est le PushButton, une instance de la classe
QPushButton
.
Nous utilisons le second des deux constructeurs donnés pour créer une instance ; ici,
c'est la chaîne de caractères "Hello world!". Ensuite, nous avons appelé la méthode
resize()
pour changer la taille du bouton en fonction de son contenu - le bouton
doit être agrandi pour que la chaîne apparaisse complètement.
Et la méthode show()
? Eh bien, vous constatez que, comme la plupart des autres
widgets, QPushButton
est basé sur un héritage simple - ici, la documentation
indique Inherits QButton
. Suivez le lien vers la classe
QButton
. Cela affiche beaucoup de méthodes qui sont héritées par
QPushButton, que nous utiliserons plus tard pour expliquer le mécanisme signal/slot.
De toute façon, la méthode show()
n'est pas listée, c'est sûrement une méthode
fournie par l'héritage. La classe dont hérite QButton
est QWidget
.
Suivez à nouveau le lien et vous verrez un grand nombre de méthodes que la classe
QWidget
définit (dont la méthode show()
). Maintenant, nous comprenons
mieux ce qui s'est passé avec le bouton dans l'exemple :
QPushButton
, utiliser le deuxième constructeur
pour définir le texte du bouton a
de
QApplication
show()
, une méthode
héritée de QWidget
. Après l'appel à la méthode exec()
, l'application est visible pour l'utilisateur,
elle a dessiné une fenêtre avec le bouton affichant "Hello world!". Par contre, les
programmes graphiques se comportent un peu différemment des applications procédurales.
Ici, le point essentiel est que l'application entre dans une "boucle d'événements principale".
Cela signifie que le programme doit attendre des actions de l'utilisateur et ensuite y réagir.
Pour une application Qt, le programme doit être dans la boucle d'événements
principale pour commencer à traiter les événements. La section suivante vous explique
brièvement ce que cela signifie pour le programmeur et ce que Qt fournit pour
traiter les événements utilisateur.
(Pour les utilisateurs déjà expérimentés : le bouton n'a pas de parent déclaré dans le
constructeur, c'est donc un "top-level widget" seul et s'exécute dans une boucle
d'événements locale qui ne nécessite pas d'attendre la boucle d'événements principale,
voir la documentation de la classe QWidget
et
le Guide de Référence des Bibliothèques de KDE).
Résumé :
Une application Qt doit toujours avoir une instance de la classe
QApplication
. Cela garantit que nous pouvons créer des fenêtres qui
sont la représentation graphique pour l'utilisateur et permettent d'interagir
avec l'utilisateur. Le contenu de la fenêtre est appelé "Main Widget",
signifiant que tous les éléments graphiques sont basés sur la classe QWidget
et peuvent être de n'importe quel type de widget correspondant aux besoins de
l'application pour interagir avec l'utilisateur. Aussi, tous les éléments
utilisateur doivent hériter de QWidget
pour être visibles.
Après avoir lu les dernières sections, vous devriez déjà savoir :
Maintenant, nous allons commencer à donner de la "vie" à l'application en traitant les événements utilisateur. Généralement, l'utilisateur a deux façons d'interagir avec un programme : la souris et le clavier. Pour tous les deux, une interface graphique utilisateur doit fournir des méthodes qui détectent les actions et des méthodes qui font quelque chose en réaction à ces actions.
Pour cela, le système de fenêtrage (NdT : Window system) envoie tous les événements
d'interaction à l'application correspondante. La QApplication les envoie ensuite
à la fenêtre active sous la forme d'un QEvent
et les widgets eux-mêmes
doivent décider ce qu'ils veulent en faire. Un widget reçoit l'événement et traite
QWidget
::event(QEvent*)
, qui décide ensuite quel événement
doit être exécuté et comment réagir ; event() est donc le gestionnaire d'événement
principal. Ensuite, la fonction event()
passe l'événement à des filtres d'événements
qui déterminent ce qui s'est passé et quoi faire avec l'événement. Si aucun filtre n'est
responsable de l'événement, les gestionnaires d'événements spécialisés sont appelés. Nous
pouvons alors décider entre :
a) Événements clavier -- touches TAB et Shift-TAB :
change le focus d'entrée du clavier du widget courant vers le widget suivant dans
l'ordre du focus. Le focus peut être défini en appelant
setFocusPolicy
()
et traitant les gestionnaires d'événements :
virtual void focusInEvent
( QFocusEvent * )
virtual void focusOutEvent
( QFocusEvent * )
b) toutes les autres entrées du clavier :
virtual void keyPressEvent
( QKeyEvent * )
virtual void keyReleaseEvent
( QKeyEvent * )
c) mouvements de la souris :
virtual void mouseMoveEvent ( QMouseEvent * )
virtual void enterEvent ( QEvent * )
virtual void leaveEvent ( QEvent * )
d) actions des boutons de la souris :
virtual void mousePressEvent ( QMouseEvent * )
virtual void mouseReleaseEvent ( QMouseEvent * )
virtual void mouseDoubleClickEvent ( QMouseEvent * )
e) événements de la fenêtre contenant le widget :
virtual void moveEvent ( QMoveEvent * )
virtual void resizeEvent ( QResizeEvent * )
virtual void closeEvent ( QCloseEvent * )
Remarquez que toutes les fonctions d'événements sont virtuelles et protégées ; ainsi,
vous pouvez ré-implanter les événements dont vous avez besoin dans vos propres widgets
et spécifier comment votre widget doit réagir. QWidget
contient aussi
d'autres méthodes virtuelles qui peuvent être utiles dans vos programmes ; en règle
générale, il est suffisant de bien connaître QWidget
.
Nous arrivons maintenant à l'avantage le plus évident de la boîte à outils Qt :
le mécanisme signal/slot. Il offre une solution très pratique et utile pour l'interaction
entre objets, qui est souvent réalisée par des fonctions callback
par les boîtes à
outils pour X-Window. Comme cette communication nécessite une programmation stricte et
rend parfois la création d'interfaces utilisateur très difficile (comme indiqué par la
documentation de Qt et expliqué dans Programmer avec Qt par K. Dalheimer),
Troll Tech a inventé un nouveau système où les objets peuvent émettre des signaux qui
sont connectés à des méthodes déclarées comme des slots. Du point de vue du
programmeur C++, celui-ci a seulement peu de choses à savoir sur le mécanisme :
Q_OBJECT
au début (sans le point-virgule) et doit dériver de la
classe QObject
emit
, exemple emit signal(parameters);
de l'intérieur de n'importe quelle fonction membre d'une classe qui autorise les
signaux/slotssignals:
slot
, exemple : public slots:
dans
la déclaration de la classemoc
doit être exécuté sur le fichier d'en-tête pour
traiter les macros et produire l'implantation (mais le savoir n'est pas vraiment
nécessaire). Les fichiers générés par moc
sont ensuite compilés par le compilateur C++. Une autre façon d'utiliser les signaux sans hériter de QObject
est d'utiliser la
classe QSignal
- voir le manuel de référence pour plus d'informations et un exemple
d'utilisation. Dans la suite, nous dériverons toujours de QObject
.
De cette façon, votre classe est capable d'envoyer des signaux n'importe où et de fournir des "slots" qui seront connectés à des signaux. Quand vous utilisez des signaux, vous n'avez pas à vous soucier de qui les reçoit - vous émettez juste le signal et quelque soit le slot que vous y avez connecté, il peut réagir à l'émission. Par ailleurs, les slots peuvent aussi être utilisés comme des méthodes normales pendant l'implantation.
Maintenant, pour connecter un signal à un slot, vous devez utiliser les méthodes
connect()
qui sont fournies par QObject
ou, lorsque c'est possible, des méthodes
spéciales que des objets fournissent pour définir la connexion pour un certain signal.
Pour expliquer la façon de définir une interaction entre objets, nous allons reprendre notre premier exemple et l'étendre avec une connexion simple :
#include <qapplication.h>
#include <qpushbutton.h>
int main( int argc, char **argv )
{
QApplication a( argc, argv );
QPushButton hello( "Hello world!" );
hello.resize( 100, 30 );
a.setMainWidget( &hello );
connect(&hello, SIGNAL( clicked() ), &a, SLOT( quit() ));
hello.show();
return a.exec();
}
Vous voyez, le seul ajout pour donner plus d'interaction au bouton est d'utiliser une
méthode connect()
:
connect(&hello, SIGNAL( clicked() ), &a, SLOT( quit() ));
et c'est tout ce
que vous devez ajouter. Qu'est-ce que cela signifie réellement ? La déclaration de la
classe QObject
décrit ainsi la méthode connect()
:
bool connect ( const QObject * sender, const char * signal, const QObject * receiver, const char * member )
Cela signifie que vous devez donner un pointeur sur une instance de QObject qui est l'émetteur du signal, ce qui veut dire qu'il peut émettre ce signal comme premier paramètre. Ensuite, vous devez spécifier le signal auquel vous voulez vous connecter. Les deux derniers paramètres sont l'objet receveur qui fournit un slot, suivi de la fonction membre qui, en fait, est le slot qui sera exécuté lors de l'émission du signal.
En utilisant des signaux et des slots, les objets de votre programme peuvent interagir facilement les uns avec les autres sans dépendre explicitement du type de l'objet receveur. Vous en apprendrez plus sur l'utilisation de ce mécanisme pour un usage intensif dans la suite de ce manuel. Plus d'informations sur le mécanisme Signal/Slot peuvent être trouvées dans Le Guide de Référence des Bibliothèques de KDE et dans le Manuel de Référence de Qt.
Au moment d'écrire ce manuel, et du fait que KDevelop utilise KDE 1.1, je me réferre à l'état des bibliothèques de KDE dans cette version. Les principales bibliothèques de KDE que vous allez utiliser pour créer vos propres applications KDE sont :
Maintenant, nous allons regarder ce qui doit être fait pour convertir notre application Qt en une application KDE.
Dans la suite, vous allez voir qu'écrire une application KDE n'est vraiment pas plus difficile que d'écrire une application Qt. Pour accéder aux fonctionnalités de KDE, vous devez seulement utiliser quelques classes supplémentaires et c'est presque tout. Comme exemple, nous allons traiter la version modifiée de l'exemple de Qt utilisé précédemment :
#include <kapp.h>
#include <qpushbutton.h>
int main( int argc, char **argv )
{
KApplication a( argc, argv );
QPushButton hello( "Hello world!" );
hello.resize( 100, 30 );
a.setTopWidget( &hello );
connect(&hello, SIGNAL( clicked() ), &a, SLOT( quit() ));
hello.show();
return a.exec();
}
D'abord, vous voyez que nous avons changé QApplication
en KApplication
.
Ensuite, nous avons du changer la méthode setMainWidget()
précédemment utilisée en
setTopWidget
que KApplication
utilise pour définir le widget principal.
C'est fini ! Votre première application KDE est prête - vous devez seulement indiquer au
compilateur les chemins menant aux fichiers "include" de KDE et à l'éditeur de liens de
lier la bibliothèque KDE-Core avec -lkdecore.
Comme vous savez déjà ce que la fonction main() fait généralement et comment une application devient visible et permet les interactions avec l'utilisateur et entre objets, nous allons passer au chapitre suivant où nous réaliserons notre première application avec KDevelop - là, vous pourrez aussi tester tout ce qui a été mentionné précédemment et en voir les effets.
Nous vous conseillons aussi de compléter ce chapitre en approfondissant le manuel de
référence de Qt, et plus spécialement les classes QApplication
,
QWidget
et QObject
, ainsi que la documentation de la classe
KApplication
de la bibliothèque KDE-Core. Le manuel de
Référence des Bibliothèques de KDE
donne aussi une description complète sur l'appel des constructeurs de QApplication
et KApplication
, y compris le traitement des arguments de la ligne de commande.
Page suivante Page précédente Table des matières