Le Manuel de Programmation de KDevelop: Le Manuel de l'Utilisateur pour la Conception d'Applications C++ pour l'Environnement de Bureau KDE avec l'EDI KDevelop, Version 1.2 | ||
---|---|---|
Précédent | Suivant |
La société norvégienne Troll Tech (\|\|) 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 (\|\|) 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 :
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.
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 :
le constructeur QApplication()
la méthode setMainWidget() et
la méthode exec().
Disséquons l'utilisation de ces méthodes :
créer d'abord une instance de la classe QApplication avec le constructeur afin de pouvoir utiliser les éléments graphiques fournis par Qt
créer un widget qui sera le contenu de la fenêtre du programme
définir le widget comme widget principal pour a
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 :
créer une instance de QPushButton, utiliser le deuxième constructeur pour définir le texte du bouton
redimensionner le widget pour que tout le texte qu'il contient apparaisse
définir le widget comme étant le widget principal de l'instance a de QApplication
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.
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.
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 :
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
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
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:
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
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.
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 .