The K Desktop Environment

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 :

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 :

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 :

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 :

b) toutes les autres entrées du clavier :

c) mouvements de la souris :

d) actions des boutons de la souris :

e) événements de la fenêtre contenant le widget :

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 :

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

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