Un peu plus qu'une simple application GTKmm « Hello world ».
Projet de Documentation GNOME
gnome-doc-list@gnome.org
Johannes Schmid
jhs@gnome.org
Marta Maria Casetti
mmcasetti@gmail.com 2013

# Image viewer

      Dans ce tutoriel, vous allez apprendre :

        quelques concepts de base de la programmation en C++/GObject,
        comment écrire une application Gtk en C++.

# Création d'un projet dans Anjuta

Avant de commencer à programmer, vous devez ouvrir un nouveau projet dans Anjuta. Ceci crée tous les fichiers qui vous sont nécessaires pour construire et exécuter votre programme plus tard. C'est aussi utile pour tout regrouper en un seul endroit.

Lancez Anjuta et cliquez sur Fichier Nouveau Projet pour ouvrir l'assistant de création de projet.

Sélectionnez GTKmm (Simple) dans l'onglet C++, cliquez sur Continuer et saisissez vos informations sur les quelques pages suivantes. Mettez image-viewer comme nom de projet et de répertoire.

Assurez-vous d'avoir désactivé Utiliser GtkBuilder pour l'interface utilisateur car nous allons créer l'interface utilisateur manuellement dans cet exemple. Consultez le tutoriel Guitar-Tuner pour un exemple d'utilisation du constructeur d'interfaces.

Cliquez sur Appliquer et le projet est créé. Ouvrez src/main.cc depuis l'onglet Projet ou l'onglet Fichiers. Vous devez voir apparaître du code commençant par les lignes :

#include <gtkmm.h> #include <iostream>

#include "config.h">

# Première construction du programme

C'est un programme C++ très basique pour configurer GTKmm. Vous trouverez plus de détails ci-dessous ; passez cette liste si vous comprenez les bases :

Les trois lignes `#include` du haut incorporent les bibliothèques `config` (définitions utiles pour la construction autoconf), `gtkmm` (interface utilisateur) et `iostream` (C++-STL). Les fonctions de ces bibliothèques seront utilisées dans le reste du programme.

La fonction `main` crée une nouvelle fenêtre (vide) et configure le titre de la fenêtre.

L'appel `kit::run()` démarre la boucle principale de GTKmm qui exécute l'interface utilisateur et commence à écouter les événements (comme des clics ou des appuis sur des touches). Comme la fenêtre est fournie comme argument de la fonction, l'application quitte automatiquement quand la fenêtre est fermée.

Le programme est prêt à être utilisé, donc vous pouvez le compiler en cliquant sur Construire Construire le projet ou en appuyant sur Maj F7.

Cliquez sur Exécuter dans la fenêtre suivante pour configurer une construction avec débogage. Vous ne devez le faire qu'une seule fois, lors de la première exécution.

# Création de l'interface utilisateur

Nous allons maintenant donner vie à la fenêtre vide. La disposition de l'interface utilisateur est faite par GTKmm avec les conteneurs `Gtk::Container` qui peuvent contenir d'autres éléments graphiques et même d'autres conteneurs. Ici, on utilise le plus simple des conteneurs disponibles, une boîte `Gtk::Box` :

int main (int argc, char *argv[]) { Gtk::Main kit(argc, argv);

Gtk::Window main_win; main_win.set_title ("image-viewer-cpp");

Gtk::Box* box = Gtk::manage(new Gtk::Box()); box->set_orientation (Gtk::ORIENTATION_VERTICAL); box->set_spacing(6); main_win.add(*box);

image = Gtk::manage(new Gtk::Image()); box->pack_start (*image, true, true);

Gtk::Button* button = Gtk::manage(new Gtk::Button("Open Image…")); button->signal_clicked().connect ( sigc::ptr_fun(&on_open_image)); box->pack_start (*button, false, false);

main_win.show_all_children(); kit.run(main_win);

return 0; }

Les premières lignes créent les éléments graphiques dont nous avons besoin : un bouton pour ouvrir une image, l'élément graphique image lui-même et la boîte que nous utilisons comme conteneur.

Les appels à `pack_start` ajoutent les deux éléments graphiques à la boîte et définissent leur comportement. L'image va s'étendre pour occuper tout l'espace disponible alors que le bouton va prendre juste la taille nécessaire. Notez que nous ne définissons pas explicitement les dimensions des éléments graphiques. Avec GTKmm, ce n'est habituellement pas nécessaire car cela facilite grandement l'obtention d'une bonne disposition pour différentes tailles de fenêtre. La boîte est ensuite ajoutée dans la fenêtre.

