Blame platform-demos/fr/image-viewer.py.page

Packit 1470ea
Packit 1470ea
<page xmlns="http://projectmallard.org/1.0/" xmlns:its="http://www.w3.org/2005/11/its" type="topic" id="image-viewer.py" xml:lang="fr">
Packit 1470ea
Packit 1470ea
  <info>
Packit 1470ea
    <title type="text">Image viewer (Python)</title>
Packit 1470ea
    <link type="guide" xref="py#examples"/>
Packit 1470ea
Packit 1470ea
    <desc>Un peu plus qu'une simple application « Hello world » - écrire un visionneur d'images en GTK.</desc>
Packit 1470ea
Packit 1470ea
    <revision pkgversion="0.1" version="0.1" date="2011-03-19" status="review"/>
Packit 1470ea
    <credit type="author">
Packit 1470ea
      <name>Jonh Wendell</name>
Packit 1470ea
      <email its:translate="no">jwendell@gnome.org</email>
Packit 1470ea
    </credit>
Packit 1470ea
    <credit type="author">
Packit 1470ea
      <name>Johannes Schmid</name>
Packit 1470ea
      <email its:translate="no">jhs@gnome.org</email>
Packit 1470ea
    </credit>
Packit 1470ea
    <credit type="editor">
Packit 1470ea
      <name>Marta Maria Casetti</name>
Packit 1470ea
      <email its:translate="no">mmcasetti@gmail.com</email>
Packit 1470ea
      <years>2013</years>
Packit 1470ea
    </credit>
Packit 1470ea
  
Packit 1470ea
    <mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
Packit 1470ea
      <mal:name>Luc Rebert,</mal:name>
Packit 1470ea
      <mal:email>traduc@rebert.name</mal:email>
Packit 1470ea
      <mal:years>2011</mal:years>
Packit 1470ea
    </mal:credit>
Packit 1470ea
  
Packit 1470ea
    <mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
Packit 1470ea
      <mal:name>Alain Lojewski,</mal:name>
Packit 1470ea
      <mal:email>allomervan@gmail.com</mal:email>
Packit 1470ea
      <mal:years>2011-2012</mal:years>
Packit 1470ea
    </mal:credit>
Packit 1470ea
  
Packit 1470ea
    <mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
Packit 1470ea
      <mal:name>Luc Pionchon</mal:name>
Packit 1470ea
      <mal:email>pionchon.luc@gmail.com</mal:email>
Packit 1470ea
      <mal:years>2011</mal:years>
Packit 1470ea
    </mal:credit>
Packit 1470ea
  
Packit 1470ea
    <mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
Packit 1470ea
      <mal:name>Bruno Brouard</mal:name>
Packit 1470ea
      <mal:email>annoa.b@gmail.com</mal:email>
Packit 1470ea
      <mal:years>2011-12</mal:years>
Packit 1470ea
    </mal:credit>
Packit 1470ea
  
Packit 1470ea
    <mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
Packit 1470ea
      <mal:name>Luis Menina</mal:name>
Packit 1470ea
      <mal:email>liberforce@freeside.fr</mal:email>
Packit 1470ea
      <mal:years>2014</mal:years>
Packit 1470ea
    </mal:credit>
Packit 1470ea
  </info>
Packit 1470ea
Packit 1470ea
<title>Image viewer</title>
Packit 1470ea
Packit 1470ea
<synopsis>
Packit 1470ea
  

Dans ce tutoriel, nous allons écrire une application GTK très simple qui charge et affiche un fichier image. Vous allez apprendre comment :

Packit 1470ea
  <list>
Packit 1470ea
    <item>

écrire une interface graphique GTK en Python,

</item>
Packit 1470ea
    <item>

travailler avec des événements en connectant des signaux à des gestionnaires de signaux,

</item>
Packit 1470ea
    <item>

mettre en forme des interfaces utilisateur GTK avec des conteneurs,

</item>
Packit 1470ea
    <item>

charger et afficher des fichiers image.

</item>
Packit 1470ea
  </list>
Packit 1470ea
  

Vous avez besoin de ce qui suit pour pouvoir suivre ce tutoriel :

Packit 1470ea
  <list>
Packit 1470ea
    <item>

l'installation du paquet <link xref="getting-ready">Anjuta IDE</link>,

</item>
Packit 1470ea
    <item>

des connaissances de base du langage de programmation python.

</item>
Packit 1470ea
  </list>
