LibGlade: vos interfaces en GTK+ sans code !

Pascal Terjan

Si vous utilisez GTK+ pour réaliser vos interfaces, vous connaissez sans doute déjà Glade1.

Ce logiciel permet de concevoir très rapidement vos interfaces. Vous choisissez à l'aide d'une palette les éléments (widgets) à y mettre puis, pour chaque élément, vous pouvez définir ses options (taille, couleur, contenu, s'il est modifiable par l'utilisateur...). La figure 1 montre l'interface principale de Glade et les options associées à la fenêtre principale de l'interface réalisée.


Figure 1: Interface de Glade


Vous définissez ensuite les réactions à avoir aux différents événements (clic, pression d'une touche, déplacement, masquage, ...) très simplement, en associant un nom de fonction à chaque signal vous intéressant (chaque widget peut émettre un certain nombre de signaux prédéfinis correspondants aux événement qu'il peut subir). Cette fonction sera automatiquement appelée lorsque l'événement se produira. La figure 2 représente la fenêtre permettant de réaliser cette association.


Figure 2: Fenêtre de choix du traitement des signaux


Son utilisation la plus courante est ensuite de lui faire générer le code (C, C++, PERL, Ada, ...) correspondant à la création de cette interface. Il y en a pourtant une autre, beaucoup plus intéressante :

Glade stocke la description de l'interface dans un fichier .glade. Ce fichier peut être chargé à l'exécution par la libGlade pour générer l'interface directement. Cet article va présenter rapidement cette utilisation. Mes explications seront principalement basées sur Ruby mais j'indiquerai à la fin l'équivalent dans d'autres langages.

1  Principe

Le fichier .glade est en fait un fichier xml contenant une description de l'interface et les fonctions à appeler pour traiter les différents signaux. La figure 3 montre un exemple très simple.

Une interface est constituée d'un bloc glade-interface avec à l'intérieur un bloc widget par widget de l'interface, simple non ?

Ce widget a une classe (son type, par exemple GtkWindow, GtkButton, ...) et un id (son nom, qui permet d'y accéder par la suite). Il contient un certain nombre de propriétés qui dépendent du type de widget. Dans l'exemple <property name="resizable">True</property> indique par exemple que la fenêtre est redimensionnable par l'utilisateur. On trouve ensuite une balise signal indiquant que l'on veut que la fonction close soit appelée lorsque l'utilisateur veut fermer la fenêtre, cela permet par exemple de terminer l'application.

Lorsqu'un widget en contient d'autres, ici la fenêtre contient un bouton, ceux-ci sont tous simplement placés dans un bloc child à l'intérieur du widget.

<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">

<glade-interface>
<requires lib="gnome"/>

<widget class="GtkWindow" id="window1">
  <property name="visible">True</property>
  <property name="title" translatable="yes">Une Fenêtre</property>
  <property name="type">GTK_WINDOW_TOPLEVEL</property>
  <property name="window_position">GTK_WIN_POS_NONE</property>
  <property name="modal">False</property>
  <property name="default_width">250</property>
  <property name="default_height">150</property>
  <property name="resizable">True</property>
  <signal name="delete_event" handler="close"/>

  <child>
    <widget class="GtkButton" id="button1">
      <property name="visible">True</property>
      <property name="can_focus">True</property>
      <property name="label">gtk-quit</property>
      <property name="use_stock">True</property>
      <property name="relief">GTK_RELIEF_NORMAL</property>
      <signal name="pressed" handler="close"/>
    </widget>
  </child>
</widget>

</glade-interface>

Figure 3: Exemple de fichier .glade


A partir de ce fichier, la bibliothèque libGlade permet très simplement de construire dynamiquement l'interface (ou uniquement une partie de l'interface, par exemple une boite de dialogue, un assistant, ...). Cette approche présente de nombreux avantages : Il est important de noter que le surcoût engendré par l'interprétation du fichier xml est très faible et n'existe de toute façon qu'au moment de la création de l'interface. Une fois l'interface créée, il n'y a plus aucune différence avec celle qui aurait été créée à la main.