Il nous faut définir ce qui se passe quand l'utilisateur clique sur le bouton. GTKmm utilise le concept de signaux. Quand le bouton est cliqué, il envoie le signal clicked qu'il est possible de relier à une action. Cela a été réalisé avec la méthode `signal_clicked().connect` qui commande à GTKmm d'appeler la fonction `on_open_image` quand le bouton est cliqué. Nous définirons la fonction de rappel à la section suivante.

La dernière étape consiste à afficher tous les éléments graphiques avec la commande `show_all_children()`. Ceci équivaut à appliquer la méthode `show()` séparément à chaque élément graphique enfant.

# Affichage de l'image

Nous allons maintenant définir le gestionnaire de signal pour le signal clicked du bouton ci-dessus. Ajoutez ce code avant la méthode `main`.

Gtk::Image* image = 0;

static void on_open_image () { Gtk::FileChooserDialog dialog("Open image", Gtk::FILE_CHOOSER_ACTION_OPEN); dialog.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT); dialog.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);

Glib::RefPtr<Gtk::FileFilter> filter = Gtk::FileFilter::create(); filter->add_pixbuf_formats(); filter->set_name("Images"); dialog.add_filter (filter);

const int response = dialog.run(); dialog.hide();

switch (response) { case Gtk::RESPONSE_ACCEPT: image->set(dialog.get_filename()); break; default: break; } }

C'est un peu plus compliqué que tout ce que nous avons essayé jusqu'à présent, donc décortiquons cette partie étape par étape :

La boîte de dialogue pour choisir le fichier en utilisant le constructeur `Gtk::FileChooserDialog`. Celui-ci prend comme argument le titre et le type de la boîte de dialogue. Ici, c'est un dialogue OPEN (ouvrir).

Les deux lignes suivantes ajoutent les boutons Open et Close à la boîte de dialogue.

Notez que nous utilisons les noms de bouton de la collection (stock) Gtk au lieu de saisir manuellement « Cancel » ou « Open ». L'avantage d'utiliser les noms de la collection est que les étiquettes des boutons seront déjà traduites dans la langue de l'utilisateur.

Le second argument de la méthode `add_button()` est une valeur identifiant le bouton cliqué. Nous utilisons ici aussi les valeurs de GTKmm fournies par défaut.

Les deux lignes suivantes limitent la boîte de dialogue Open à l'affichage des seuls fichiers pouvant être ouverts par `Gtk::Image`. Un objet filtre est d'abord créé ; ensuite nous ajoutons tous les types de fichier pris en charge par `Gdk::Pixbuf` (ce qui inclut la plupart des formats d'image comme PNG ou JPEG) au filtre. Enfin, nous appliquons ce filtre à la boîte de dialogue Open.

`Glib::RefPtr` utilisé ici, est un pointeur intelligent qui surveille que le filtre soit bien détruit quand il n'a plus de référence vers lui.

`dialog.run` affiche la boîte de dialogue Open. La boîte de dialogue attend que l'utilisateur choisisse une image ; quand c'est fait, `dialog.run` retourne la valeur `Gtk::RESPONSE_ACCEPT` (il retourne la valeur `Gtk::RESPONSE_CANCEL` si l'utilisateur clique sur Cancel). L'instruction `switch` teste cette réponse.

Nous masquons la boîte de dialogue Open car on n'en a plus besoin. Elle aurait de toute façon été masquée plus tard, car ce n'est qu'une variable locale qui est détruite (et donc disparaît) lorsqu'elle sort de la portée.

Supposons que l'utilisateur a cliqué sur le bouton Ouvrir, la ligne suivante charge le fichier dans le`Gtk::Image` afin qu'elle s'affiche.

# Construction et lancement de l'application

À ce stade, tout le programme est fonctionnel. Cliquez sur Construire Construire le projet pour tout reconstruire et faites Exécuter Exécuter pour lancer l'application.

Si ce n'est pas encore fait, sélectionnez l'application Debug/src/image-viewer dans la boîte de dialogue qui s'affiche et cliquez sur Exécuter. Amusez-vous bien !

# Implémentation de référence

Si vous rencontrez des difficultés avec ce tutoriel, comparez votre programme à ce programme de référence.

# Les étapes suivantes

Voici quelques idées sur la manière d'étendre ce simple exemple :

Faire que l'utilisateur puisse sélectionner un dossier plutôt qu'un fichier et fournir les contrôles pour naviguer parmi toutes les images d'un dossier.

Appliquer au hasard des filtres et des effets à l'image quand elle est chargée et permettre à l'utilisateur d'enregistrer l'image modifiée.

GEGL fournit de puissantes possibilités de manipulation d'image.

Permettre à l'utilisateur de charger des images depuis des sites de partage, des scanners ou d'autres sources plus sophistiquées.

Vous pouvez utiliser GIO pour gérer des transferts de fichiers en ligne et des choses du même type et GNOME Scan pour gérer les documents scannés.