Packit 1470ea
</synopsis>
Packit 1470ea
Packit 1470ea
<media type="image" mime="image/png" src="media/image-viewer.png"/>
Packit 1470ea
Packit 1470ea
<section id="anjuta">
Packit 1470ea
  <title>Création d'un projet dans Anjuta</title>
Packit 1470ea
  

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.

Packit 1470ea
  <steps>
Packit 1470ea
    <item>
Packit 1470ea
    

Lancez Anjuta et cliquez sur <guiseq><gui>Fichier</gui><gui>Nouveau</gui><gui>Projet</gui></guiseq> pour ouvrir l'assistant de création de projet.

Packit 1470ea
    </item>
Packit 1470ea
    <item>
Packit 1470ea
    

Sélectionnez <gui>PyGTK (automake)</gui> dans l'onglet <gui>Python</gui>, cliquez sur <gui>Continuer</gui> et saisissez vos informations sur les pages suivantes. Mettez <file>image-viewer</file> comme nom de projet et de répertoire.

Packit 1470ea
   	</item>
Packit 1470ea
   	<item>
Packit 1470ea
   	

Assurez-vous d'avoir désactivé <gui>Utiliser GtkBuilder pour l'interface utilisateur</gui> car nous allons créer l'interface utilisateur manuellement dans cet exemple. Consultez <link xref="guitar-tuner.py">l'exemple Guitar-Tuner</link> pour un exemple d'utilisation du constructeur d'interfaces.

Packit 1470ea
    </item>
Packit 1470ea
    <item>
Packit 1470ea
    

Cliquez sur <gui>Appliquer</gui> et le projet est créé. Ouvrez <file>src/image_viewer.py</file> depuis l'onglet <gui>Projet</gui> ou l'onglet <gui>Fichiers</gui>. Il contient quelques lignes de code très basique.

Packit 1470ea
    </item>
Packit 1470ea
  </steps>
Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
<section id="first">
Packit 1470ea
  <title>Une première application Gtk</title>
Packit 1470ea
  

Voyons à quoi ressemble une application Gtk basique écrite en Python :

Packit 1470ea
  
Packit 1470ea
from gi.repository import Gtk, GdkPixbuf, Gdk
Packit 1470ea
import os, sys
Packit 1470ea
Packit 1470ea
class GUI:
Packit 1470ea
	def __init__(self):
Packit 1470ea
		window = Gtk.Window()
Packit 1470ea
		window.set_title ("Hello World")
Packit 1470ea
		window.connect_after('destroy', self.destroy)
Packit 1470ea
Packit 1470ea
		window.show_all()
Packit 1470ea
Packit 1470ea
	def destroy(window, self):
Packit 1470ea
		Gtk.main_quit()
Packit 1470ea
Packit 1470ea
def main():
Packit 1470ea
	app = GUI()
Packit 1470ea
	Gtk.main()
Packit 1470ea
Packit 1470ea
if __name__ == "__main__":
Packit 1470ea
    sys.exit(main())
Packit 1470ea
]]>
Packit 1470ea
  
Packit 1470ea
  

Regardons ce qui se passe :

Packit 1470ea
  <list>
Packit 1470ea
    <item>
Packit 1470ea
    

La première ligne importe l'espace de nom Gtk (c.-à-d. cela inclut la bibliothèque Gtk). Les bibliothèques sont fournies par « GObject Introspection (gi) » qui fournit les liens de langage à beaucoup de bibliothèques GNOME.

Packit 1470ea
    </item>
Packit 1470ea
    <item>
Packit 1470ea
    

La méthode __init__ de la classe GUI crée une fenêtre Gtk.Window (vide), définit son titre, puis connecte un signal pour quitter l'application quand la fenêtre est fermée. C'est globalement très simple. Nous en verrons un peu plus sur les signaux plus tard.

Packit 1470ea
    </item>
Packit 1470ea
    <item>
Packit 1470ea
    

Ensuite est définie la méthode destroy qui quitte juste l'application. Elle est appelée par le signal connecté ci-dessus.

Packit 1470ea
    </item>
Packit 1470ea
    <item>
Packit 1470ea
    

Le reste du fichier effectue l'initialisation pour Gtk et affiche l'interface graphique.

Packit 1470ea
    </item>
Packit 1470ea
  </list>
Packit 1470ea
Packit 1470ea
  

Ce programme est prêt à être utilisé, donc essayez-le en utilisant le menu <guiseq><gui>Exécuter</gui><gui>Exécuter</gui></guiseq>. Cela devrait vous afficher une fenêtre vide.

Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
<section id="signals">
Packit 1470ea
  <title>Les signaux</title>
