GTK+ par l'exemple


précédentsommairesuivant

XIV. Les racourcis clavier

XIV-A. Aperçu

Image non disponible
Cliquez pour agrandir

XIV-B. Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mnémoniques, ces derniers permettent d'accéder à un élément séquentiellement alors que les raccourcis appellent une fonction si l'utilisateur appuie simultanément sur une ou plusieurs touches (généralement de la forme <Modificateur>Touche, où Modificateur représente les touches Shift, Alt et Control). Ce raccourci peut être attaché à un élément du menu mais ceci n'est pas obligatoire.
Les raccourcis sont regroupés en groupe dans un GtkAccelGroup qu'il faut commencer par créer :

raccourcis.c
Sélectionnez
#include <gtk/gtk.h>
#include "callback.h"
#include "raccourcis.h"

GtkAccelGroup *accel_group_new (gpointer user_data)
{
  GtkAccelGroup *p_accel_group = NULL;

  p_accel_group = gtk_accel_group_new ();
  /* ... */
  return p_accel_group;
}

Vous commencez à avoir l'habitude de cette organisation, nous allons donc créer une fonction qui va se charger d'ajouter un raccourci au groupe :

raccourcis.c
Sélectionnez
static void accelerator_new (GtkAccelGroup *p_accel_group, const gchar *accelerator, const gchar *accel_path,
                             GCallback callback, gpointer user_data)
{
  guint key;
  GdkModifierType mods;
  GClosure *closure = NULL;

  gtk_accelerator_parse (accelerator, &key, &mods);
  closure = g_cclosure_new (callback, user_data, NULL);
  gtk_accel_group_connect (p_accel_group, key, mods, GTK_ACCEL_VISIBLE, closure);
  gtk_accel_map_add_entry (accel_path, key, mods);
}

La fonction gtk_accelerator_parse permet de décomposer une chaîne de caractères de la forme "<Control>F1" ou encore "<Alt>A" en numéro de touche et modificateur.
En plus des touches, pour créer un raccourci clavier, nous avons besoin d'une fonction à appeler lorsque l'utilisateur appuie sur les touches spécifiées. gtk_accel_group_connect attend une fonction du type GClosure, regardons la documentation de gobject pour savoir à quoi cela correspond :

 
Sélectionnez
typedef struct {
} GClosure;

Bon pas très instructif :( Heureusement en regardant le constructeur de la classe GClosure on retombe sur des choses connues :

 
Sélectionnez
GClosure *g_cclosure_new (GCallback callback_func, gpointer user_data, GClosureNotify destroy_data);

Le dernier paramètre est une fonction qui sera appelée pour détruire l'objet user_data lorsqu'il ne sera plus utilisé.
Voilà nous pouvons déjà connecter le raccourci clavier à notre fonction callback.
Pour finir, pour associer un élément du menu à un raccourci clavier, nous avons besoin de l'ajouter à la carte des raccourcis, cette carte est unique et spécifique à chaque application :

 
Sélectionnez
void gtk_accel_map_add_entry (const gchar *accel_path, guint accel_key, GdkModifierType accel_mods);

Il nous manque juste le paramètre accel_path. Il s'agit, comme son nom le laisse penser, d'un chemin pour notre raccourci. Ce chemin est semblable à un chemin de fichier : "<WINDOWTYPE>/Category1/Category2/.../Action" où WINDOWTYPE est un identifiant spécifique à chaque application, pour notre application, nous utiliserons EditeurGTK, ensuite la documentation de GTK+ conseille, pour les éléments du menu, d'utiliser son chemin, par exemple pour l'élément Nouveau : "Fichier/Nouveau" ce qui nous donne : "<EditeurGTK>/Fichier/Nouveau". Comme il va être nécessaire de reprendre ces chemins lors de la création des éléments du menu, il est préférable d'en faire des constantes :

raccourcis.h
Sélectionnez
#define ACCEL_PATH_NEW "<EditeurGTK>/Fichier/Nouveau"
#define ACCEL_PATH_OPEN "<EditeurGTK>/Fichier/Ouvrir"
#define ACCEL_PATH_SAVE "<EditeurGTK>/Fichier/Enregistrer"
#define ACCEL_PATH_SAVEAS "<EditeurGTK>/Fichier/Enregistrer sous"
#define ACCEL_PATH_CLOSE "<EditeurGTK>/Fichier/Fermer"
#define ACCEL_PATH_QUIT "<EditeurGTK>/Fichier/Quitter"

Avant de créer nos raccourcis, il faut régler un problème (sur ce point je trouve que GTK+ est mal fait), en effet il est précisé que la fonction callback pour les raccourcis doit avoir la signature suivante :

 
Sélectionnez
gboolean (*GtkAccelGroupActivate) (GtkAccelGroup *accel_group, GObject *acceleratable, guint keyval, GdkModifierType modifier);

Alors que nous avons des fonctions de la forme :

 
Sélectionnez
void callback (GtkWidget *p_widget, gpointer user_data);

On est donc obligé de créer des fonctions de type GtkAccelGroupActivate qui vont se charger d'appeler nos fonctions callback :

raccourcis.c
Sélectionnez
static gboolean accel_new (GtkAccelGroup *accel_group, GObject *acceleratable, guint keyval, GdkModifierType modifier, gpointer user_data)
{
  cb_new (NULL, user_data);
  return TRUE;
}

Notre fonction n'a pas la même signature que les GtkAccelGroupActivate puisque g_cclosure_new précise qu'il appelle la fonction callback ainsi créée avec user_data comme dernier paramètre.

Maintenant que le problème est résolu, créons nos raccourcis :

raccourcis.c
Sélectionnez
  accelerator_new (p_accel_group, "<Control>N", ACCEL_PATH_NEW, G_CALLBACK (accel_new), user_data);
  accelerator_new (p_accel_group, "<Control>O", ACCEL_PATH_OPEN, G_CALLBACK (accel_open), user_data);
  accelerator_new (p_accel_group, "<Control>S", ACCEL_PATH_SAVE, G_CALLBACK (accel_save), user_data);
  accelerator_new (p_accel_group, "<Control><Shift>S", ACCEL_PATH_SAVEAS, G_CALLBACK (accel_saveas), user_data);
  accelerator_new (p_accel_group, "<Control>W", ACCEL_PATH_CLOSE, G_CALLBACK (accel_close), user_data);
  accelerator_new (p_accel_group, "<Control>Q", ACCEL_PATH_QUIT, G_CALLBACK (accel_quit), user_data);

Pour finir, il faut ajouter le GtkAccelGroup à notre fenêtre principale :

raccourcis.c
Sélectionnez
  gtk_window_add_accel_group (docs.p_main_window, p_accel_group);

Voilà, nous en avons fini avec ce fichier, maintenant il faut revenir à menu.c pour associer les raccouris aux éléments du menu. Il nous suffit de modifier notre constructeur de GtkMenuItem pour qu'il prenne en argument le accel_path :

menu.c
Sélectionnez
static void menu_item_new (GtkMenu *p_menu, const gchar *title, const gchar *accel_path, GCallback callback, gpointer user_data)
{
  /* ... */
  gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item), accel_path);
}

Et d'utiliser nos constantes lors de l'appel à la fonction meni_item_new :

menu.c
Sélectionnez
    menu_item_new (GTK_MENU (p_menu), "_Nouveau", ACCEL_PATH_NEW, G_CALLBACK (cb_new), user_data);

XIV-C. Code source


précédentsommairesuivant

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2006-2008 Nicolas Joseph. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.