À la découverte de Qt

Cet article est le premier d'une série consacrée à la librairie Qt, une librairie C++ développée par TrollTech et sur laquelle est entièrement basé l'environnement KDE. Il s'agit donc de l'un des acteurs majeurs dans le monde Linux - et puis, il fallait bien apporter une réponse à la série sur les librairies Gtk+ de mon confrère DindinX.

1. Installation

2. Utilisation

3. Codons !

4. Conclusion

5. Références

codes sources

D'ailleurs, je ferai de fréquentes analogies entre les deux librairies, non pas dans le but malin d'enflammer les trolls, mais afin de vous donner un maximum de points de repères. En parlant de trolls, Qt a été (et est encore) développé par la société TrollTech, basée à Oslo en Norvège [1]. Il ne s'agit donc pas d'un projet « purement libre », mais bien d’un produit commercial - aspect qui a été l’occasion d’une guerre violente entre « gnomiens » et « kdeistes » (les utilisateurs de fvwm ou WindowMaker devaient compter les points en riant). Aujourd’hui, la librairie Qt présente une remarquable portabilité (Unix/X11, Windows, MacOS, et périphériques en frame-buffer). Toutefois seules les versions pour X-Window et pour frame-buffer sont distribuées sous licence GPL (si, la vraie, l’originale) ainsi que sous licence QPL pour ceux que la GPL irrite.

1. Installation

Mais assez parlé. Si vous avez la dernière mouture de KDE (2.2.2), vous avez déjà sans doute la librairie Qt d’installée, version 2.3.1 ou 2.3.2. Mais comme la version 3.0.1 vient de sortir, et que KDE 3 (à paraître début de l’année prochaine) sera basé dessus, je vous propose d’installer dès maintenant la dernière version de Qt, en parallèle de votre version actuelle : surtout ne la remplacez pas, les deux versions sont incompatibles, et KDE ne fonctionnerait plus.

La méthode présentée ici, si elle n’est pas des plus élégante, fonctionne fort bien sur ma distribution Debian sid. Commencez par télécharger la librairie, par exemple avec :

$ wget -nd --passive-ftp \ ftp://ftp.trolltech.com/qt/source/qt-x11-free-3.0.1.tar.gz

Il faut maintenant décider où vous installez la librairie. Elle sera en effet logée dans son répertoire à elle, pour ne pas (trop) polluer votre installation. Personnellement j’utilise /usr/local/lib/qt3, les étapes sont alors :

$ cd /usr/local/lib
$ tar zxvf /chemin/vers/qt-x11-free-3.0.1.tar.gz
$ mv qt-x11-free-3.0.1/ qt3

Afin de nous placer dans un environnement favorable pour la compilation de la librairie, il est nécessaire de définir au moins la variable d’environnement QTDIR comme suit :

$ export QTDIR="/usr/local/lib/qt3"

Qt est accompagnée de quelques outils propres, qui sont construits durant la compilation pour être utilisés par la suite. Aussi est-il nécessaire d'étendre le PATH pour que notre Qt trouvez ces outils (notez que ceux-ci prendrons le pas sur ceux éventuellement déjà installés par ailleurs) :

$ export PATH="$QTDIR/bin:$PATH"
$ cd $QTDIR

Nous voilà prêt à configurer la librairie. Elle est fournie avec un script configure, aussi pour voir les différentes options disponibles :

$ ./configure --help

Quelques explications sur ces options :

Petit reproche, il n’est pas évident de savoir quels sont les modules inclus ou non par défaut, ou les formats d’images inclus comme plugins ou « en dur ». Sachant cela, et voulant utiliser les images GIF, les threads, tous les modules, ainsi que les bases de données, j’utilise la commande suivante pour configurer Qt :

$ ./configure -release -qt-gif -thread -no-g++-exceptions -qt-sql-mysql -qt-sql-psql -enable-styles -enable-tools -enable-kernel -enable-widgets -enable-dialogs -enable-iconview -enable-workspace -enable-network -enable-canvas -enable-table -enable-xml -enable-opengl -enable-sql -qt-imgfmt-jpeg -qt-imgfmt-mng -qt-imgfmt-png -no-xinerama -I/usr/include/postgresql/ -I/usr/include/mysql/

Ce n’est pas le plus optimisé possible, mais ça me convient. Ceci va générer les divers Makefiles pour compiler non seulement la librairie, mais également les exemples qui l’accompagnent. Pendant que ça tourne, allez donc vous préparer un café.

Lorsque la commande précédente se termine enfin, vous pouvez lancer la compilation avec un simple

$ make

Bon, là, étant donné le temps que ça prend, buvez votre café, faites-en un autre, sortez le chien... C’est du C++, et malheureusement notre compilateur préféré GCC semble assez lent à compiler le C++.

Lorsque la compilation est terminée, les répertoires les plus intéressants sous /usr/local/lib/qt3 sont :

Plus quelques autres que nous verrons par la suite.

2. Utilisation

L’utilisation de Qt 3 nécessite de définir quelques variables d’environnement. Personnellement, j’utilise pour cela un petit fichier placé dans mon répertoire maison, nommé qt3exp, qui contient :

export QTDIR="/usr/lib/qt3"
export QMAKESPECS="$QTDIR/mkspecs/linux-g++"
export PATH="$QTDIR/bin:$PATH"
export LD_LIBRARY_PATH="$QTDIR/lib:$LD_LYBRARY_PATH"

Il suffit ensuite de le charger dans le shell courant (bash dans mon cas) :

$ . ~/qt3exp

À adapter selon le shell que vous utilisez.

Cela étant fait, lancez un utilitaire de configuration de Qt :