Packit 1470ea
  

Les signaux sont un des concepts clé de la programmation Gtk. Chaque fois que quelque chose arrive à un objet, il émet un signal ; par exemple, quand un bouton est cliqué, il renvoie le signal clicked. Si vous voulez que votre programme réagisse en conséquence, il faut connecter une fonction (un « gestionnaire de signal ») à ce signal. Voici un exemple :

Packit 1470ea
  
Packit 1470ea
def button_clicked () :
Packit 1470ea
  print "you clicked me!"
Packit 1470ea
Packit 1470ea
b = new Gtk.Button ("Click me")
Packit 1470ea
b.connect_after ('clicked', button_clicked)]]>
Packit 1470ea
  

Les deux dernières lignes créent un bouton Gtk.Button appelé b et connectent son signal clicked à la fonction button_clicked définie au-dessus. Chaque fois que ce bouton est cliqué, le code de la fonction button_clicked est exécuté. Il affiche juste un message dans cet exemple.

Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
<section id="containers">
Packit 1470ea
  <title>Les conteneurs : agencement de l'interface utilisateur</title>
Packit 1470ea
  

Les éléments graphiques (les contrôles, comme les boutons ou les étiquettes) peuvent être disposés dans la fenêtre à l'aide de conteneurs. Vous pouvez organiser l'agencement en mélangeant différents types de conteneurs, comme des boîtes ou des grilles.

Packit 1470ea
  

Une fenêtre Gtk.Window est elle-même un type de conteneur, mais vous ne pouvez y insérer directement qu'un seul élément graphique. Nous aimerions avoir deux éléments graphiques, une image et un bouton, donc nous devons placer un conteneur de « plus haute capacité » dans la fenêtre pour tout contenir. Plusieurs <link href="http://library.gnome.org/devel/gtk/stable/GtkContainer.html">types de conteneurs</link> sont disponibles, mais nous allons utiliser ici une boîte Gtk.Box. Une boîte Gtk.Box peut contenir plusieurs éléments graphiques, disposés horizontalement ou verticalement. On pourrait créer des agencements plus complexes en mettant plusieurs boîtes dans une autre et ainsi de suite.

Packit 1470ea
  <note>
Packit 1470ea
  

Il existe un concepteur graphique d'interface utilisateur appelé <app>Glade</app> intégré à <app>Anjuta</app> ce qui rend la conception d'interface utilisateur vraiment facile. Dans cet exemple simple, cependant, nous allons tout programmer à la main.

Packit 1470ea
  </note>
Packit 1470ea
  

Ajoutons la boîte et les éléments graphiques à la fenêtre. Insérez le code suivant dans la méthode __init__, juste après la ligne window.connect_after :

Packit 1470ea
Packit 1470ea
box = Gtk.Box()
Packit 1470ea
box.set_spacing (5)
Packit 1470ea
box.set_orientation (Gtk.Orientation.VERTICAL)
Packit 1470ea
window.add (box)
Packit 1470ea
]]>
Packit 1470ea
Packit 1470ea
  

La première ligne crée une Gtk.Box nommée box et les lignes suivantes définissent deux de ses propriétés : l'orientation est verticale (donc les éléments graphiques sont disposés en colonne) et l'espacement entre les éléments graphiques est fixé à 5 pixels. La ligne suivante ajoute ensuite cette nouvelle Gtk.Box à la fenêtre.

Packit 1470ea
  

Pour l'instant, la fenêtre ne contient qu'une boîte Gtk.Box vide et si vous exécutez le programme, vous ne verrez pas encore de changement (la boîte Gtk.Box est un conteneur transparent et vous ne le voyez donc pas).

Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
<section id="packing">
Packit 1470ea
  <title>Placement : ajout d'éléments graphiques au conteneur</title>
Packit 1470ea
  

Pour ajouter d'autres éléments graphiques à la fenêtre, insérez ce code juste dessous la ligne window.add (box) :

Packit 1470ea
  
Packit 1470ea
self.image = Gtk.Image()
Packit 1470ea
box.pack_start (self.image, False, False, 0)]]>
Packit 1470ea
  

La première ligne crée une nouvelle image Gtk.Image nommée image qui sera utilisée pour afficher un fichier image. Comme nous en avons besoin plus tard dans la fonction de gestion de signal, nous la définissons comme étant un attribut de classe. Vous devez ajouter image = 0 au début de la classe GUI. Puis, l'élément graphique image est ajouté (placé) dans le conteneur box à l'aide de la méthode <link href="http://library.gnome.org/devel/gtk/stable/GtkBox.html#gtk-box-pack-start">pack_start</link> de GtkBox.

