Développement d`applications graphiques

Transcription

Développement d`applications graphiques
Développement d’applications
graphiques
Département Informatique
Télécom SudParis — 1ère année
TÉLÉCOM SudParis — INF
Mars 2014
Développement d’applications graphiques
Contents
Développement d’applications graphiques
Département Informatique, , TÉLÉCOM SudParis — INF, Télécom SudParis — 1ère
année
Mars 2014
1
Plan
3
1 Généralités sur la conception d’applications graphiques
1.1 Application en mode terminal . . . . . . . . . . . . . . . . .
1.2 Application graphique . . . . . . . . . . . . . . . . . . . . .
1.3 Structuration client-serveur avec XWindow . . . . . . . . .
1.4 Programmation événementielle . . . . . . . . . . . . . . . .
1.5 Structure type d’une application graphique . . . . . . . . .
1.6 Les widgets . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.7 Bibliothèques graphiques de haut niveau . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
4
5
6
7
8
9
10
11
2 Introduction à Gtk
2.1 Aperçu de la hiérarchie de widgets Gtk . . . . . .
2.2 Un exemple simple d’interface . . . . . . . . . . . .
2.3 Programme Gtk en C pour cette interface . . . . .
2.4 Compilation d’une application Gtk en C . . . . . .
2.5 Concepteur d’interface Glade . . . . . . . . . . . .
2.6 Description XML de l’exemple d’interface . . . . .
2.7 Utilisation en C d’une description XML d’interface
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
12
13
14
15
16
17
18
19
3 Version graphique de l’application exemple
3.1 Organisation générale de l’application . . . .
3.2 Adaptation à réaliser pour gtk . . . . . . . .
3.3 Structure générale de la version graphique . .
3.4 Éléments de l’interface graphique . . . . . . .
3.5 Interaction pour l’ajout d’un ouvrage . . . .
3.6 Interaction graphique pour l’ajout . . . . . .
3.7 Affichage de la boîte de dialogue Ajout . . . .
3.8 Validation des informations saisies . . . . . .
3.9 Récupération des informations saisies . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
20
21
22
23
24
25
26
27
28
29
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
TÉLÉCOM SudParis — INF — Département Informatique — Mars 2014 — Télécom SudParis — 1ère année 2
Développement d’applications graphiques
'
$
Plan
#2
1 Généralités sur la conception d’applications graphiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2 Introduction à Gtk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3 Application exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
&
%
L’objectif de cette présentation est de donner un aperçu de l’organisation du développement d’une application graphique et quelques indications pratiques pour faciliter un tel développement en s’appuyant sur
la bibliothèque graphique Gtk et sur l’outil Glade.
Il ne s’agit cependant que d’une introduction et l’étude des documentations et des tutoriels correspondants
est bien entendu indispensable pour mener à bien une réalisation.
TÉLÉCOM SudParis — INF — Département Informatique — Mars 2014 — Télécom SudParis — 1ère année 3
Développement d’applications graphiques
'
$
1 Généralités sur la conception d’applications graphiques
#3
1.1
1.2
1.3
1.4
1.5
1.6
1.7
Application en mode terminal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Application graphique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Structuration client-serveur avec XWindow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Programmation événementielle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Structure type d’une application graphique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Les widgets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Bibliothèques graphiques de haut niveau . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
&
%
L’objectif d’une application est la production potentielle d’un ensemble de résultats à partir d’un ensemble
de données. Toute application comporte donc sous une forme ou une autre une partie traitement chargée du
calcul de résultats pertinents à partir des données disponibles, et une partie interface utilisateur dédiée à la
récupération des informations à traiter par l’application et à la présentation des résultats attendus.
Une application graphique permet une interaction de l’utilisateur avec l’application beaucoup plus riche
et confortable qu’une application en mode terminal.
D’une façon générale, les interfaces graphiques reposent sur deux notions clés : les widgets, ou composants
graphiques de l’interface, et les événements, générés à la suite d’actions de l’utilisateur.
Pour une application graphique, le travail de conception, de développement, et de test de l’interface
utilisateur peut être très conséquent, alors que les mécanismes mis en jeu sont souvent les mêmes d’une
application graphique à l’autre. Aussi, des briques de base ont-elles été développées une fois pour toutes et
mises à disposition des programmeurs sous forme d’environnements et de bibliothèques graphiques.
TÉLÉCOM SudParis — INF — Département Informatique — Mars 2014 — Télécom SudParis — 1ère année 4
Développement d’applications graphiques
'
1 Généralités sur la conception d’applications graphiques
$
1.1 Application en mode terminal
Exécution dans le cadre d’une console
#4
Déroulement de l’interaction selon une séquence prédéterminée
Le programme “contrôle les opérations”,
L’utilisateur n’est sollicité que pour saisir des informations au moment voulu
⇒ faible interactivité
Interface utilisateur en mode texte (CLI)
Possibilités d’interactions très limitées
I actions sur les touches du clavier
Saisie d’informations exclusivement textuelles
I données numériques, textes, noms de fichiers...
Possibilités d’affichage très limitées
I caractères alphanumériques, séquences d’échappement
&
%
L’interface utilisateur est constituée de l’ensemble des moyens mis à disposition de l’utilisateur pour
interagir avec l’application afin d’utiliser les fonctionnalités proposées par celle-ci. Elle permet à l’utilisateur,
lors de l’exécution de l’application, de choisir les résultats qu’il souhaite produire parmi toutes les possibilités
offertes par l’application, de préciser les données à soumettre aux traitements sélectionnés, et de prendre
connaissance des résultats produits par l’application. Son ergonomie détermine le confort d’utilisation de
l’application.
L’interactivité d’une application caractérise la fréquence à laquelle l’utilisateur peut intervenir sur le
déroulement de cette application.
Dans le cas d’une application en mode terminal, l’utilisateur n’a “la main” qu’à des instants prédéterminés, généralement avant d’engager les traitements (de façon à choisir ceux-ci et fixer les données à traiter).
L’utilisateur n’interagit avec l’application qu’à travers des saisies clavier ; on parle de Command-Line
Interface (CLI). Ces saisies nécessitent en général beaucoup de soin pour garantir un comportement fiable de
l’application et en assurer une utilisation confortable (confirmations utilisateur, validation des saisies avant
utilisation...) ; il peut être nécessaire de leur consacrer un temps important de conception, de développement,
et de test.
En dehors des saisies sollicitées par le programme, l’utilisateur ne peut intervenir de manière asynchrone
sur le déroulement de l’exécution d’une application en mode terminal que pour l’arrêter prématurément
(combinaison de touches Ctrl-C) ou pour la suspendre (Ctrl-Z).
TÉLÉCOM SudParis — INF — Département Informatique — Mars 2014 — Télécom SudParis — 1ère année 5
Développement d’applications graphiques
'
1 Généralités sur la conception d’applications graphiques
$
1.2 Application graphique
Exécution dans le cadre d’une fenêtre graphique
Déroulement de l’exécution soumis aux interventions de l’utilisateur
L’utilisateur peut, en général, interagir à tout moment avec l’application par le
biais de la souris
Le programme ne fait que réagir aux actions de l’utilisateur
#5
Possibilités d’affichage très riches
images, courbes, couleurs, épaisseur des traits, fonte des caractères
Interface utilisateur graphique (GUI)
constituée d’éléments...
I de présentation d’information : fenêtre, ascenseurs, image
I de saisie d’information : bouton, zone de saisie
I mixtes (présentation/saisie) : liste déroulante (menu)
organisée hiérarchiquement
I racine de l’arborescence : fenêtre principale
I arborescence de composants graphiques
&
%
Grâce à une interface graphique, l’utilisateur peut communiquer ses ordres non plus seulement par le
clavier, mais également en agissant, par l’intermédiaire de la souris, sur les différents composants de l’interface
graphique.
L’application est a priori conçue pour être beaucoup plus interactive qu’une application en mode terminal.
Elle permet en général à l’utilisateur d’intervenir à tout moment pour influer sur le déroulement de l’exécution
: il peut, par exemple, cliquer où il veut quand il veut (avec ou sans effet cependant, certaines actions pouvant
éventuellement être temporairement inhibées dans certaines circonstances). Le programme réagit aux actions
de l’utilisateur sur l’interface selon ce que le programmeur de l’application a prévu.
Toute application graphique s’exécute dans le cadre d’une (ou plusieurs) fenêtre(s), et présente à
l’utilisateur une interface graphique ou GUI. L’acronyme GUI signifie Graphical User Interface.
L’interface est constituée de composants graphiques élémentaires appelés widgets, correspondant à des
zones rectangulaires affichables et auxquelles sont attachées des sémantiques d’interaction : affichage, saisie
clavier, sélection par un clic souris, etc.
Widget est l’acronyme de Windows, Icons, Dialog box, Graphics Extensions, Track ball, souvent décliné
sous la forme WInDows gadGET.
Les caractéristiques d’une fenêtre sont liées à sa géométrie (taille, position à l’écran), sa bordure (épaisseur, couleur ou motif), son fond (couleur, motif ou transparence) ou encore la forme attribuée au curseur
quand il est positionné dans la fenêtre.
Le programme peut associer des effets différents au clic, au double-clic, à l’action sur les différents
boutons de la souris, et prendre en compte le positionnement (coordonnées) du curseur dans la fenêtre ou
ses déplacements.
Le contenu (information/présentation) de l’affichage évolue en fonction des interactions de l’utilisateur
avec l’interface graphique : mise à jour de certaines zones d’affichage, affichage d’informations complémentaires...
Le concepteur de l’application devra définir les objets graphiques (menus, composants...) que contiendra
la fenêtre principale de l’application et leur organisation selon une arborescence de widgets dont la racine est
la fenêtre principale, les nœuds internes des conteneurs et les feuilles des widgets graphiques.
TÉLÉCOM SudParis — INF — Département Informatique — Mars 2014 — Télécom SudParis — 1ère année 6
Développement d’applications graphiques
'
1 Généralités sur la conception d’applications graphiques
$
1.3 Structuration client-serveur avec XWindow
Le
#6
serveur graphique (serveur X )
s’exécute sur la machine de l’utilisateur (un seul serveur par machine)
attend les demandes de connexion d’applications clientes
reçoit et traite les requêtes des différentes applications clientes
gère l’affichage (tracés, texte) en s’appuyant sur des structures de données
(contextes graphiques) stockant les paramètres des actions graphiques (police,
couleur, épaisseur de trait, motif de remplissage de zone)
intercepte les actions de l’utilisateur (clavier, souris) et transmet les informations
correspondantes aux applications concernées
L’application cliente
s’exécute n’importe où, i.e. localement ou sur une machine distante
se connecte au serveur qui s’exécute sur la machine à laquelle est attachée la
console de l’utilisateur et s’enregistre pour être avertie de certaines actions
émet des requêtes, par exemple d’affichage, auprès du serveur
reçoit du serveur des informations sur les actions utilisateur auxquelles elle a
souscrit
&
%
Le fonctionnement d’une application dans un environnement graphique comme XWindow repose sur une
séparation des responsabilités entre l’application, qui exécute les traitements, et le serveur qui gère l’interface
utilisateur. Le comportement du serveur a été écrit une fois pour toutes. Les développeurs d’applications
peuvent donc se concentrer exclusivement sur la description des traitements propres à l’application.
La philosophie de XWindow repose sur la notion de ressources, qui doivent être chargées en mémoire par
le serveur X ou créées pour pouvoir être utilisées. Celles-ci peuvent être des polices, des palettes (colormap),
des contextes graphiques, des fenêtres, des matrices de pixels (pixmaps), etc.
XWindow est livré avec une bibliothèque de bas niveau de requêtes élémentaires au serveur X, la Xlib,
interface de programmation du protocole X, dont la programmation est très technique (gestion explicite du
dialogue de l’application avec le serveur X, utilisation du contexte graphique courant...).
Le serveur X s’exécute sur l’unité centrale directement raccordée à la console et gère en mémoire vive un
ensemble de ressources nécessaires à son travail d’affichage (palettes de couleurs, fontes, etc). Il surveille par
ailleurs les actions de l’utilisateur sur les différents éléments de l’interface utilisateur (fenêtres, etc) pour les
transmettre aux applications concernées.
Ces actions sont les saisies clavier (appui et relâchement de touches du clavier), les mouvements de
la souris, les actions sur ses boutons (appui, relâchement) lorsque le curseur est positionné dans certains
éléments de l’interface.
En fait, pour être notifiée de certaines actions de l’utilisateur par le serveur, une application doit auparavant s’enregistrer auprès du serveur pour les actions dont elle souhaite être alertée.
Quelques documents pour en savoir plus sur XWindow :
Concepts X11
Cours X11 (http://www.urec.cnrs.fr/IMG/ps/GERET-93.01-Cours.X11.ps)
Quelques documents pour en savoir plus sur les internes de X et sur la Xlib :
xwindow (http://www.u-picardie.fr/~ferment/xwindow/index.htm)
motif (http://buffa.developpez.com/xwindow/)
TÉLÉCOM SudParis — INF — Département Informatique — Mars 2014 — Télécom SudParis — 1ère année 7
Développement d’applications graphiques
'
1 Généralités sur la conception d’applications graphiques
$
1.4 Programmation événementielle
L’application est en permanence notifiée par le serveur graphique des actions de
l’utilisateur sur l’interface
L’utilisateur "pilote" le programme, qui ne fait que réagir aux sollicitations de
l’utilisateur... à condition que ces réactions aient été prévues par le programmeur
#7
En réponse à une action de l’utilisateur, le serveur X construit une structure
événement du type ButtonPress, KeyPress, EnterNotify...
Un événement contient toutes les informations concernant l’action associée :
composant concerné, éléments de contexte
Les infos associées à un événement dépendent de celui-ci
clic souris : coordonnées du point de clic
frappe d’un caractère : code du caractère frappé
événement lié à une fenêtre : redimensionnement, iconification
&
%
Dans un environnement graphique comme XWindow, le serveur graphique détecte en permanence les
actions utilisateur et construit les événements correspondant à ces actions. Le serveur transmet, à chaque
application cliente qui s’est enregistrée pour être notifiée, les événements correspondants sous forme d’une
file de messages.
L’application doit donc s’inscrire auprès du serveur pour recevoir les différents événements d’intérêt et
disposer de fonctions décrivant la manière de les traiter, appelées fonctions de rappel (callbacks).
Le concepteur de l’application définit les différentes actions que pourra effectuer l’utilisateur dans la
fenêtre de l’application (cliquer sur tel bouton, sur tel item d’un menu...), et décrit les traitements correspondant aux réactions de l’application à chacune des actions prévues. Le programmeur de l’application
doit bien entendu décrire précisément ces réactions dans les fonctions de rappel.
Attention, le programmeur doit identifier a priori toutes les actions de l’utilisateur qu’il veut traiter ; il
doit décrire le traitement associé, mais sans savoir à quel moment l’action sera déclenchée... et la callback
correspondante exécutée. En effet, après une phase d’initialisation, une application graphique exécute une
boucle de surveillance des événements utilisateur auxquels elle est capable de répondre. Si l’application doit
passer successivement par un ensemble d’états à la suite des actions de l’utilisateur, comme par exemple pour
simuler le déroulement d’une partie d’un jeu quelconque, il peut être nécessaire qu’une callback invoquée
puisse déterminer l’état courant afin de faire progresser l’application de façon pertinente vers un nouvel état
et préparer l’interface graphique pour l’interaction utilisateur suivante. Dans ce cas, l’état courant doit être
reflété dans des variables rendues accessibles aux callbacks (soit par l’intermédiaire de variables globales, soit
par passage de paramètre).
TÉLÉCOM SudParis — INF — Département Informatique — Mars 2014 — Télécom SudParis — 1ère année 8
Développement d’applications graphiques
'
1 Généralités sur la conception d’applications graphiques
$
1.5 Structure type d’une application graphique
Initialisation de l’usage de la bibliothèque graphique
Connexion au serveur X
Définition de ressources : palettes de couleurs, etc
Mise en place des éléments de l’interface graphique
Création en mémoire vive d’une arborescence de widgets
#8
Association d’actions aux événements pertinents sur certains éléments
Connexion des paires widget/événement à des callbacks
Affichage de l’interface
Mapping à l’écran de l’arborescence créée en mémoire vive
Boucle de gestion des événements
Récupération du prochain événement
Traitement de l’événement récupéré
&
%
Une application graphique met en place un ensemble de widgets constituant l’interface utilisateur, puis
réagit aux événements déclenchés par l’utilisateur, en exécutant les callbacks associées qui exploitent les
informations correspondantes et provoquent éventuellement des mises à jour appropriées de certains éléments
de l’interface. Le programmeur doit donc choisir les widgets constituant l’interface et définir leur organisation,
ainsi que les réactions de l’application aux actions de l’utilisateur sur ces widgets.
L’écriture du dialogue entre une application et un serveur graphique respectant un protocole tel que
le protocole X serait fastidieuse. Heureusement, les bibliothèques graphiques proposent des primitives qui
encapsulent un tel dialogue, ainsi que des composants graphiques de base prédéfinis permettant de construire
plus confortablement des interfaces graphiques.
L’utilisation d’une bibliothèque s’appuie sur une API (Application Programming Interface) qui décrit
un ensemble de types prédéfinis et des fonctions pour manipuler les objets correspondants.
La programmation d’une application graphique repose sur l’utilisation d’une bibliothèque qui fournit une
API pour la gestion des widgets et des événements, ainsi que pour celle des ressources du serveur nécessaires
à l’application.
Lorsqu’une application veut créer une fenêtre, elle adresse une requête au serveur X qui crée une réprésentation interne de la fenêtre en mémoire vive, en lui associant un identifiant et une pixmap (matrice de pixels).
Pour être visible, un widget doit être “mappé” à l’écran par le biais d’une requête d’affichage au serveur
graphique et ne devient visible que lorsque son parent est lui-même “mappé”. La fenêtre de plus haut niveau
n’a pas de parent et devient visible dès qu’elle est “mappée”.
Le mapping à l’écran d’une fenêtre consiste pour le serveur X à recopier en mémoire graphique de l’écran
la pixmap associée à la réprésentation logique interne de la fenêtre, ce qui la rend visible sur l’écran.
Pour construire une interface graphique aisément, le programmeur doit avoir une bonne connaissance des
classes de widgets disponibles dans la bibliothèque qu’il utilise, de façon à effectuer des choix pertinents. Il
doit en général travailler constamment avec la documentation de la bibliothèque.
TÉLÉCOM SudParis — INF — Département Informatique — Mars 2014 — Télécom SudParis — 1ère année 9
Développement d’applications graphiques
'
1 Généralités sur la conception d’applications graphiques
$
1.6 Les widgets
widget = aspect graphique + comportement
Ils possédent des attributs et méthodes par défaut, mais modifiables
Ils sont définis et organisés selon une hiérarchie de classes fournie par l’API
Ils autorisent, par héritage, la définition de ses propres widgets utilisateur,
dérivés de classes prédéfinies
#9
A chaque widget sont associés des événements auxquels l’application peut réagir
Un événement se traduit par un message du serveur X vers l’application pour
signaler une interaction utilisateur
Il faut associer une fonction de rappel (callback) à un tel événement (paramètres
: pointeurs sur le widget concerné et sur une donnée utilisateur)
La structure logique d’une interface graphique est une arborescence comportant
des nœuds internes qui sont des widgets conteneurs
I avec pour un conteneur ayant plusieurs widgets enfants, la possibilité de
spécifier une disposition des enfants (tailles et positions relatives)
des nœuds feuilles qui sont de simples widgets
&
%
Les widgets, éléments de base qui composent une interface graphique (bouton, ascenseur...), correspondent
en général à des régions de l’écran et sont généralement implémentés sous forme d’objets dont les types
(ou classes) sont organisés en une hiérarchie d’héritage, ce qui permet de factoriser le code décrivant les
fonctionnalités de base de ces objets.
Il ne faut pas confondre d’une part la hiérarchie des classes de widgets construite lors de la définition
d’une bibliothèque graphique, et d’autre part, quand on considère une application particulière, la structure
arborescente que celle-ci établit entre les widgets qui composent son interface graphique. Les nœuds internes
de cette arborescence sont nécessairement des widgets conteneurs, qui permettent d’organiser la disposition
relative de leurs widgets enfants dans la zone d’écran qui leur correspond dans l’interface graphique de
l’application, et selon leur type (alignement horizontal ou vertical des widgets enfants, par exemple).
Dans la conduite du dialogue avec l’utilisateur, trois notions clés interviennent :
- la sensibilité : le widget répond ou non à une saisie (il apparaît normalement ou grisé),
- le focus : le widget est la cible exclusive des saisies clavier quand il a le focus,
- la capture (ou grab) du pointeur souris et du clavier : le widget ayant la capture devient un passage obligé,
le reste de l’application étant figé (on parle de dialogue modal).
Au niveau programmation, les widgets, comme la plupart des ressources graphiques, sont manipulés à
travers des pointeurs qui sont souvent des variables globales, de façon à être accessibles sans passage de
paramètre.
Les bibliothèques graphiques proposent en général un ensemble de widgets prédéfinis et prêts à l’emploi
dont le programmeur n’a plus qu’à fixer les caractéristiques pour composer son interface graphique.
En dehors de la fenêtre principale de l’application, racine de l’arborescence logique de l’interface
graphique, chaque widget a un widget parent qui joue le rôle de conteneur et assure, lorsqu’il a plusieurs
widgets enfants, leur positionnement relatif.
TÉLÉCOM SudParis — INF — Département Informatique — Mars 2014 — Télécom SudParis — 1ère année 10
Développement d’applications graphiques
'
1 Généralités sur la conception d’applications graphiques
$
1.7 Bibliothèques graphiques de haut niveau
# 10
gdk
surcouche d’abstraction et de portabilité de la Xlib qui masque sa complexité
Gtk (Gimp tool kit)
utilisée par gnome (environnement graphique de bureau Open Source)
boîte à outils constituée de bibliothèques indépendantes : Glib, Pango, ATK...
Gtk utilise plutôt gdk que directement la Xlib => Gtk disponible sous windows
Qt
bibliothèque C++
utilisée par KDE (autre environnement graphique de bureau Open Source)
Tk
bibliothèque graphique de widgets pour l’écriture de scripts Tcl/Tk avec GUI
surcouche de Xlib
SDL
bibliothèque de programmation multimédia portable
Impossible de connaître une API par cœur => utiliser la documentation
&
%
Les primitives de la Xlib sont relativement basiques (tracé de ligne, récupération de caractères au clavier),
mais permettent cependant de produire tous les effets utiles, au prix de combinaisons le plus souvent complexes.
Pour simplifier la programmation, on utilise plutôt des API de plus haut niveau, basées sur la Xlib, comme
la boîte à outils XToolkit, par exemple, qui comporte des structures de base permettant la construction de
widgets, et les éléments nécessaires pour implémenter des menus, des boîtes de dialogue, des barres de
défilement, etc.
Le système XWindow est traditionnellement distribué avec la bibliothèque de widgets Athena (Xaw)
fournie par le MIT.
Les bibliothèques graphiques les plus utilisées sur les systèmes GNU-Linux sont gdk, Gtk, Qt et Tk.
gdk est le kit de dessin de l’application gimp (GNU image manipulation program, équivalent libre de Photoshop), et peut être considéré comme une surcouche de la Xlib pour la rendre portable (il existe un portage
sous Windows). Lorsque l’on programme avec gdk, la Xlib est néanmoins utilisable pour des manipulations
de plus bas niveau, en incluant gdk/gdkx.h.
La bibliothèque Gtk, sur laquelle repose l’environnement graphique de bureau gnome, est également
disponible sous (Windows) et permet donc le développement d’applications graphiques relativement portables.
Qt est la bibliothèque graphique sur laquelle repose l’environnement graphique de bureau KDE. Initialement propriétaire, elle est maintenant publiée sous une licence open source.
Tcl est un langage de script, i.e. permettant d’écrire des programmes exécutables sans compilation ;
l’interprète tcl lit le script instruction après instruction, analyse chacune d’elles et exécute l’action correspondante. Tk offre une couche de présentation graphique au-dessus de tcl permettant le développement
rapide d’applications graphiques.
SDL (Simple DirectMedia Layer) est une bibliothèque de programmation multimédia portable (GNULinux, Windows, Mac, *BSD... et même PSP !). Elle offre des abstractions pour manipuler les images 1D,
le son, les périphériques de jeu (clavier/souris/manettes), et permet l’exécution de calculs parallèles. Elle
est distribuée sous licence LGPL (en savoir plus sur SDL).
TÉLÉCOM SudParis — INF — Département Informatique — Mars 2014 — Télécom SudParis — 1ère année 11
Développement d’applications graphiques
'
$
2 Introduction à Gtk
# 11
2.1
2.2
2.3
2.4
2.5
2.6
2.7
Aperçu de la hiérarchie de widgets Gtk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
Un exemple simple d’interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
Programme Gtk en C pour cette interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
Compilation d’une application Gtk en C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Concepteur d’interface Glade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
Description XML de l’exemple d’interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
Utilisation en C d’une description XML d’interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
&
%
Gtk est une bibliothèque couramment utilisée pour le développement sous GNU-Linux d’applications
graphiques, exploitables également sous Windows. Elle est à la base de nombreuses applications sous GNULinux (Gimp, Gnome...).
La hiérachie de widgets de Gtk comporte des classes très élaborées, comme par exemple GtkFileSelection,
boîte de dialogue permettant la sélection graphique d’un fichier dans un système de fichiers, ou encore
GtkCTree, fenêtre permettant l’affichage d’un arbre dont l’utilisateur peut déployer les branches à volonté.
Glade est un outil graphique permettant le maquettage rapide d’interfaces graphiques simples. Il offre
à la fois à l’utilisateur la possibilité de choisir visuellement dans une palette les widgets nécessaires à son
application, de les organiser et de spécifier leurs caractéristiques à travers des boîtes de dialogue pour
construire progressivement son interface graphique.
On peut ainsi déterminer facilement l’arborescence de widgets à utiliser pour obtenir une interface satisfaisant le cahier des charges. L’outil Glade produit une description XML de cette arborescence qui est
directement exploitable par Gtk, mais il est cependant vivement conseillé de construire l’interface par programmation à l’aide d’appels à la bibliothèque Gtk pour créer l’arborescence de widgets déterminée avec
Glade.
TÉLÉCOM SudParis — INF — Département Informatique — Mars 2014 — Télécom SudParis — 1ère année 12
Développement d’applications graphiques
'
2 Introduction à Gtk
$
2.1 Aperçu de la hiérarchie de widgets Gtk
# 12
GtkWidget
+GtkMisc
| +GtkLabel
| ‘GtkImage
+GtkContainer
| +GtkBin
| | +GtkButton
| | +GtkWindow
| | | ‘GtkDialog
| | +GtkScrolledWindow
| | ‘GtkViewport
| +GtkBox
| | ‘GtkButtonBox
| ‘GtkPaned
+GtkCalendar
&
%
Les types de widgets Gtk sont organisés en une hiérarchie d’héritage dont la racine est la classe GtkWidget
(à noter que la racine de l’arborescence complète est en fait la classe GObject dont une des descendantes est
la classe GtkObject, elle-même classe mère de GtkWidget).
Chaque type de widget dispose des caractéristiques de tous ses ancêtres dans la hiérarchie, et les primitives
d’une classe peuvent être appliquées aux widgets de toutes les classes descendantes. Un jeu de macros permet
de considérer temporairement un widget comme élément d’une classe ancêtre, comme on le voit par exemple
dans le slide 2.3 avec la macro GTK_CONTAINER appliquée à une variable de type GtkWindow.
Chaque classe dispose d’une primitive de création de widget (e.g. gtk_window_new(), gtk_label_new(),
etc) et d’un ensemble de primitives correspondant aux spécificités de la classe.
Gtk distingue deux types de conteneurs : ceux de la classe GtkBin et de ses sous-classes (en particulier
GtkWindow), qui ne pouvent avoir qu’un seul widget enfant, et ceux des autres sous-classes de GtkContainer
(comme par exemple GtkBox ou GtkTable), qui peuvent avoir plusieurs widget enfants et permettent de gérer
la taille et la position relative des différents widget enfants.
Pour avoir un aperçu des widgets Gtk, le plus simple est de lancer l’outil Glade. Les widgets sont présentés
dans une palette semblable à celle de la partie droite du slide, et il suffit de positionner le curseur de souris
sur un widget pour obtenir son nom dans une pop up.
Pour avoir un aperçu de la programmation Gtk, on peut utiliser la commande gtk-demo qui regroupe un
ensemble de programmes de démonstration.
Quelques documents pour en savoir plus sur Gtk :
Site officiel gtk (http://www.gtk.org/)
Tutoriel gtk (http://library.gnome.org/devel/gtk-tutorial/)
Site gtkFr (http://www.gtk-fr.org/wakka.php?wiki=PageAccueil)
TÉLÉCOM SudParis — INF — Département Informatique — Mars 2014 — Télécom SudParis — 1ère année 13
Développement d’applications graphiques
'
2 Introduction à Gtk
$
2.2 Un exemple simple d’interface
Présentation :
Une fenêtre principale : widget de la classe GtkWindow
Une zone comportant un message : widget de la classe GtkLabel
# 13
Comportement :
Un clic sur l’icone de fermeture de la fenêtre (événement delete-event)
fait quitter l’application
&
%
Cette interface simplissime va néanmoins permettre d’illustrer les principaux concepts de la programmation avec Gtk : initialisation de la bibliothèque, création d’une fenêtre principale, enregistrement d’une
fonction de rappel (callback), création d’un widget fils, affichage de l’interface, boucle de gestion des événements.
Elle illustre également la différence entre widget conteneur et simple widget.
TÉLÉCOM SudParis — INF — Département Informatique — Mars 2014 — Télécom SudParis — 1ère année 14
Développement d’applications graphiques
'
2 Introduction à Gtk
$
2.3 Programme Gtk en C pour cette interface
# 14
#include <gtk/gtk.h>
void sortie(GtkWidget *widget, gpointer data) {
gtk_main_quit();
}
int main( int argc, char *argv[] ) {
GtkWidget *fenetre, *label;
gtk_init( &argc, &argv );
fenetre = gtk_window_new( GTK_WINDOW_TOPLEVEL );
// création
gtk_window_set_default_size( GTK_WINDOW(fenetre), 200, 100);
g_signal_connect( G_OBJECT(fenetre), "delete_event", \
G_CALLBACK(sortie), NULL);
// enregistrement
label = gtk_label_new( "Hello World" );
gtk_container_add( GTK_CONTAINER(fenetre), label);
gtk_widget_show_all( fenetre );
// affichage
gtk_main();
// boucle de gestion des evenements
return 0;
}
&
%
Un programme Gtk est constitué de la définition d’un ensemble de fonctions de rappel (callbacks) et d’une
fonction principale reprenant la structure type d’une application graphique avec la fonction gtk_main() pour
la boucle de gestion des événements. La fenêtre principale est désignée par GTK_WINDOW_TOPLEVEL
et le mapping d’un widget à l’écran est assuré par la fonction gtk_widget_show().
Le prototype d’une fonction de rappel est toujours le même :
void myCallback(GtkWidget *widget, gpointer data)
L’enregistrement de l’association à un événement se fait au moyen de la fonction g_signal_connect() qui
prend en argument le widget concerné, l’événement considéré, la fonction de rappel et un pointeur sur une
donnée utilisateur éventuelle (NULL si c’est inutile). Lorsque l’événement intervient, la fonction de rappel est
appelée et deux informations lui sont transmises lors de cet appel et sont donc utilisables dans le corps de la
fonction : le pointeur sur le widget, et le pointeur sur la donnée utilisateur référencé lors de l’enregistrement
de l’association. Il est à remarquer que le nom de la fonction d’enregistrement est bien g_signal_connect()
(et non gtk_signal_connect() qui correspond à une fonction obsolète).
La programmation Gtk demande de spécifier dans le détail les attributs des widgets constituant l’interface,
donc de bien maîtriser la hiérarchie des widgets.
Il existe un certain nombre d’outils pour faciliter la construction d’interfaces graphiques, comme Glade
par exemple.
TÉLÉCOM SudParis — INF — Département Informatique — Mars 2014 — Télécom SudParis — 1ère année 15
Développement d’applications graphiques
'
2 Introduction à Gtk
$
2.4 Compilation d’une application Gtk en C
GTK est un environnement complet et relativement complexe
Plus de 20 bibliothèques
Une dizaine de chemins d’accès pour les fichiers d’entête
# 15
pkg-config pour la génération automatisée des options de compilation
pour la compilation séparée
I ‘pkg-config --cflags gtk+-3.0‘
pour l’édition de liens
I ‘pkg-config --libs gtk+-3.0‘
Compilation + édition des liens, de l’exemple
gcc -Wall hello-gtk.c -o hello-gtk ‘pkg-config --cflags --libs
gtk+-3.0‘
&
%
L’utilisation de nombreuses bibliothèques impose l’inclusion de fichiers d’entête nombreux et dispersés dans l’arborescence de fichiers. Pour faciliter la compilation, il existe heureusement la commande
pkg-config. pkg-config détermine les informations nécessaires sur les bibliothèques installées sur le système
et permet de préparer les lignes de commande appropriées, l’utilisateur n’ayant à écrire qu’une commande
générique.
Dans la commande gcc ci-dessus, nous utilisons le résultat de pkg-config (c.f. l’utilisation de ‘ ‘ dans
le shell). L’option --cflags permet d’obtenir les options de compilation pour les répertoires des fichiers
d’entête (génération des options -I), et l’option --libs les librairies (génération des options -l).
Exemple de résultat de la commande pkg-config :
$ pkg-config --cflags --libs gtk+-3.0
-pthread -I/usr/include/gtk-3.0 -I/usr/include/atk-1.0 -I/usr/include/at-spi2-atk/2.0
-I/usr/include/pango-1.0 -I/usr/include/gio-unix-2.0/ -I/usr/include/cairo
-I/usr/include/gdk-pixbuf-2.0 -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include
-I/usr/include/harfbuzz -I/usr/include/freetype2 -I/usr/include/pixman-1
-I/usr/include/libpng15 -I/usr/include/libdrm -lgtk-3 -lgdk-3 -latk-1.0 -lgio-2.0
-lpangocairo-1.0 -lgdk_pixbuf-2.0 -lcairo-gobject -lpango-1.0 -lcairo -lgobject-2.0
-lglib-2.0
Sur cet exemple, nous obtenons finalement la commande de compilation suivante :
$ gcc -Wall hello-gtk.c -o hello-gtk -pthread -I/usr/include/gtk-3.0
-I/usr/include/atk-1.0 -I/usr/include/at-spi2-atk/2.0 -I/usr/include/pango-1.0
-I/usr/include/gio-unix-2.0/ -I/usr/include/cairo -I/usr/include/gdk-pixbuf-2.0
-I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -I/usr/include/harfbuzz
-I/usr/include/freetype2 -I/usr/include/pixman-1 -I/usr/include/libpng15
-I/usr/include/libdrm -lgtk-3 -lgdk-3 -latk-1.0 -lgio-2.0 -lpangocairo-1.0
-lgdk_pixbuf-2.0 -lcairo-gobject -lpango-1.0 -lcairo -lgobject-2.0 -lglib-2.0
TÉLÉCOM SudParis — INF — Département Informatique — Mars 2014 — Télécom SudParis — 1ère année 16
Développement d’applications graphiques
'
2 Introduction à Gtk
$
2.5 Concepteur d’interface Glade
Environnement de création d’interfaces graphiques basé sur la bibliothèque Gtk
évite de connaître les mécanismes internes de la bibliothèque graphique
permet d’obtenir rapidement des maquettes
décrit les interfaces graphiques dans des fichiers XML portables
ne donne certes pas directement accès à toute la souplesse de Gtk
mais autorise des solutions mixtes (Glade + programmation Gtk)
# 16
Organisation type du développement d’une application avec Glade
production d’un fichier XML avec l’outil Glade
I conception interactive de l’interface graphique et sauvegarde de sa description
écriture de la fonction principale avec la structure type
I parsing du fichier XML : gtk_builder_add_from_file
I récupération de pointeurs sur des widgets : gtk_builder_get_object
I boucle Gtk habituelle de gestion des événements : gtk_main
écriture usuelle des fonctions de rappel avec Gtk
I affichage/masquage de widget : gtk_widget_show/gtk_widget_hide
&
%
La construction d’une interface graphique par programmation en Gtk peut paraître laborieuse puisqu’il
faut créer explicitement chaque widget, fixer ses propriétés et l’ajouter à son widget parent. L’intérêt de
Glade est que le même résultat peut être obtenu en deux lignes de programme : ouverture d’un fichier
XML et parsing du contenu du fichier. Le format du fichier XML étant défini au niveau de Gtk, cela
donne la possibilité d’utiliser d’autres outils que Glade pour concevoir une telle interface graphique pour un
programme Gtk.
Afin de pouvoir récupérer des pointeurs sur les widgets qu’il a besoin de manipuler dans son programme
(par exemple dans la définition des fonctions de rappel), le développeur doit simplement connaître les noms
attribués à ces widgets par le concepteur de l’interface.
Mais attention : l’outil Glade n’est pas adapté à la construction d’interfaces graphiques complexes, comme
par exemple lorsque de nombreux éléments similaires sont nécessaires (éléments de jeux, par exemple). Dans
ce cas, il permet juste d’obtenir rapidement une maquette réduite sans avoir besoin d’une connaissance
approfondie de l’API Gtk. Il est donc judicieux de l’utiliser pour faire une première ébauche d’interface en
effectuant un choix visuel parmi les widgets disponibles dans Glade. Après validation de la maquette, une
programmation directe en Gtk peut bien entendu permettre de produire la même interface ; mais comme
elle apporte davantage de contrôle et de possibilités au programmeur à travers les structures de contrôle
uselles (conditionnelles, boucles...), une programmation entièrement en Gtk permet surtout de produire
confortablement une interface plus ambitieuse.
Historiquement, les premières versions de Glade généraient automatiquement un ensemble de fichiers
sources C comportant les appels aux primitives Gtk nécessaires pour produire l’interface telle que définie
dans l’outil. L’approche Glade est devenue générique depuis la version 3 et n’impose plus un développement
en C : l’interface créée est sauvegardée sous la forme d’un fichier au format XML, exploitable à partir de très
nombreux langages de programmation grâce à une API intégrée à la bibliothèque Gtk (disponible depuis la
version 3.6 de Glade en lieu et place de la bibliothèque libglade utilisée précédemment). Cette API repose
sur un objet Gtk auxiliaire de la classe GtkBuilder capable de parser un fichier XML.
Une interface graphique construite avec Glade est donc complétement portable.
Quelques documents pour en savoir plus sur Glade :
Site officiel de glade (http://glade.gnome.org)
Programmation Gtk avec glade (http://wingtk.sourceforge.net/ishan/glade.html)
Petit tutoriel sur glade (http://franckh.developpez.com/tutoriels/gtk/gtkbuilder)
TÉLÉCOM SudParis — INF — Département Informatique — Mars 2014 — Télécom SudParis — 1ère année 17
Développement d’applications graphiques
'
2 Introduction à Gtk
$
2.6 Description XML de l’exemple d’interface
# 17
<?xml version="1.0"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<!-- interface-naming-policy project-wide -->
<object class="GtkWindow" id="fenetre">
<property name="default_width">200</property>
<property name="default_height">100</property>
<signal name="delete_event" handler="gtk_main_quit"/>
<child>
<object class="GtkLabel" id="label">
<property name="visible">True</property>
<property name="label" translatable="yes">Hello world</property>
</object>
</child>
</object>
</interface>
&
%
L’interface est constituée de deux widgets :
• un widget de la classe GtkWindow correspondant à la fenêtre principale, et
• un widget fils de la classe GtkLabel dont la propriété label a pour valeur la chaîne de caractères “Hello
World”.
Chaque widget a un attribut chaîne de caractères nommé id qui permet de le désigner dans le programme
exploitant cette interface.
TÉLÉCOM SudParis — INF — Département Informatique — Mars 2014 — Télécom SudParis — 1ère année 18
Développement d’applications graphiques
'
2 Introduction à Gtk
$
2.7 Utilisation en C d’une description XML d’interface
# 18
#include <gtk/gtk.h>
int main( int argc, char *argv[] ) {
GtkBuilder *monBuilder;
GtkWidget *maFenetre;
gtk_init( &argc, &argv );
monBuilder = gtk_builder_new();
gtk_builder_add_from_file( monBuilder, "hello.glade", NULL);
gtk_builder_connect_signals( monBuilder, NULL);
maFenetre = GTK_WIDGET(gtk_builder_get_object(monBuilder, "fenetre"));
gtk_widget_show_all (maFenetre);
gtk_main();
return 0;
}
Génération automatisée des options nécessaires
gcc -Wall hello-glade.c -o hello-glade ‘pkg-config --cflags --libs
gtk+-3.0 gmodule-2.0‘
&
%
Le programme exploite, grâce à des appels aux fonctions de l’API GtkBuilder, la description de l’interface
contenue dans le fichier XML produit par l’outil graphique Glade. Il peut comporter également des
appels à des fonctions de la bibliothèque Gtk. L’analyse du fichier XML est réalisée par la fonctionn
gtk_builder_add_from_file() par l’intermédiaire d’un objet de la classe GtkBuilder créé par appel de
la fonction gtk_builder_new().
C’est le nommage des widgets qui établit le lien entre l’interface décrite en XML et leur manipulation
dans le programme. Précisément, la fonction gtk_builder_get_object() retourne un pointeur sur le widget
à partir de son identifiant (ici, “fenetre”) ; à noter l’utilisation de la macro GTK_WIDGET pour retyper
en GtkWidget le GObject retourné par la fonction.
L’argument gmodule de pkg-config permet d’obtenir, lors de l’exécution, une édition des liens dynamique correcte pour l’ensemble des symboles introduits dans la description au format XML et utilisés par
le programme.
TÉLÉCOM SudParis — INF — Département Informatique — Mars 2014 — Télécom SudParis — 1ère année 19
Développement d’applications graphiques
'
$
3 Version graphique de l’application exemple
# 19
3.1
3.2
3.3
3.4
3.5
3.6
3.7
3.8
3.9
Organisation générale de l’application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
Adaptation à réaliser pour gtk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Structure générale de la version graphique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Éléments de l’interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
Interaction pour l’ajout d’un ouvrage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
Interaction graphique pour l’ajout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
Boîte de dialogue Ajout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
Validation de la saisie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
Récupération de la saisie. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .28
&
%
Cette section propose une présentation sommaire d’une version graphique de l’application exemple réalisée
précédemment pour la modalité "terminal".
Partir d’une application en mode terminal pour obtenir une application graphique n’est pas nécessairement une bonne idée et peut s’avérer très coûteux. Dans le cas de l’application exemple choisie, la structure
simple de l’application sous forme d’une boucle saisie/traitement facilite néanmoins l’adaptation. De plus,
l’effet des actions de l’utilisateur au cours d’une session d’utilisation se trouve naturellement matérialisé dans
le contenu du fichier texte data.txt listant les ouvrages ; il n’est donc pas nécessaire d’introduire de variables
à consulter/modifier par les callbacks pour refléter un quelconque état d’avancement dans le déroulement de
l’application. De façon générale, si on a le projet de passer d’une version en mode terminal à une version
graphique, il sera plus facile de réutiliser en disposant d’une multitude de petites fonctions ciblées que d’un
petit nombre de très grosses fonctions.
La version graphique de l’application exemple ré-utilise tous les fichiers source génériques de la version
"terminal" (main.c, menu.c, bibliotheque.c, ouvrage.c et util.c), et s’appuie sur la bibliothèque Gtk pour
l’implantation de l’interaction graphique.
Avec une programmation purement Gtk, l’interface graphique est construite progressivement à l’aide
d’une succession d’appels à des fonctions de création de widgets notamment. Comme l’interface visée ici
est assez basique, l’outil Glade peut être utilisé pour éviter d’entrer dans tous les détails de l’API Gtk et
construire graphiquement l’interface de l’application. La mise en place de l’interface par le programme à
partir de la description XML est alors obtenue par un simple appel de fonction de l’API GtkBuilder.
Des indications complémentaires sont données pour une version purement Gtk, celle-ci étant également
mise à disposition à titre d’exemple.
TÉLÉCOM SudParis — INF — Département Informatique — Mars 2014 — Télécom SudParis — 1ère année 20
Développement d’applications graphiques
'
3 Version graphique de l’application exemple
$
3.1 Organisation générale de l’application
bibliotheque−term.c
ouvrage.c
afficherCollectionOuvrages
ouvrageToString
afficher
afficherBibliotheque
menu−term.c
init
afficherOuvrage
choixAfficher
bibliotheque.c
saisirOuvrage
quit
ouvrage−term.c
insererDansFichier
choixAjouter
ajouterOuvrage
# 20
menu
choixRechercher
saisirAuteur
rechercherLesOuvragesDeAuteur
main
rechercherOuvrageDansCollection
choix Supprimer
menu.c
insererOuvrageDansCollection
collectionOuvrages.c
supprimerLesOouvragesDeAuteur
suprimerBibliotheque
supprimerOuvrageCollection
viderCollectionOuvrages
ecritureFichier
nouvelleBibliotheque
lectureFichier
purge
fichierOuvrages.c
&
%
Le découpage en modules qui a été adopté pour la version en mode "terminal" est mis en évidence sur le
graphe d’appel :
• main, qui correspond à la fonction principale, avec le point d’entrée de l’application (initialisation,
affichage d’un menu),
• menu, dédié à l’interaction utilisateur (affichage/saisie d’informations, boucle d’interaction avec
l’utilisateur),
• bibliotheque, dédié à la gestion des collections d’ouvrages,
• ouvrage, dédié à la gestion des ouvrages,
• util, fonctionnalités de plus bas niveau liées au stockage de l’information (sur disque et en mémoire).
L’implantation des modules menu, ouvrage et bibliotheque amène à distinguer les opérations spécifiques à
chaque modalité d’utilisation. Pour chacun de ces modules, les fonctions sont réparties dans deux fichiers
sources : l’un pour la partie générique, constituée des fonctions du module dont l’implantation est totalement
indépendante des modalités d’interaction avec l’utilisateur, l’autre pour la partie spécifique à chaque modalité
d’interaction ("terminal" ou graphique).
Les noms des fichiers de la version en mode "terminal" comportant les fonctions spécifiques sont suffixés
par -term. Les fichiers correspondants de la version graphique seront dans la suite suffixés par -gtk
s’il n’utilisent que Gtk ou par -glade s’ils reposent également sur l’outil Glade. Ainsi, il y a un fichier
bibliotheque-gtk.c utilisé à la fois par la version graphique avec Glade et par la version graphique purement
Gtk, mais les deux autres fichiers spécifiques sont distincts pour les deux versions graphiques : menu-glade.c
et ouvrage-glade.c d’une part, ouvrage-gtk.c et menu-gtk.c d’autre part.
TÉLÉCOM SudParis — INF — Département Informatique — Mars 2014 — Télécom SudParis — 1ère année 21
Développement d’applications graphiques
'
3 Version graphique de l’application exemple
$
3.2 Adaptation à réaliser pour gtk
Entrées-sortie réalisées dans les différents modules :
# 21
Fichier bibliotheque-gtk.c
afficherCollectionOuvrages() : printf()
⇒ gtk_text_buffer_insert*()
Fichier ouvrage-*.c
afficherOuvrage(Ouvrage), afficherAuteur(Auteur) : printf()
⇒ gtk_text_buffer_insert*()
SaisieOuvrage(), SaisieAuteur() : fgets(), fscanf()
⇒ gtk_entry_get_text() appliqué au widget zone de saisie
Fichier menu-*.c
affiche() : printf()
⇒ gtk_text_buffer_insert*()
menu (Bibliotheque) : printf(), scanf()
⇒ gtk_text_buffer_insert*(), gtk_entry_get_text()
Initialisation de la bibliothèque Gtk avec gtk_init() : fonction init() dans menu-*.c
&
%
Les modalités d’entrée-sortie doivent être adaptées en s’appuyant sur les fonctionnalités de Gtk.
L’interface comporte une zone d’affichage dans la fenêtre principale, sous la forme d’un widget de la classe
GtkTextView. Tous les affichages effectués par des appels à printf() dans la version terminal seront réalisés
dans cette zone d’affichage au moyen d’appel à des primitives de la famille gtk_text_buffer_insert*().
Les saisies seront réalisées quant à elle par l’intermédiaire d’appels à gtk_entry_get_text() appliqués aux
widgets zone de saisie de la classe GtkEntry contenus dans les fenêtres de dialogue.
TÉLÉCOM SudParis — INF — Département Informatique — Mars 2014 — Télécom SudParis — 1ère année 22
Développement d’applications graphiques
'
3 Version graphique de l’application exemple
$
3.3 Structure générale de la version graphique
Fichier menu-glade.c :
init()
initialisation de l’usage de la bibliothèque graphique
⇒ gtk_init()
# 22
menu()
mise en place des éléments de l’interface graphique
⇒ gtk_builder_new(), gtk_builder_add_from_file()
association d’actions aux événements pertinents sur certains éléments
⇒ gtk_builder_connect_signals()
récupération de pointeurs sur les boîtes de dialogues et zones de saisie
⇒ gtk_builder_get_object()
affichage de l’interface
⇒ gtk_widget_show()
boucle de gestion des événements
⇒ gtk_main()
&
%
L’essentiel de la structure de la version graphique de l’application exemple se retrouve dans les fonctions
définies dans le fichier menu-*.c (menu-glade.c ou menu-gtk.c) :
• l’initialisation de la bibliothèque graphique est réalisée par la fonction init(), appelée par la fonction
main() du fichier main.c
• la mise en place des éléments de l’interface, les associations "événement-action" et l’affichage de
l’interface sont réalisés par la fonction menu() (qui comporte également la boucle de gestion des événements), elle aussi appelée par la fonction main().
La définition, de ces deux fonctions s’appuie sur l’API Gtk ; à noter que pour l’initialisation, la fonction
gtk_init_check() qui évite une sortie brutale du programme en cas d’échec de l’initialisation peut être utilisée
à la place de gtk_init().
Le slide précise les quelques fonctions utlisées dans la version Glade, alors que la version purement Gtk
fait appel à davantage de fonctions, notamment pour la création des widgets des différentes classes.
La version Glade doit bien entendu utiliser la fonction gtk_builder_get_object(), qui retourne un
pointeur sur un GObject à partir de son identifiant, pour faire le lien entre les widgets définis dans le fichier
XML décrivant l’interface et ceux manipulés dans le programme C.
TÉLÉCOM SudParis — INF — Département Informatique — Mars 2014 — Télécom SudParis — 1ère année 23
Développement d’applications graphiques
'
3 Version graphique de l’application exemple
$
3.4 Éléments de l’interface graphique
# 23
&
%
L’interface graphique comporte une fenêtre principale avec des boutons permettant d’activer les fonctionnalités. Certaines fonctionnalités, comme par exemple la fonctionnalité d’ajout d’un ouvrage, vont entraîner
l’affichage d’une boîte de dialogue pour la saisie d’informations complémentaires.
Chaque élément de l’interface doit être explicitement créé et mis en place si l’on n’utilise pas Glade,
alors que sinon le chargement de l’interface décrite au format XML dans le fichier bibliotheque.glade met
directement tous les éléments en place.
Les événements d’intérêt pour l’application vont provoquer l’exécution des fonctions de rappel (ou callbacks) associées.
Toutes les fonctions de rappel sont définies dans le fichier menu-*.c, et leurs identifiants ont le suffixe
Call pour pouvoir mieux les distinguer des fonctions ordinaires.
TÉLÉCOM SudParis — INF — Département Informatique — Mars 2014 — Télécom SudParis — 1ère année 24
Développement d’applications graphiques
'
3 Version graphique de l’application exemple
$
3.5 Interaction pour l’ajout d’un ouvrage
bibliotheque−term.c
ouvrage.c
afficherCollectionOuvrages
ouvrageToString
afficher
afficherBibliotheque
menu−term.c
init
afficherOuvrage
choixAfficher
bibliotheque.c
saisirOuvrage
quit
ouvrage−term.c
insererDansFichier
choixAjouter
ajouterOuvrage
# 24
menu
choixRechercher
saisirAuteur
rechercherLesOuvragesDeAuteur
main
rechercherOuvrageDansCollection
choix Supprimer
menu.c
insererOuvrageDansCollection
collectionOuvrages.c
supprimerLesOouvragesDeAuteur
suprimerBibliotheque
supprimerOuvrageCollection
viderCollectionOuvrages
ecritureFichier
nouvelleBibliotheque
lectureFichier
purge
fichierOuvrages.c
&
%
A titre d’exemple, on focalise ici sur le cas d’utilisation de l’ajout d’un ouvrage, illustré sur le graphe
d’appel de la version terminal ci-dessus. Ce choix de l’utilisateur dans la fonction menu() produit un appel
de la fonction générique choixAjouter() du module menu (fichier menu.c). Cette fonction générique choixAjouter() appelle alors la fonction spécifique saisirOuvrage() du module ouvrage (fichier ouvrage-term.c),
puis la fonction générique ajouterOuvrage() du module bibliotheque (fichier bibliotheque.c) qui elle-même
appelle les fonctions insererOuvrageDansCollection() et insererDansFichier() du module util. On note ici
que la fonction saisirOuvrage() fait partie de la partie spécifique du module ouvrage alors que la fonction
ajouterOuvrage() est une fonction générique du module bibliotheque.
L’approche événementielle de gtk s’appuie sur le mécanisme des fonctions de rappel, et l’interation se
traduit donc par un graphe d’appel qui les fait intervenir explicitement (cf slide suivant).
TÉLÉCOM SudParis — INF — Département Informatique — Mars 2014 — Télécom SudParis — 1ère année 25
Développement d’applications graphiques
'
3 Version graphique de l’application exemple
$
3.6 Interaction graphique pour l’ajout
bibliotheque−term.c
ouvrage.c
afficherCollectionOuvrages
ouvrageToString
afficherBibliotheque
afficherOuvrage
afficher
choixAfficher
bibliotheque.c
saisirOuvrage
menu−*.c
ouvrage−*.c
insererDansFichier
choixAjouter
ajouterOuvrage
init
# 25
choixRechercher
menu
saisirAuteur
rechercherLesOuvragesDeAuteur
rechercherOuvrageDansCollection
choix Supprimer
Callbacks
menu.c
insererOuvrageDansCollection
collectionOuvrages.c
supprimerLesOouvragesDeAuteur
supprimerOuvrageCollection
ajouterOuvrageCall
suprimerBibliotheque
afficherSaisieAjoutCall
... quitCall
viderCollectionOuvrages
ecritureFichier
nouvelleBibliotheque
lectureFichier
purge
main
clic sur Valid
clic sur Ajout
... clic sur Quit
fichierOuvrages.c
Affichage boite de dialogue
&
%
Avec la version graphique de l’application, l’activation de la fonctionnalité d’ajout d’un ouvrage se déroule
en deux temps :
• clic de l’utilisateur sur le bouton Ajout de la fenêtre principale, action qui provoque l’ouverture d’une
boîte de dialogue permettant à l’utilisateur de saisir les informations nécessaires (par l’intermédiaire
de l’exécution de la fonction de rappel afficherSaisieAjoutCall()),
• clic de l’utilisateur sur le bouton de validation de la boîte de dialogue, action qui déclenche l’ajout
effectif (dans la collection et le fichier) d’un ouvrage dont les attributs correspondent aux informations
saisies par l’utilisateur dans la boîte de dialogue (par l’intermédiaire de l’exécution de la fonction de
rappel ajouterOuvrageCall()).
Ces fonctions de rappel, définies comme toutes les autres dans le fichier menu-*.c, doivent être au préalable associées aux événements concernés. Pour la version Glade, cette association est mise en place lors
du démarrage de l’application par la fonction gtk_builder_connect_signals(), car tous les éléments de
l’interface sont présents dès le chargement de l’interface, y compris les différentes boîtes de dialogue. Les
choses sont donc un peu plus complexes pour la version purement Gtk puisque les boîtes de dialogue doivent
être créées à la volée et les associations événement-callback mises en place à ce moment-là.
Les slides suivants détaillent les trois fonctions spécifiques à cette version graphique et impliquées dans
l’interaction d’ajout d’un ouvrage : afficherSaisieAjoutCall()), ajouterOuvrageCall() et saisirOuvrage().
Nota : on a pris soin de nommer toutes les fonctions de rappel par des identifiants se terminant par Call
pour faciliter la lecture.
TÉLÉCOM SudParis — INF — Département Informatique — Mars 2014 — Télécom SudParis — 1ère année 26
Développement d’applications graphiques
'
3 Version graphique de l’application exemple
$
3.7 Affichage de la boîte de dialogue Ajout
bibliotheque.glade :
23
24
28
136
# 26
<object class="GtkButton" id="button1">
<property name="label" translatable="yes">Ajout</property>
<signal name="clicked" handler="afficherSaisieAjoutCall"/>
<object class="GtkDialog" id="Ajout">
menu-glade.c :
dialogAjout = GTK_WIDGET(gtk_builder_get_object(builder,"Ajout"));
void afficherSaisieAjoutCall( GtkWidget *widget, gpointer data) {
gtk_grab_add(dialogAjout); // prise de la capture par le widget
gtk_entry_set_text(titreEntry, "");
// vidage des differents
gtk_entry_set_text(auteurEntry, ""); // champs de saisie de texte
gtk_widget_show(dialogAjout);
// affichage du widget
}
&
%
Les trois premières lignes extraites du fichier bibliotheque.glade montrent comment est défini le bouton
“Ajout” (GtkButton) de la fenêtre principale de l’interface, et comment est établi le lien avec la fonction de
rappel afficherSaisieAjoutCall() associée au clic sur ce bouton. La quatrième ligne montre le début de la
définition du widget boîte de dialogue Ajout, avec l’identifiant “Ajout” qui est utilisé dans le programme C
pour la récupération d’un pointeur dialogAjout sur le widget, comme on le voit en dessous.
Le pointeur dialogAjout est une variable globale au fichier menu-glade.c qui initialisée dans la fonction
menu() lors de la mise en place de l’interface. Il est ensuite utilisé par la fonction afficherSaisieAjoutCall()
qui prépare le widget pour l’interaction avec l’utilisateur.
Comme pour tous les éléments de l’interface graphique, la représentation interne de la boîte
de dialogue Ajout est présente en mémoire après l’appel, par la fonction menu(), de la fonction
gtk_builder_add_from_file() qui exploite la description XML de l’interface pour créer sa représentation interne. La fonction de rappel afficherSaisieAjoutCall() associée au clic sur le bouton “Ajout” ne fait
simplement qu’afficher la fenêtre de dialogue (gtk_widget_show()), avec des champs de saisie vides (utilisation de la fonction “accesseur” en écriture gtk_entry_set_text() avec une chaîne vide), et lui attribuer
la capture (gtk_grab_add()). A noter que les variables globales titreEntry et auteurEntry sont également
utilisées dans le fichier ouvrage-glade.c
La boîte de dialogue comporte un bouton de validation pour lequel le clic est associé à la fonction de
rappel ajouterOuvrageCall() décrite plus loin.
TÉLÉCOM SudParis — INF — Département Informatique — Mars 2014 — Télécom SudParis — 1ère année 27
Développement d’applications graphiques
'
3 Version graphique de l’application exemple
$
3.8 Validation des informations saisies
bibliotheque.glade :
# 27
165
193
221
249
250
255
<object class="GtkEntry" id="titreEntry">
<object class="GtkEntry" id="auteurEntry">
<object class="GtkSpinButton" id="anneeSpin">
<object class="GtkButton" id="button6">
<property name="label">gtk-ok</property>
<signal name="clicked" handler="ajouterOuvrageCall"/>
menu-glade.c :
void ajouterOuvrageCall( GtkWidget *widget, gpointer data) {
GtkWidget * dialogBox;
Bibliotheque bibliotheque = (Bibliotheque) data;
dialogBox = gtk_widget_get_toplevel(widget);
choixAjouter(bibliotheque);
gtk_widget_hide(dialogBox);
// masquage du widget
gtk_grab_remove(dialogBox);
// relâchement de la capture
}
&
%
Les lignes extraites du fichier bibliotheque.glade montrent une partie de la définition des widgets correspondant à la boîte de dialogue “Ajout” : les deux zones de saisie (GtkEntry), le bouton de sélection d’une
valeur dans un intervalle de valeurs (GtkSpinButton) et le bouton de validation (GtkButton) ; elles montrent
également l’association de la fonction de rappel ajouterOuvrageCall() au clic sur ce dernier bouton.
Ainsi, un clic sur le bouton de validation déclenche l’exécution de la callback ajouterOuvrageCall() associée
à cet événement. Cette fonction récupère par gtk_widget_get_toplevel() un pointeur sur le widget boîte
de dialogue “Ajout” (qui constitue le toplevel widget pour le bouton de validation), et appelle la fonction
générique choixAjouter(), définie dans le fichier menu.c ; au retour de cet appel, ajouterOuvrageCall() masque
la boîte de dialogue (gtk_widget_hide()) et relache la capture(gtk_grab_remove()). On peut noter que,
dans la version purement Gtk de l’application, le code de cette callback est plus court car elle se contente de
détruire la boîte de dialogue, celle-ci étant recréée lors de chaque usage; en revanche, le code déroulé par la
callback afficherSaisieAjoutCall() est plus conséquent puisque celle-ci doit construire une boîte de dialogue,
ce qui est fait à travers un appel à la fonction générique afficherSaisieOuvrage().
Comme il apparaît sur le slide 3.6, la fonction choixAjouter() appelée par la callback ajouterOuvrageCall()
appelle elle-même la fonction saisirOuvrage(), définie dans le fichier ouvrage-glade.c, qui ne fait quant à elle
qu’exploiter les informations disponibles dans les champs de saisie de la boîte de dialogue pour construire
l’ouvrage nécessaire au travail de ajouterOuvrage().
On peut noter l’utilisation du second paramètre de la fonction de rappel ajouterOuvrageCall() pour transmettre la donnée utilisateur bibliotheque, nécessaire pour l’appel de la fonction choixAjouter(). Ce paramètre
est mis à disposition de la callback par le mécanisme de rappel car il a été transmis par la fonction menu()
(menu-glade.c) lors de l’appel de fonction gtk_builder_connect_signals(builder, bibliotheque) qui
effectue la connection des signaux présents dans la description de l’interface lors de sa mise en place.
Dans notre programme, toutes les fonctions de rappel utilisent cette même variable bibliotheque, initialisée
lors du démarrage du programme (lecture du fichier) et mise à jour tout au long de son utilisation. Il
est à noter que si ces fonctions nécessitaient plusieurs informations (stockées dans différentes variables), il
faudrait créer une structure de données qui regrouperait toutes ces informations. On pourrait ainsi passer
en paramètre à gtk_builder_connect_signals() un pointeur sur cette structure unique pour permettre à
chaque fonction rappel de récupérer les informations qui lui sont utiles.
TÉLÉCOM SudParis — INF — Département Informatique — Mars 2014 — Télécom SudParis — 1ère année 28
Développement d’applications graphiques
'
3 Version graphique de l’application exemple
$
3.9 Récupération des informations saisies
ouvrage-*.c :
# 28
Ouvrage saisirOuvrage() {
Ouvrage ouvrage= {"sans titre","sans auteur",0};
char tampon[TAILLE_MAX_TITRE+1];
int annee;
if ((titreEntry!=NULL) && (gtk_entry_get_text(titreEntry)!=NULL)){
strcpy( tampon, gtk_entry_get_text(titreEntry));
if (strlen(tampon) > 0) strcpy( ouvrage.titre, tampon); }
if ((auteurEntry!=NULL) && (gtk_entry_get_text(auteurEntry)!=NULL)){
strcpy( tampon, gtk_entry_get_text(auteurEntry));
if (strlen(tampon) > 0) strcpy( ouvrage.nomAuteur, tampon); }
annee = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(anneeSpin));
ouvrage.anneeEdition = annee;
return ouvrage;
}
&
%
La récupération des informations saisies par l’utilisateur dans la boîte de dialogue est réalisée par la
fonction saisirOuvrage(). Cette fonction, définie à l’identique pour les deux versions graphiques dans le fichier
ouvrage-*.c et appelée par la fonction choixAjouter(), n’est pas une callback mais une fonction ordinaire.
Elle applique des fonctions “accesseurs” en lecture (*_get_*()) aux widgets de saisie pour récupérer les
informations.
La bibliothèque Gtk propose en effet, pour la plupart des attributs des objets, des fonctions jouant le rôle
d’accesseurs en lecture (fonctions *_get_*()) ou en écriture (fonctions *_set_*()) : un accesseur en lecture
permet de consulter la valeur de l’attribut, un accesseur en écriture permet d’affecter sa valeur.
TÉLÉCOM SudParis — INF — Département Informatique — Mars 2014 — Télécom SudParis — 1ère année 29