Développement Rapide D'Interfaces - Guillaume Rivière

1.1 Dessin de l'interface à l'aide de Glade

La première étape est de construire une fenêtre GtkWindow qui sera structurée par un conteneur GtkTable et qui contiendra trois étiquettes GtkLabel, deux zones de saisie GtkEntry et un bouton GtkButton :

Composition de la fenêtre du programme addition
Figure 1.1.1
  1. Lancez le programme C:\"Program Files (x86)"\GLADE-3.8\bin\glade-3.exe
    • Remarque : créer un raccourci sur votre bureau permettra d'aller plus vite les prochaines fois.
  2. À partir de ce point, les étapes sont décrites dans la vidéo gtk-glade-v2.avi :
    1. Créez deux nouveaux répertoires C:\PROG1ACI\1A_GUI_GTK\ et C:\PROG1ACI\1A_GUI_GTK\Addition\
    2. Copiez la vidéo dans C:\PROG1ACI\1A_GUI_GTK\Addition\
      • en la récupérant depuis le disque "Cours" I:\G.RIVIERE\1A_Developpement_Rapide_Interfaces\ (de préférence, car plus rapide)
      • ou bien, en la récupérant depuis internet : gtk-glade-v2.avi (10 Mio)
    3. Attention, votre répertoire de travail sera C:\PROG1ACI\1A_GUI_GTK\Addition\ ce qui diffère légèrement du chemin donné à la fin de la vidéo.
    4. Branchez vos écouteurs pour avoir les commentaires et utilisez à bon escient le bouton pause pendant la lecture de cette vidéo !

Nous qualifions cette approche de « rapide » ou de « facile » car la visualisation du résultat est immédiate, d'une part, et car cela évite de produire le code « à la main » (et « en aveugle »), d'autre part. L'autre approche, que nous pouvons qualifier de « classique », consisterait par exemple à produire deux fichiers comme ceux-ci :addition.h#ifndef __ADDITON_H #define __ADDITON_H struct addition_widgets { GtkWindow *window; GtkLabel *label_message; GtkEntry *entry_nombre1; GtkEntry *entry_nombre2; } ; struct addition_widgets create_addition_widgets () ; #endif /* __ADDITON_H */ addition.c#include #include "callbacks.h" #include "addition.h" struct addition_widgets create_addition_widgets () { GtkWidget *label1, *label2, *button1, *table1; struct addition_widgets addition ; label1 = gtk_label_new ("Nombre 1 : "); label2 = gtk_label_new ("Nombre 2 : "); button1 = gtk_button_new_with_label ("Addition"); table1 = gtk_table_new (3, 2, TRUE); addition.window = (GtkWindow *) gtk_window_new (GTK_WINDOW_TOPLEVEL); addition.entry_nombre1 = (GtkEntry *) gtk_entry_new (); addition.entry_nombre2 = (GtkEntry *) gtk_entry_new (); addition.label_message = (GtkLabel *) gtk_label_new (""); gtk_table_attach (GTK_TABLE(table1), label1 , 0, 1, 0, 1, 0, 0, 0, 0); gtk_table_attach (GTK_TABLE(table1), GTK_WIDGET(addition.entry_nombre1), 1, 2, 0, 1, 0, 0, 0, 0); gtk_table_attach (GTK_TABLE(table1), label2 , 0, 1, 1, 2, 0, 0, 0, 0); gtk_table_attach (GTK_TABLE(table1), GTK_WIDGET(addition.entry_nombre2), 1, 2, 1, 2, 0, 0, 0, 0); gtk_table_attach (GTK_TABLE(table1), button1 , 0, 1, 2, 3, 0, 0, 0, 0); gtk_table_attach (GTK_TABLE(table1), GTK_WIDGET(addition.label_message), 1, 2, 2, 3, 0, 0, 0, 0); gtk_window_set_title (addition.window, "Addition"); gtk_container_add (GTK_CONTAINER (addition.window), GTK_WIDGET(table1)); g_signal_connect (G_OBJECT(addition.window), "destroy", G_CALLBACK(on_window1_destroy), NULL); g_signal_connect (G_OBJECT(button1), "clicked", G_CALLBACK(on_button_addition_clicked), NULL); return addition; }