Packit 1470ea
  

pack_start prend 4 arguments : l'élément graphique enfant (child) qui doit être ajouté à la boîte Gtk.Box ; si la boîte Gtk.Box doit s'agrandir (expand) quand le nouvel élément graphique est ajouté ; si le nouvel élément graphique doit prendre tout le nouvel espace créé quand la boîte Gtk.Box s'agrandit (fill) ; et enfin combien d'espace libre (padding), en pixels, il doit y avoir entre l'élément graphique et ses voisins à l'intérieur de la Gtk.Box.

Packit 1470ea
  

Si vous les laissez faire, les conteneurs Gtk (et les éléments graphiques) s'agrandissent dynamiquement pour occuper tout l'espace disponible. Vous ne positionnez pas les éléments graphiques dans la fenêtre en leur spécifiant des coordonnées x,y précises mais vous les positionnez les uns par rapport aux autres. Ceci permet un redimensionnement plus aisé de la fenêtre et les éléments graphiques devraient automatiquement prendre une taille raisonnable dans la plupart des cas.

Packit 1470ea
  

Notez aussi de quelle manière les éléments graphiques sont organisés hiérarchiquement. Une fois placée dans la Gtk.Box, l'image Gtk.Image est considérée comme un enfant de la boîte Gtk.Box. Ceci vous permet de traiter tous les enfants d'un élément graphique comme un groupe ; par exemple, vous pouvez masquer la boîte Gtk.Box qui du coup, masque tous ses enfants en même temps.

Packit 1470ea
  

Insérez maintenant ces deux lignes en dessous des deux que vous venez d'ajouter :

Packit 1470ea
  
Packit 1470ea
button = Gtk.Button ("Open a picture...")
Packit 1470ea
box.pack_start (button, False, False, 0)
Packit 1470ea
]]>
Packit 1470ea
  

Ces lignes ressemblent aux deux premières, mais cette fois elles créent un bouton Gtk.Button et l'ajoute à la box. Notez que nous paramétrons ici l'argument expand (le second) sur False, alors qu'il était sur True pour l'image Gtk.Image. Ceci va conduire à ce que l'image prenne tout l'espace disponible et le bouton seulement l'espace nécessaire. Lors d'un redimensionnement de la fenêtre, la taille du bouton reste identique, alors que la taille de l'image va augmenter pour occuper le reste de la fenêtre.

Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
<section id="loading">
Packit 1470ea
  <title>Chargement de l'image : connexion au signal clicked du bouton</title>
Packit 1470ea
  

Quand l'utilisateur clique sur le bouton <gui>Open a picture...</gui>, une boîte de dialogue s'affiche pour lui permettre de choisir une image. Une fois ce choix effectué, la photo est chargée et affichée dans l'élément graphique image.

Packit 1470ea
  

Connectez d'abord le signal clicked du bouton à une fonction de gestion de signal que vous appelez on_open_clicked. Mettez ce code immédiatement après la ligne button = Gtk.Button() où le bouton a été créé :

Packit 1470ea
  
Packit 1470ea
button.connect_after('clicked', self.on_open_clicked)
Packit 1470ea
]]>
Packit 1470ea
  

Cela connecte le signal clicked à la méthode on_open_clicked que nous définirons ci-dessous.

Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
<section id="loading2">
Packit 1470ea
  <title>Chargement de l'image : écriture de la fonction de rappel du signal</title>
Packit 1470ea
  

On peut maintenant créer la méthode on_open_clicked. Insérez ce qui suit dans le bloc de code de la classe GUI, après la méthode __init__ :

Packit 1470ea
    
Packit 1470ea
def on_open_clicked (self, button):
Packit 1470ea
	dialog = Gtk.FileChooserDialog ("Open Image", button.get_toplevel(), Gtk.FileChooserAction.OPEN);
Packit 1470ea
	dialog.add_button (Gtk.STOCK_CANCEL, 0)
Packit 1470ea
	dialog.add_button (Gtk.STOCK_OK, 1)
Packit 1470ea
	dialog.set_default_response(1)
Packit 1470ea
Packit 1470ea
	filefilter = Gtk.FileFilter ()
Packit 1470ea
	filefilter.add_pixbuf_formats ()
Packit 1470ea
	dialog.set_filter(filefilter)
Packit 1470ea
Packit 1470ea
	if dialog.run() == 1:
Packit 1470ea
		self.image.set_from_file(dialog.get_filename())