$ qtconfig &

Cet utilitaire permet de définir le comportement par défaut de Qt, comme la police par défaut, l’aspect général des objets graphiques, la durée d’un double-click... Bref configurez ce que vous voulez, c’est plus du confort qu’autre chose.

3. Codons !

Bon, il va être temps de coder un peu quand même, ne serait-ce que pour vérifier que ça marche. Je vous propose un classique « Hello world » un peu étendu, écrit dans un fichier nommé, par exemple, demo01.cpp :

01: #include <qapplication.h>
02: #include <qlabel.h>
03: int main (int argc, char* argv[])
04: { QApplication app (argc, argv) ;
05:   QLabel label("<h1>Test Qt</h1>"
06:                "Voici un label Qt, qui permet d?afficher :\n"
07:                "<ul><li>du <b>gras</b> ;"
08:                "<li>de l?<i>italique</i> ;"
09:                "<li>de la <font color=\"red\">couleur</font> ;"
10:                "<li>et tout ça dans une liste !</ul>", 0) ;
11:   app.setMainWidget(&label) ;
12:   label.show() ;
13:   return app.exec() ;
14: }

J’en vois déjà qui ouvrent de grands yeux... La compilation se fait avec :

$ g++ -I$QTDIR/include -L$QTDIR/lib -lqt-mt -o demo01.x demo01.cpp

Attention, si vous avez compilé Qt sans le support des threads (si vous n’avez pas donné l’option -thread à configure plus haut), il faut utiliser -lqt au lieu de -lqt-mt. Lorsque ce simple petit programme est compilé, exécutez-le avec

$ ./demo01.x

Vous obtenez quelque chose comme ça :

Un peu plus avancé qu’un simple « Hello world », n’est-ce pas ? Reprenons cela en détail :

01: #include <qapplication.h>
02: #include <qlabel.h>

Ces deux premières lignes sont assez évidentes, la première nous donne accès à la classe QApplication, la seconde à la classe QLabel.

03: int main (int argc, char* argv[])
04: { QApplication app (argc, argv) ;

La traditionnelle fonction main(). La première chose que nous faisons est de créer une instance de la classe QApplication : c’est elle qui encapsule les diverses fonctionnalités globales (comme l’interprétation des arguments standards comme -display ou -geometry). Il ne peut y en avoir qu’une seule par programme, et au moins une pour un programme possédant une interface graphique (dans ce cas, elle doit être créée avant tout autre objet graphique). Cette instance est par la suite toujours accessible en tout point du programme par une variable globale nommée qApp (pointeur défini dans <qapplication.h>).

À l’issue de cette déclaration, le tableau argv est dépouillé des arguments classiques pour une application graphique, et argc est modifié en conséquence.

Si je précise « au moins une », c’est que Qt contient quelques classes qui peuvent être utilisées indépendamment d’une interface graphique (classes containers, utilitaires, ...). Vous en trouverez la liste dans $QTDIR/doc/html/tools.html.

05:   QLabel label("<h1>Test Qt</h1>...dans une liste !</ul>", 0) ;

Les éléments affichables d’un programme Qt sont désignés par le terme de widget (le même qui est utilisé par Gtk+). Tous les objets graphiques dérivent (directement ou non) d’une classe commune QWidget. Si cela vous intéresse, vous trouverez un graphique (cliquable) représentant la hiérarchie des classes Qt dans $QTDIR/doc/html/classchart.html.

Nous déclarons ici un objet QLabel, utilisé pour afficher un morceau de texte non modifiable (sauf par le programme lui-même). Le constructeur prend deux arguments, d’abord le texte à afficher, ensuite un pointeur sur l’objet graphique qui va contenir le label. Comme le label est ici le seul et unique widget de notre programme, il n’a pas de parent, d’où le 0.

Mais sans doute votre oeil alerte a-t-il remarqué le contenu de la chaîne de caractères : ce sont effectivement des tags, qui ressemblent fortement à ceux du HTML. Pratiquement tous les widgets de Qt qui affichent du texte sont capables d’interpréter ce genre de tags. Attention toutefois, ce n’est pas du HTML, mais plutôt un substrat limité (mais qui permet déjà pas mal de fantaisies assez facilement). Pour avoir la liste des tags supportés par défaut, voyez $QTDIR/doc/html/qstylesheet.html.

11:   app.setMainWidget(&label) ;

Il est nécessaire de préciser quel est le widget qui va contenir les autres, le widget principal. C’est le rôle de la méthode QApplication::setMainWidget(), à laquelle nous donnons ici l’adresse de notre label.

12:   label.show() ;

Simplement pour indiquer à notre widget principal qu’il peut s’afficher dès que possible.

13:   return app.exec() ;

Enfin, la méthode QApplication::exec() lance la boucle principale de Qt, celle qui va recevoir les évènements de l’utilisateurs (clic de souris, etc.) et les diriger vers les bons widgets. Cette fonction ne se termine que par l’appel à QApplication::exit() (et la valeur de retour est celle donnée à exit()), ou par la destruction du dernier widget principal.

4. Conclusion

Voilà, c’est tout pour cette petite mise en bouche. Dans le prochain article, nous découvrirons de nouveaux widgets, un peu plus précisément comment tout cela s’organise, ainsi que la méthode originale utilisée par Qt pour réagir aux évènements qui peuvent survenir.


5. Références

TrollTech : http://www.trolltech.com

Licence Unisys qui embête tout le monde : http://www.unisys.com/unisys/lzw/


Yves Bailly

http://www.kafka-fr.net


Article publié dans LinuxMagazine 36 de février 2002