2  En pratique

Ruby/LibGlade22 fournit un programme appelé ruby-glade-create-template permettant de générer un squelette de programme Ruby à partir d'un .glade. La figure 4 présente le résultat (légérement modifié) sur l'exemple de la figure 3.

#!/usr/bin/env ruby
require 'libglade2'
class Exemple1
  def initialize(path)
    @glade = GladeXML.new(path) {|handler| method(handler)}
  end
  def close()
    Gtk.main_quit
  end
end

Gtk.init

#Set correct path by yourself.
Exemple1.new("exemple1.glade")
Gtk.main

Figure 4: Exemple de script Ruby généré par ruby-glade-create-template


Une classe est créée, Exemple1, qui est l'application principale. Dans son constructeur, l'interface est créée. On remarque également que la méthode close indiquée dans le .glade à été définie, charge à nous d'y faire ce que l'on souhaite. J'ai ici appelé la méthode main_quit de Gtk qui permet de mettre fin à la boucle de Gtk, et donc de quitter l'application vu que l'on ne lance rien ensuite. Le script initialise ensuite GTK, crée une instance de l'application et lance la boucle principale de GTK.

La ligne qui nous intéresse est la suivante :
@glade = GladeXML.new(path) {|handler| method(handler)}

La création de l'interface en utilisant la libGlade consiste comme vous le voyez à créer un objet de type GladeXML. Cet objet vous permettra en particulier d'accéder aux éléments de l'interface par la suite. Détaillons un peu cette création et en particulier le bloc qui peut vous sembler étrange, surtout si vous ne connaissez pas Ruby.

Le constructeur prend 2 paramètres : le chemin du fichier .glade et un bloc de code permettant de déterminer la méthode à appeler pour chaque fonction indiquée dans le .glade. Ce bloc est appelé par le constructeur avec un nom de fonction, et renvoie une méthode qui sera associée au signal. La version présentée est la plus couramment utilisée : pour chaque nom, utiliser la méthode ayant ce nom.

Une exécution du code de la figure 4 affiche la fenêtre que vous pouvez voir sur la figure 5 et lorsque que vous cliquez sur le bouton ou fermez la fenêtre en utilisant la croix, l'application se termine.


Figure 5: Résultat du script de la figure 4


3  Accès aux widgets

Les widgets ayant été créés automatiquement, vous n'avez pas de variables permettant d'y accéder, par exemple pour en changer le contenu ou modifier leur état. Ne vous inquiétez pas, c'est très facile d'y accéder grâce à la méthode get_widget qui renvoie le widget dont on lui fournit le nom. En Ruby, cette méthode a un alias [] qui permet joliment d'y accéder comme si l'interface était un Hash (tableau associatif).

Par exemple, la ligne suivante permet de modifier le titre de la fenêtre principale :
@glade['window1'].title="plop"

4  Autres langages

La création d'interface se fait aussi simplement dans les autres langages supportant la libGlade :

5  Conclusion

J'espère par cette très brève présentation vous avoir donné envie d'essayer cette bibliothèque très pratique et je vous invite à regarder le tutoriel8 de Laurent Sansonetti et Nikolai Weibull montrant comment réaliser très simplement une application complète en combinant la facilité d'utilisation de Ruby, de la libGlade et des autres bibliothèques GNOME comme GnomeVFS et gstreamer.


1
http://glade.gnome.org
2
http://ruby-gnome2.sourceforge.jp/
3
http://developer.gnome.org/doc/API/2.0/libglade/
4
http://gtk.php.net
5
http://gtk2-perl.sourceforge.net/doc/pod/Gtk2/GladeXML.html
6
http://www.daa.com.au/~james/software/pygtk/
7
http://libre.act-europe.fr/GtkAda/docs/gtkada_ug.html
8
http://ruby-gnome2.sourceforge.jp/hiki.cgi?FOSDEM_2004

This document was translated from LATEX by HEVEA.