Packit 1470ea
Packit 1470ea
	dialog.destroy()]]>
Packit 1470ea
  

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

Packit 1470ea
  <list>
Packit 1470ea
    <item>
Packit 1470ea
      

La ligne commençant par dialog crée une boîte de dialogue <gui>Open</gui> qui permet à l'utilisateur de choisir des fichiers. Nous paramétrons trois propriétés : le titre de la boîte de dialogue ; la fonction (le type) de la boîte de dialogue (c'est une boîte de dialogue « OPEN », mais on aurait pu utiliser (SAVE) (enregistrer) si notre intention avait été d'enregistrer un fichier) et transient_for, qui définit la fenêtre parent de la boîte de dialogue.

Packit 1470ea
    </item>
Packit 1470ea
    <item>
Packit 1470ea
    

Les deux lignes suivantes ajoutent les boutons <gui>Cancel</gui> (Annuler) et <gui>Open</gui> (Ouvrir) à la boîte de dialogue. Le second argument de la méthode add_button est la valeur (de type entier) qui est retournée lorsque le bouton est cliqué : 0 pour <gui>Annuler</gui> et 1 pour <gui>Ouvrir</gui>.

Packit 1470ea
    

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.

Packit 1470ea
    </item>
Packit 1470ea
    <item>
Packit 1470ea
    

set_default_response détermine le bouton qui est activé quand l'utilisateur fait un double-clic sur un fichier ou appuie sur la touche <key>Entrée</key>. Ici, nous utilisons le bouton <gui>Open</gui> (qui a la valeur 1).

Packit 1470ea
    </item>
Packit 1470ea
    <item>
Packit 1470ea
    

Les trois lignes suivantes limitent la boîte de dialogue <gui>Ouvrir</gui> à 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 <gui>Open</gui>.

Packit 1470ea
    </item>
Packit 1470ea
    <item>
Packit 1470ea
    

dialog.run affiche la boîte de dialogue <gui>Open</gui>. La boîte de dialogue attend que l'utilisateur choisisse une image ; quand c'est fait, dialog.run retourne la valeur <output>1</output> (il retourne la valeur <output>0</output> si l'utilisateur clique sur <gui>Annuler</gui>). L'instruction if teste cette réponse.

Packit 1470ea
    </item>
Packit 1470ea
    <item>

Supposons que l'utilisateur a cliqué sur le bouton <gui>Ouvrir</gui>, la ligne suivante définit la propriété file du Gtk.Image au nom de fichier image sélectionné. Gtk.Image charge alors l'image choisie et l'affiche.

Packit 1470ea
    </item>
Packit 1470ea
    <item>
Packit 1470ea
    

La dernière ligne de cette méthode détruit la boîte de dialogue <gui>Open</gui> car nous n'en avons plus besoin.

Packit 1470ea
    </item>
Packit 1470ea
  </list>
Packit 1470ea
Packit 1470ea
  </section>
Packit 1470ea
Packit 1470ea
<section id="run">
Packit 1470ea
  <title>Exécution de l'application</title>
Packit 1470ea
  

Tout le programme nécessaire est maintenant en place, donc essayez de l'exécuter. Cela devrait fonctionner ; un visionneur d'images totalement fonctionnel (et une visite éclair de Python et de Gtk) en très peu de temps !

Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
<section id="impl">
Packit 1470ea
 <title>Implémentation de référence</title>
Packit 1470ea
 

Si vous rencontrez des difficultés avec ce tutoriel, comparez votre programme à ce <link href="image-viewer/image-viewer.py">programme de référence</link>.

Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
<section id="next">
Packit 1470ea
  <title>Les étapes suivantes</title>
Packit 1470ea
  

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

Packit 1470ea
  <list>
Packit 1470ea
   <item>
Packit 1470ea
   

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.

Packit 1470ea
   </item>
Packit 1470ea
   <item>
Packit 1470ea
   

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.

Packit 1470ea
   

<link href="http://www.gegl.org/api.html">GEGL</link> fournit de puissantes possibilités de manipulation d'image.

Packit 1470ea
   </item>
Packit 1470ea
   <item>
Packit 1470ea
   

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

Packit 1470ea
   

You can use <link href="http://library.gnome.org/devel/gio/unstable/">GIO</link> to handle network file transfers and the like, and <link href="http://library.gnome.org/devel/gnome-scan/unstable/">GNOME Scan</link> to handle scanning.

Packit 1470ea
   </item>
Packit 1470ea
  </list>
Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
</page>