1.2 Le fichier principal de l'interface (main.c)

  • À l'aide de Notepad++ vous allez créer le fichier C:\PROG1ACI\1A_GUI_GTK\Addition\main.c comme suit :
    #include <stdio.h> #include <stdlib.h> #include <gtk/gtk.h> #include "callbacks.h" GtkBuilder *builder; int main (int argc, char *argv[]) { GtkWidget *window1; /* Initialisation de GTK */ gtk_init (&argc, &argv); /* Creation des widgets de l'interface a partir du fichier XML de Glade, grace au builder GTK */ builder = gtk_builder_new (); if (gtk_builder_add_from_file (builder, "addition.glade", NULL) == 0) { fprintf (stderr, "Erreur: ouverture du fichier GLADE\n") ; exit(EXIT_FAILURE); } /* Recuperation du widget de la fenetre principale */ window1 = GTK_WIDGET (gtk_builder_get_object (builder, "window1")); /* Connection des fonctions de rappel avec les signaux de l'interface */ gtk_builder_connect_signals (builder, NULL); /* Changement de la fenetre principale a l'etat visible */ gtk_widget_show (window1); /* Lancement de l'execution de la boucle GTK */ gtk_main (); g_object_unref (G_OBJECT (builder)); printf ("Fin du programme\n") ; /* Fin du programme */ return EXIT_SUCCESS; }
    Code 1.2.1
  • Remarquez que le fichier addition.glade créé précédemment à l'aide de Glade est utilisé par la fonction gtk_builder_add_from_file().

1.3 Un fichier pour les fonctions de rappels de l'interface (callbacks.c)

