À 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.
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.
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 :
-qt-gif
: rappelez-vous,
la licence d’Unisys concernant l’algorithme LZW... par
défaut Qt ne supporte pas (plus) le format d’images
GIF, spécifiez cela pour l’obtenir ;
-no-g++-exceptions
:
désactive le support des exceptions C++ - code plus petit,
plus rapide, mais moins solide...
-enable-<module>
:
permet d’activer ou désactiver tel ou tel élément
de Qt.
-qt-sql-<driver>
:
sélectionne les pilotes d’accès aux bases de
données (disponibles : MySQL, Postgresql et ODBC).
-thread
: permet ou non
d’utiliser le multi-threading avec Qt, en fait
paramètre l’inclusion ou non d’un module de
threads portable.
-qt-imgfmt-<format>
: comment doit être inclu le support des divers formats
d’image.
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 :
bin
, contenant les outils
de Qt, comme designer
(interface de
développement), qmake
(génération de Makefile
),
etc. ;
lib
, la librairie
elle-même ;
includes
, les fichiers
d’en-tête pour les #include
de vos programmes ;
examples
, contient de
nombreux exemples de code (la plupart compilés et prêt
à l’emploi), à consulter ;
doc
, la documentation de
la librairie : très bien faite, garder sous le coude la
version HTML dans doc/html/index.html
;
src
, le code source, pour
les amateurs.
Plus quelques autres que nous verrons par la suite.
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.
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.
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.
TrollTech : http://www.trolltech.com
Licence Unisys qui embête tout le monde :
http://www.unisys.com/unisys/lzw/
Yves Bailly
Article publié dans LinuxMagazine 36 de février 2002