summaryrefslogtreecommitdiff
path: root/content/Informatique/2014-02-09-ocaml_gtk.rst
diff options
context:
space:
mode:
Diffstat (limited to 'content/Informatique/2014-02-09-ocaml_gtk.rst')
-rw-r--r--content/Informatique/2014-02-09-ocaml_gtk.rst206
1 files changed, 206 insertions, 0 deletions
diff --git a/content/Informatique/2014-02-09-ocaml_gtk.rst b/content/Informatique/2014-02-09-ocaml_gtk.rst
new file mode 100644
index 0000000..09f1aee
--- /dev/null
+++ b/content/Informatique/2014-02-09-ocaml_gtk.rst
@@ -0,0 +1,206 @@
+.. -*- rst -*-
+.. -*- coding: utf-8 -*-
+
+=======================================
+Trois manière d'utiliser Gtk avec OCaml
+=======================================
+
+:date: 2014-02-09
+:tags: ocaml, gtk
+:summary: |summary|
+:logo: /images/ocaml/camel_75.jpg
+
+.. default-role:: literal
+
+.. figure:: {filename}/images/ocaml/camel_2.jpg
+ :figwidth: 150
+ :figclass: floatleft
+ :alt: Pavement
+
+ Image : `Kevin Botto`_ (creativecommons_)
+
+.. _Kevin Botto: http://www.flickr.com/photos/kevinbotto/3251157974/
+.. _creativecommons: http://creativecommons.org/licenses/by-nd/2.0/deed.fr
+
+|summary|
+
+
+.. |summary| replace::
+ Créer des interfaces Gtk pour OCaml peut se réveler compliquer. On trouve
+ beaucoup d'explications un peu confuses sur le net, et n'est pas facile de
+ trouver comment faire.
+ Je vous propose ici trois manières différentes en utilisants les différents
+ outils disponibles.
+
+Il est possible d'utiliser la bibliothèque Gtk à l'aide de la librairie
+lablgtk_, qui fourni un binding pour l'ensemble de la bibliothèque. L'avantage
+est de pouvoir fonctionner sur toutes les plateformes où gtk est disponible, et
+de bénéficier d'une interface évoluée et agréable pour écrire son application.
+
+L'inconvénient réside dans la bibliothèque gtk : api très compliquée,
+documentation confuse, bref on se retrouve rapidement face à des problèmes là
+où l'on pensait pouvoir avancer sans difficulté. De plus, on est aujourd'hui
+passé à gtk3 alors que `lablgtk` utilise toujours l'api de gtk2. Cela ne pose pas
+de problème dans la compilation (la compatibilité est assurée), mais peut poser
+problème lors de l'utilisation d'outils tels que `glade` (voir plus loin).
+
+.. _lablgtk: http://lablgtk.forge.ocamlcore.org/
+
+Tout construire à la main
+=========================
+
+C'est la première solution, qui demande de connaître Gtk : tous les objets sont
+construits à la main, et le code décrit la manière de faire. L'avantage est que
+le code ne dépend d'aucune ressource externes contrairement aux deux suivantes.
+De plus on contrôle complètement la création de l'interface, on peut donc
+choisir de paramétrer l'interface au lieu d'avoir une interface unique. Un
+tutoriel complet est disponible sur le site d'`OCaml.org`_, je ne vais pas
+le reprendre ici et vous encourage à le suivre.
+
+.. _ocaml.org: http://ocaml.org/learn/tutorials/introduction_to_gtk.html
+
+L'exemple est donné dans la console interactive. Si l'on souhaite le compiler
+dans un module, il faut initialiser Gtk avant de lancer l'affichage :
+
+.. code-block:: ocaml
+
+ GtkMain.Main.init ();
+
+Pour compiler un module, il est nécessaire de faire référence au package
+`lablgtk2`. Voici un exemple pour compiler un fichier `hello.ml` :
+
+.. code-block:: console
+
+ $ ocamlfind ocamlc -package lablgtk2 -I . -c hello.ml
+
+Maintenant il ne reste plus qu'à se plonger dans la documentation de gtk pour
+construire son interface !
+
+Utiliser Glade
+==============
+
+Glade est une interface graphique permettant de construire son application en
+plaçant les contrôles de manière visuelle. Elle génère un fichier XML qui
+décrit l'interface et sera chargé par l'application pour construire
+l'interface. Cela permet de gagner du temps et d'éviter d'écrire le code
+nécessaire pour construire son interface, on se concentre sur les actions
+à exécuter lorsque l'utilisateur interagit.
+
+.. image:: {filename}/images/glade.jpg
+ :class: center
+ :alt: Utilisation de glade.
+
+
+Les XMLs générés par glade sont destinés à être utilisés avec gtk3. Or,
+`lablgtk` utilise encore gtk2, il est donc nécessaire d'utiliser une conversion
+pour pouvoir les charger par la suite. Voici une petite règle `make` qui se
+charge de faire le travail :
+
+.. code-block:: make
+
+ %.glade2: %.glade
+ cat $< | sed 's/interface/glade-interface/' | sed 's/object/widget/' | sed 's/GtkBox/GtkVBox/' > $@
+
+Maintenant qu'on dispose d'un fichier au format glade2, on peut le charger dans
+OCaml.
+
+Attention, lors de la compilation, il est nécessaire d'utiliser `libglade` pour
+construire l'application, celle-ci est disponible dans la librairie
+`lablgtk2.glade`. Voici donc un exemple de commande pour compiler un fichier
+`hello.ml` :
+
+.. code-block:: console
+
+ $ ocamlfind ocamlc -package lablgtk2.glade -I . -c hello.ml
+
+.. _gtkbuilder: https://developer.gnome.org/gtk3/3.4/GtkBuilder.html
+
+Charger le fichier xml
+----------------------
+
+Il s'agit de la solution la plus dynamique : on référence le fichier xml dans
+le code, et l'interface se construit toute seule. Cette solution est présentée
+sur le site de `developpez.com`_. L'exemple donné est toujours valide, il ne
+faut pas oublier d'initialiser Gtk avec la commande suivante avant de lancer la
+construction de l'interface :
+
+.. code-block:: ocaml
+
+ GtkMain.Main.init ();
+
+L'inconvénient de cette méthode (du moins pour un développeur OCaml) est que
+l'on est obligé de convertir de manière dynamique tous les objets présents dans
+le XML. Il n'est pas possible de savoir au moment de la compilation si le code
+que l'on va exécuter est bien valide.
+
+En effet, les objets chargés depuis le XML nous sont retournés sous la forme
+widget gtk, qu'il faut convertir en Bouton, Menu via les méthodes appropriées
+(`GtkWindow.Window.cast` par exemple). On n'est donc pas à l'abri d'avoir une
+erreur lors du fonctionnement du programme, alors que celui-ci a pu compiler
+sans problème. Je pense que lorsqu'on cherche à développer en OCaml, ce genre
+de problème peut être rédhibitoire.
+
+.. _developpez.com: http://blog.developpez.com/damien-guichard/p7748/programmation-fonctionnelle/hello_developpez_avec_libglade_xml_1
+
+De plus, rien ne garantie que le fichier XML ne va pas évoluer de manière
+incompatible du code ; les deux étant distincts.
+
+
+Utiliser lablgladecc2
+---------------------
+
+Heureusement, la librairie `lablgtk2` nous fourni un petit utilitaire nommé
+`lablgladecc2` qui va convertir un fichier xml glade2 en un fichier OCaml. On
+dispose donc d'un chargement dynamique du fichier xml, mais en gardant un code
+cohérent, qui détectera les erreurs dès la compilation. Il s'agit en quelque
+sorte d'un moyen de combiner les deux solutions précédentes.
+
+On va ajouter une règle au makefile pour générer notre fichier OCaml :
+
+.. code-block:: make
+
+ %.ml: %.glade2
+ lablgladecc2 -embed $< > $@
+
+Le fichier généré se compose d'une classe reprenant les différents composants
+de notre interface, il ne nous reste plus qu'à réaliser les connexions, ainsi,
+à partir d'un fichier glade nommé *gui* composé d'une fenêtre `window1`, d'un
+bouton `button` et d'une entrée de menu, on peut créer le code suivant :
+
+.. code-block:: ocaml
+
+ let gladecc () =
+ let window = new Gui.window1 () in
+
+ window#button#connect#clicked (fun () -> prerr_endline "Ouch!");
+ window#window1#connect#destroy GMain.quit;
+ window#imagemenuitem5#connect#activate GMain.quit;
+
+ window#toplevel#show ()
+
+ let () =
+ GtkMain.Main.init ();
+ gladecc ();
+ GMain.Main.main ()
+
+
+l'objet `toplevel` est créé par `lablgladecc2` et correspond à la fenêtre
+principale de notre objet.
+
+Dans cette chaîne de compilation, le fichier xml est écrit dans le programme
+OCaml (il s'agit de la signification de l'option `-embed`), ainsi, le fichier
+XML n'a pas besoin de figurer parmi les ressources de l'application.
+
+Conclusion
+==========
+
+Trois manière de faire qui répondent à trois besoin différents, entre le tout
+codé et le tout dynamique, il est possible de créer des interfaces graphiques
+en utilisant les capacités du langage caml sur l'inférence de type et le
+contrôle de l'ensemble de l'application.
+
+Pour ma part, je préfère la dernière solution, qui permet de conserver la
+simplicité de `glade` combiné avec la force du langage OCaml. J'ai écrit cet
+article suite à pas mal d'errance sur le net pour trouver les informations
+nécessaires, j'espère que la documentation va évoluer par la suite et permettre
+de faire ce genre de choses plus facilement…