Page suivante Page précédente Table des matières

### 2. Les Bibliothèques de KDE et Qt

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.

### 2.1 La boîte à outils graphique Qt

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 :

- un ensemble complet de classes et de méthodes prêtes à être utilisées même pour des fonctions non graphiques
- une bonne solution pour les interactions avec l'utilisateur par l'intermédiaire des méthodes virtuelles et du mécanisme signal/slot
- un ensemble d'éléments graphiques prédéfinis appelés widgets qui peuvent facilement être utilisés pour créer les entités visibles
- des boîtes de dialogue complètement pré-définies supplémentaires qui sont souvent utilisées dans les applications (ouverture/enregistrement de fichiers, progression d'opération...).

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.

#### La première Application Qt

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.

#### Le Manuel de Référence de Qt

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.

#### Dissection de l'exemple

En commençant par `QApplication`, vous trouverez toutes les méthodes utilisées dans notre premier exemple :

- le constructeur `QApplication()`
- la méthode `setMainWidget()` et
- la méthode `exec()`.

Disséquons l'utilisation de ces méthodes :

1. créer d'abord une instance de la classe `QApplication` avec le constructeur afin de pouvoir utiliser les éléments graphiques fournis par Qt
2. créer un widget qui sera le contenu de la fenêtre du programme
3. définir le widget comme widget principal pour `a`
4. exécuter l'instance `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 :

1. créer une instance de `QPushButton`, utiliser le deuxième constructeur pour définir le texte du bouton
2. redimensionner le widget pour que tout le texte qu'il contient apparaisse
3. définir le widget comme étant le widget principal de l'instance `a` de `QApplication`
4. dire au widget de s'afficher sur l'écran en appelant `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.

#### Interaction avec l'Utilisateur

Après avoir lu les dernières sections, vous devriez déjà savoir :

- ce que fournit la bibliothèque Qt en termes d'applications graphiques
- comment un programme utilisant Qt est créé
- où et comment chercher des informations, avec le navigateur de documentation, sur les classes que vous voulez utiliser.

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

#### Interaction entre Objets par Signal et Slot

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 :

1. la déclaration d'une classe utilisant des "signaux/slots" doit contenir la macro `Q_OBJECT` au début (sans le point-virgule) et doit dériver de la classe `QObject`
2. un signal peut être émis par le mot-clé `emit`, exemple `emit signal(parameters);` de l'intérieur de n'importe quelle fonction membre d'une classe qui autorise les signaux/slots
3. tous les signaux utilisés par les classes qui ne sont pas héritées doivent être ajoutés dans la déclaration de la classe par une section `signals:`
4. toutes les méthodes qui peuvent être connectées à un signal sont déclarées dans des sections avec le mot-clé supplémentaire `slot`, exemple : `public slots:` dans la déclaration de la classe
5. le compilateur de méta-objet `moc` 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.

#### Exemple d'utilisation

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.

### 2.2 Ce que fournit KDE

#### Les bibliothèques de KDE 1.1.x

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 :

- la bibliothèque KDE-Core, contenant toutes les classes qui sont des éléments non visibles et fournit des fonctionnalités que votre application pourrait utiliser
- la bibliothèque KDE-UI, contenant des éléments d'interface utilisateur comme les barres de menus, les barres d'outils, etc
- la bibliothèque KFile, contenant les boîtes de dialogue de sélection de fichier.

En plus, pour des applications spécifiques, KDE fournit les bibliothèques suivantes :

- la bibliothèque KHTMLW, contenant un widget complet interprétant du HTML, qui est utilisé dans différents programmes comme KDEHelp, KFM ou KDevelop
- la bibliothèque KFM, permettant d'utiliser le gestionnaire de fichiers de KDE à l'intérieur de n'importe quelle application
- la bibliothèque KAB, le KAddressBook. Elle fournit un accès au carnet d'adresses pour des applications telles que les clients de messagerie
- la bibliothèque KSpell, contenant des widgets et des fonctionnalités pour intégrer l'utilisation d'Ispell, le vérificateur d'orthographe, dans des applications comme les éditeurs (utilisée notamment dans l'application KEdit).

Maintenant, nous allons regarder ce qui doit être fait pour convertir notre application Qt en une application KDE.

#### Exemple d'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