Avec Glade nous avons précédemment indiqué d'une part que le signal "destroy" de la fenêtre window1 serait connecté à une fonction nommée on_window1_destroy(), et d'autre part, que le signal "clicked" du composant button_addition serait connecté à une fonction nommée on_button_addition_clicked(). Pour que notre interface puisse fonctionner, il faut donc écrire le code de ces deux « fonctions de rappel » (en d'autres termes, fonction qui sera appelée lorsque le signal correspondant sera émis par le composant auquel elle est connectée). Le rôle de la première fonction sera simplement de stopper la boucle d'exécution de GTK. Le rôle de la seconde sera de récupérer les valeurs saisies par l'utilisateur, de procéder au calcul et d'afficher le résultat.

  • À l'aide de Notepad++ vous allez créer le fichier C:\PROG1ACI\1A_GUI_GTK\Addition\callbacks.h comme suit :
    #ifndef CALLBACKS_H #define CALLBACKS_H #include <gtk/gtk.h> G_MODULE_EXPORT void on_window1_destroy (GtkObject *object, gpointer user_data) ; G_MODULE_EXPORT void on_button_addition_clicked (GtkObject *object, gpointer user_data) ; #endif /* CALLBACKS_H */
    Code 1.3.1
  • Vous allez maintenant créer le fichier C:\PROG1ACI\1A_GUI_GTK\Addition\callbacks.c
    1. Au début du fichier copiez les inclusions d'entêtes suivantes :
      #include <stdio.h> /* sprintf */ #include <stdlib.h> /* atoi */ #include <string.h> /* strlen, strcmp */ #include <ctype.h> /* isdigit */ #include "callbacks.h"
      Code 1.3.2
    2. Afin de pouvoir utiliser la variable globale que nous avons définie dans le fichier main.c ajoutez ensuite cette déclaration :
      extern GtkBuilder *builder;
      Code 1.3.3
    3. Donnez le code suivant pour la fonction on_window1_destroy() :
      printf("Fermeture de la fenetre.\n"); gtk_main_quit();
      Code 1.3.4
      • Ainsi, fermer la fenêtre provoquera en même temps l'arrêt de la boucle GTK (lancée dans la fonction main()) puis le programme se terminera.
      • Car sinon, la fenêtre se fermera, mais le programme continuera de fonctionner !
    4. Donnez le code suivant pour la fonction on_button_addition_clicked() :
      int n1, n2, n3 ; char msg[128] = "" ; const char *s1, *s2 ; /* Recuperer des pointeurs vers les widgets */ GtkLabel *label_message = GTK_LABEL (gtk_builder_get_object (builder, "label_message")); GtkEntry *entry_nombre1 = GTK_ENTRY (gtk_builder_get_object (builder, "entry_nombre1")); GtkEntry *entry_nombre2 = GTK_ENTRY (gtk_builder_get_object (builder, "entry_nombre2")); /* Recuperer le contenu des deux zones de saisie */ s1 = gtk_entry_get_text (entry_nombre1) ; s2 = gtk_entry_get_text (entry_nombre2) ; /* Traitement */ if (!strcmp(s1, "") || !strcmp(s2, "")) { sprintf (msg, "Champs vides") ; } else if (!est_nombre_entier(s1) || !est_nombre_entier(s2)) { sprintf (msg, "Pas des nombres") ; } else { n1 = atoi(s1) ; n2 = atoi(s2) ; n3 = n1 + n2 ; sprintf (msg, "La somme vaut %d", n3) ; } /* Remplacer le texte du label de message */ gtk_label_set_text (label_message, msg) ;
      Code 1.3.5
      • Remarquez l'utilisation de sprintf() pour préparer les chaînes de caractères.
    5. Ajouter la fonction suivante avant les autres fonctions :
      char est_nombre_entier (const char *s) { int i ; char res = 1 ; /* true */ for (i=0 ; i<strlen(s) && res ; i++) if (!isdigit(s[i])) res = 0 ; /* false */ return res ; }
      Code 1.3.6
      • La fonction isdigit() permet de savoir si le caractère est un chiffre.
    6. N'oubliez pas d'enregistrer les fichiers main.c, callbacks.h et callbacks.c

1.4 Compilation et exécution

  • En programmation, lorsqu'on utilise une bibliothèque (comme GTK, mais encore OpenCV, OpenGL, … par exemple) il faut spécifier au compilateur différentes informations comme :
    • Les répertoires où trouver les fichiers d'entête en .h (option -I de gcc)
    • Les répertoires où trouver les fichiers .lib (option -L de gcc)
    • Le nom des fichiers .lib qu'on souhaite utiliser (option -l de gcc, mais sans écrire le .lib)
  • L'écriture de la commande de compilation devient alors longue et difficile à écrire ! La solution est alors de passer par un fichier dit Makefile qui décrit comment le projet doit être compilé (voir dans le chapitre 1 du cours de programmation procédurale). Téléchargez, dans le répertoire C:\PROG1ACI\1A_GUI_GTK\Addition, le fichier Makefile déjà écrit.
    • Attention, le fichier doit s'appeler Makefile et non pas Makefile.txt, il faudra donc peut être le renommer comme suit depuis une console :rename Makefile.txt Makefile
    • Ouvrez maintenant le fichier Makefile avec Notepad++ et examinez son contenu.
  • Depuis la console :
    1. Depuis le répertoire C:\PROG1ACI\1A_GUI_GTK\Addition
    2. Pour exécuter le fichier Makefile tapez simplement make
    3. Et si tout s'est bien passé, tapez addition.exe
      • Si jamais un message d'erreur apparaît concernant les DLL (ex. : zlib1.dll), c'est parce que d'autres versions de la bibliothèque sont installées sur votre système.
      • Dans ce cas, copiez directement la bonne version des DLL de GTK à côté de votre exécutable, comme ceci :copy C:\"Program Files (x86)"\GTK\bin\*.dll C:\PROG1ACI\1A_GUI_GTK\Addition\
      • Essayez de nouveau de lancer addition.exe
    4. Vous devez alors voir la fenêtre suivante apparaître :
La fenêtre du programme addition
Figure 1.4.1

Tag » Apprendre Gtk