> Tutoriel GTK Haskell : installez les bindings gtk2hs / haskell-gi, créez une fenêtre, ajoutez un bouton et branchez des callbacks sur les signaux.

*Source : https://coder-studio.com/tutoriels/gtk-haskell/*

---

[// Fonctionnel](https://coder-studio.com/tutoriels/)

# Créer une interface graphique GTK en Haskell

Par **Kévin Papot** · publié le 14 février 2026

On associe souvent Haskell au calcul pur, aux types et à la ligne de commande. Pourtant, rien n’empêche d’écrire une **interface graphique en Haskell**. La bibliothèque **GTK**, qui motorise le bureau GNOME et d’innombrables applications Linux, dispose de bindings Haskell mûrs et confortables. Dans ce tutoriel, nous allons construire une petite fenêtre avec un bouton et brancher une action dessus, ce qui suffit à comprendre le modèle événementiel de GTK.

## gtk2hs ou haskell-gi ?

Historiquement, les bindings GTK pour Haskell portaient le nom de **gtk2hs**. C’est le projet qui a longtemps servi de référence, exposant l’API de GTK 2 sous forme de modules Haskell. Il fonctionne toujours et beaucoup de tutoriels s’y réfèrent.

Le projet a ensuite évolué vers **haskell-gi**, qui génère automatiquement les bindings à partir des fichiers d’introspection _GObject Introspection_. C’est aujourd’hui l’approche recommandée pour cibler **GTK 3** ou **GTK 4** : le paquet s’appelle `gi-gtk`. Les deux partagent la même philosophie ; nous montrerons ici les deux styles pour que vous reconnaissiez le code que vous croiserez.

## Installer les dépendances

GTK est une bibliothèque C : il faut donc que ses en-têtes de développement soient présentes sur le système avant de compiler le binding.

```
# Debian / Ubuntu
sudo apt install libgtk-3-dev

# Fedora
sudo dnf install gtk3-devel
```

Ensuite, on ajoute le paquet Haskell au projet. Avec **Stack**, on déclare la dépendance dans le fichier `package.yaml` :

```
dependencies:
  - base
  - gi-gtk
  - haskell-gi-base
```

Avec **Cabal**, on ajoute simplement `gi-gtk` à la section `build-depends` du fichier `.cabal`. La compilation télécharge et bâtit le binding ; la première fois peut être longue, c’est normal.

## Une première fenêtre

Voici le squelette minimal d’une application `gi-gtk`. On initialise GTK, on crée une fenêtre, on demande son affichage et on lance la boucle d’événements.

```
{-# LANGUAGE OverloadedStrings #-}
module Main where

import qualified GI.Gtk as Gtk

main :: IO ()
main = do
  _ <- Gtk.init Nothing

  fenetre <- Gtk.windowNew Gtk.WindowTypeToplevel
  Gtk.setWindowTitle fenetre "Bonjour Coder Studio"
  Gtk.setWindowDefaultWidth  fenetre 320
  Gtk.setWindowDefaultHeight fenetre 200

  Gtk.widgetShowAll fenetre
  Gtk.main
```

Deux points méritent l’attention. L’extension `OverloadedStrings` permet d’écrire les titres directement entre guillemets, car GTK attend des chaînes `Text` et non des `String`. Et surtout, **`Gtk.main` est une boucle bloquante** : c’est elle qui attend les clics, les frappes et les redessins. Tant qu’on ne la quitte pas, la fenêtre reste vivante.

## Fermer proprement l’application

En l’état, cliquer sur la croix ferme la fenêtre mais ne rend pas la main au programme. Il faut connecter le signal `destroy` de la fenêtre à l’arrêt de la boucle GTK.

```
import Data.GI.Base (on)

_ <- on fenetre #destroy Gtk.mainQuit
```

La fonction `on` est le pont central du modèle événementiel : elle relie un **signal** émis par un widget à une **action** Haskell. Ici, quand la fenêtre émet `destroy`, on appelle `mainQuit`, ce qui fait retourner `Gtk.main` et termine `main`.

## Ajouter un bouton et un callback

Passons à l’essentiel : réagir à une interaction. On crée un bouton, on le place dans la fenêtre, puis on branche son signal `clicked` sur une fonction.

```
bouton <- Gtk.buttonNewWithLabel "Cliquez-moi"
Gtk.containerAdd fenetre bouton

_ <- on bouton #clicked $ do
  putStrLn "Le bouton a été cliqué !"
  Gtk.setButtonLabel bouton "Merci !"

Gtk.widgetShowAll fenetre
```

À chaque clic, le callback s’exécute : il affiche un message dans la console et change le texte du bouton. C’est exactement le principe de GTK — on décrit _quoi faire quand_ tel événement survient, et la boucle principale se charge d’appeler nos fonctions au bon moment. Notez que `containerAdd` n’accepte qu’un seul enfant direct ; pour disposer plusieurs widgets, on utilise un conteneur comme `Gtk.boxNew`.

## Le même code en style gtk2hs

Si vous tombez sur du code utilisant l’ancien binding **gtk2hs**, la structure est très proche, avec une syntaxe légèrement différente pour connecter les signaux :

```
import Graphics.UI.Gtk

main :: IO ()
main = do
  initGUI
  fenetre <- windowNew
  bouton  <- buttonNewWithLabel "Cliquez-moi"
  containerAdd fenetre bouton
  on bouton buttonActivated $ putStrLn "Cliqué !"
  on fenetre objectDestroy   mainQuit
  widgetShowAll fenetre
  mainGUI
```

On retrouve les mêmes idées : `initGUI` pour démarrer, la connexion des signaux avec `on`, et `mainGUI` comme boucle bloquante. Seuls les noms changent.

## Compiler et lancer

Avec Stack, il suffit d’un `stack run` ; avec Cabal, d’un `cabal run`. Une petite fenêtre apparaît, et chaque clic déclenche votre callback. Vous tenez là toutes les briques fondamentales d’une GUI GTK : fenêtre, widget, signal et boucle d’événements.

## Aller plus loin

À partir de ce socle, on ajoute des champs de saisie (`Gtk.entryNew`), des dispositions en boîtes ou en grilles, et l’on peut même charger l’interface depuis un fichier décrit avec l’éditeur **Glade**. La force de Haskell reste entière : la logique métier demeure pure et typée, seule la couche d’interaction touche à `IO`.

## À lire ensuite

-   Si Haskell est nouveau pour vous, commencez par [débuter avec Haskell sans prise de tête](https://coder-studio.com/tutoriels/demarrer-haskell-platform/).
-   Comparez les approches GUI multiplateformes avec [l’introduction à wxWidgets](https://coder-studio.com/tutoriels/introduction-wxwidgets/).
-   Prenez du recul sur le paradigme avec notre guide de la [programmation fonctionnelle](https://coder-studio.com/tutoriels/programmation-fonctionnelle/).
