Les widgets III : barres et menus

Reprenons notre chemin dans la forêt des widgets. Nous ne pourrons pas tous les voir mais je sais que vous attendez avec impatience de pouvoir ajouter des menus ou des barres d'icônes à vos programmes. Ce sera donc le cœur de ce troisième et dernier chapitre sur les widgets. Cela ne signifie pas que nous aurons tout vu, loin de là, mais nous aurons alors effectué un large tour des possibilités offertes par GTK.

La barre de menu

Créer une barre de menu

Fiche d'identité

  • Widget : GTK_Menu_Bar
  • Package : Gtk.Menu_Bar et Gtk.Menu_Shell
  • Descendance : GTK_Widget >> GTK_Container >> GTK_Menu_Shell
  • Description : La GTK_Menu_Bar est simplement la barre dans laquelle nous placerons nos divers menus. Sur la figure suivante, vous pouvez observer une barre de menu un peu vide et… sans menus.

La barre des menus

Le package GTK.Menu_Bar ne contient que très peu de méthodes ; je vous invite donc à jeter un œil au package GTK.Menu_Shell dont hérite GTK.Menu_Bar.

Quelques méthodes et un exemple

Le constructeur des GTK_Menu_Bar est simplissime et ne demande aucun paramètre. La seule méthode définie spécifiquement pour les GTK_Menu_Bar est la suivante :

1
2
3
4
procedure Set_Pack_Direction(Menubar  : access Gtk_Menu_Bar_Record;
                             Pack_Dir : Gtk.Enums.Gtk_Pack_Direction);
function Get_Pack_Direction (Menubar : access Gtk_Menu_Bar_Record) 
                             return Gtk.Enums.Gtk_Pack_Direction;

C'est elle qui indiquera comment seront classés vos menus : de gauche à droite, de haut en bas… Les valeurs possibles pour le paramètre Pack_Dir sont :

  • Pack_Direction_LTR : classement de gauche à droite (Left To Right)
  • Pack_Direction_RTL : classement de droite à gauche(Right To Left)
  • Pack_Direction_TTB : classement de haut en bas (Top To Bottom)
  • Pack_Direction_BTT : classement de bas en haut (Bottom To Top)

Avec ceci nous pouvons dors et déjà créer une fenêtre contenant une barre de menu :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
WITH Gtk.Main ;                   USE Gtk.Main ;
WITH Gtk.Window ;                 USE Gtk.Window ;
WITH Gtk.Menu_Bar ;               USE Gtk.Menu_Bar ;
WITH Gtk.Enums ;                  USE Gtk.Enums ;

PROCEDURE MesMenus IS
   Win          : GTK_Window ; 
   Barre        : GTK_Menu_Bar ; 
BEGIN
   Init ; 
      --Création de la fenêtre
   Gtk_New(Win) ;
   Win.Set_Default_Size(250,25) ;
   Win.Set_Title("Mes menus") ;

      --Création de la barre de menu
   Gtk_New(Barre) ; 
   Barre.set_pack_direction(Pack_Direction_LTR) ;   --cette ligne est superflue car par défaut, 
                                                    --GTK oriente le menu de gauche à droite
   Win.Add(Barre) ; 

      --Finalisation
   Win.Show_All ; 
   Main ; 
END MesMenus ;

Nous obtenons ainsi la barre de menu vide présentée en introduction. Pour plus de méthodes, il faudra fouiller le package Gtk.Menu_Shell. Voici quelques-unes qui nous serviront :

1
2
3
4
5
6
7
procedure Append (Menu_Shell : access Gtk_Menu_Shell_Record;
                  Child      : access Gtk_Menu_Item_Record'Class);
procedure Prepend(Menu_Shell : access Gtk_Menu_Shell_Record;
                  Child      : access Gtk_Menu_Item_Record'Class);
procedure Insert (Menu_Shell : access Gtk_Menu_Shell_Record;
                  Child      : access Gtk_Menu_Item_Record'Class;
                  Position   : Gint);

Voila des noms qui devraient vous parler désormais : Append() ajoute à la fin, Prepend() ajoute au début et Insert() ajoute à la position indiquée. Oui mais qu'ajoutent-elles ces méthodes ? Si vous avez observé leurs spécifications, vous avez du remarquer qu'elles permettent d'ajouter des GTK_Menu_Item.

Qu'est-ce que c'est que ça encore ? :( Et puis j'aimerais que ma barre ne soit plus vide svp.

Ça tombe bien, car les GTK_Menu_Item sont justement les widgets qui vont remplir notre barre.

Créer et ajouter des items

Fiche d'identité

  • Widget : GTK_Menu_Item
  • Package : Gtk.Menu_Item
  • Descendance : GTK_Widget >> GTK_Container >> GTK_Bin >> GTK_Item
  • Description : Ce sont des sortes de cases cliquables contenant du texte et que nous allons insérer dans notre GTK_Menu_Bar (voir la figure suivante).

Une GTK_Menu_Bar contenant un GTK_Menu_Item

Retour sur notre exemple

Pour obtenir la barre ci-dessus, vous allez devoir créer un GTK_Menu_Item et l'ajouter à votre barre à l'aide de l'une des trois méthodes Append(), Prepend() et Insert(). Voici la spécification du constructeur :

1
procedure Gtk_New(Menu_Item : out Gtk_Menu_Item; Label : UTF8_String := "");

Et voici ce que donnerait notre code :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
WITH Gtk.Main ;                   USE Gtk.Main ;
WITH Gtk.Window ;                 USE Gtk.Window ;
WITH Gtk.Menu_Bar ;               USE Gtk.Menu_Bar ;
WITH Gtk.Menu_Item ;              USE Gtk.Menu_Item ;
WITH Gtk.Enums ;                  USE Gtk.Enums ;

PROCEDURE MesMenus IS
   Win          : GTK_Window ; 
   Barre        : GTK_Menu_Bar ; 
   Item_Fichier : Gtk_Menu_Item ;
BEGIN
   Init ; 
      --Création de la fenêtre
   Gtk_New(Win) ;
   Win.Set_Default_Size(250,25) ;
   Win.Set_Title("Mes menus") ;

      --Création de la barre de menu
   Gtk_New(Barre) ; 
   Win.Add(Barre) ; 

      --Création de l'item Fichier
   Gtk_New(Item_Fichier,"Fichier") ; 
   Barre.Append(Item_Fichier) ; 

      --Finalisation
   Win.Show_All ; 
   Main ; 
END MesMenus ;

Ça y est. Ma barre n'est plus vide ! :D Mais… mais cette fois c'est le menu fichier qui est vide ! :colere:

Erreur ! Le menu Fichier n'est pas vide : il n'existe pas ! Tout ce que vous avez fait pour l'instant, c'est ajouter du texte à votre barre. Il vous reste une dernière étape : créer un menu déroulant. Mais avant cela, jetons tout de même un rapide coup d’œil aux méthodes disponibles :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
procedure Gtk_New_With_Mnemonic(Menu_Item : out Gtk_Menu_Item;
                                Label     : UTF8_String);

procedure Set_Label(Menu_Item : access Gtk_Menu_Item_Record;
                    Label     : String);
function Get_Label (Menu_Item : access Gtk_Menu_Item_Record)
                    return String;

procedure Set_Use_Underline(Menu_Item : access Gtk_Menu_Item_Record;
                            Setting   : Boolean);
function Get_Use_Underline (Menu_Item : access Gtk_Menu_Item_Record)
                            return Boolean;

Ces méthodes devraient vous dire quelque chose désormais puisque nous les avons déjà vues lors des chapitres sur les étiquettes, les boutons ou les extenseurs. Elles vous permettront de redéfinir le texte de votre GTK_Item ou d'utiliser des caractères soulignés (pratique si vous voulez créer des raccourcis claviers). Mais comme votre priorité est d'ajouter un menu à votre item, voici les méthodes qu'il vous faut :

1
2
3
4
procedure Set_Submenu(Menu_Item : access Gtk_Menu_Item_Record;
                      Submenu   : access Gtk_Widget_Record'Class);
function Get_Submenu (Menu_Item : access Gtk_Menu_Item_Record) 
                      return Gtk_Widget;

Créer et ajouter un menu déroulant

Pour finaliser notre barre de menu, nous avons besoin d'un ultime widget : GTK_Menu.

Fiche d'identité

  • Widget : GTK_Menu
  • Package : Gtk.Menu
  • Descendance : GTK_Widget >> GTK_Container >> GTK_Menu_Shell
  • Description : Ce widget est un menu déroulant pouvant contenir plusieurs items (voir la figure suivante).

Avec un menu déroulant

Terminons notre exemple

Nous allons achever notre barre de menu. Pour cela nous allons :

  1. créer un GTK_Menu ;
  2. l'attacher au GTK_Menu_Item que nous avons appelé Item_Fichier à l'aide de la méthode Set_Submenu() vue précédemment ;
  3. lui ajouter deux items : Ouvrir et Fermer.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
WITH Gtk.Main ;                   USE Gtk.Main ;
WITH Gtk.Window ;                 USE Gtk.Window ;
WITH Gtk.Menu_Bar ;               USE Gtk.Menu_Bar ;
WITH Gtk.Menu ;                   USE Gtk.Menu ;
WITH Gtk.Menu_Item ;              USE Gtk.Menu_Item ;


PROCEDURE MesMenus IS
   Win          : GTK_Window ; 
   Barre        : GTK_Menu_Bar ; 
   Menu_Fichier : Gtk_Menu ; 
   Item_Fichier : Gtk_Menu_Item ;
   Item_Ouvrir  : Gtk_Menu_Item ;
   Item_Fermer  : Gtk_Menu_Item ;
BEGIN
   Init ; 
      --Création de la fenêtre
   Gtk_New(Win) ;
   Win.Set_Default_Size(250,25) ;
   Win.Set_Title("Mes menus") ;

      --Création de la barre de menu
   Gtk_New(Barre) ; 
   Win.Add(Barre) ; 

      --Création de l'item Fichier
   Gtk_New(Item_Fichier,"Fichier") ; 
   Barre.Append(Item_Fichier) ; 

      --Création du menu Fichier
   Gtk_New(Menu_Fichier) ; 
   Item_Fichier.Set_Submenu(Menu_Fichier) ; 

      --Création de l'item Ouvrir
   Gtk_New(Item_Ouvrir,"Ouvrir") ; 
   Menu_Fichier.append(Item_Ouvrir) ; 

      --Création de l'item Fermer
   Gtk_New(Item_Fermer,"Fermer") ; 
   Menu_Fichier.Append(Item_Fermer) ; 

      --Finalisation
   Win.Show_All ; 
   Main ; 

END MesMenus ;

Désormais, vous n'avez plus qu'à connecter les GTK_Item à vos callbacks. Pour cela, vous aurez besoin du signal suivant : Signal_Activate ou "activate". Celui-ci est émis dès lors que vous cliquez sur un item.

Améliorer la barre de menu

Vous connaissez désormais les rudiments nécessaires pour créer une barre de menu. Comme je ne cesse de le répéter depuis le début de la partie V, n'hésitez pas à ouvrir et lire les fichiers ads. Vous y trouverez toutes les méthodes disponibles ainsi que des commentaires généralement exhaustifs. Dans cette partie, nous allons voir comment améliorer nos menus à partir de ce que nous savons déjà ou à l'aide de nouveaux widgets.

Créer un menu en image

GTK est livré avec toute une batterie d'images permettant d'égayer vos menus et boutons. Vous pouvez par exemple obtenir un menu comme celui-ci :

Menus avec icônes

Si vous êtes tentés, rien de plus simple. Abandonnez les GTK_Menu_Item au profit du widget fils : Gtk_Image_Menu_Item. Vous aurez deux possibilités pour créer vos items en image :

  1. Le créer comme précédemment puis lui ajouter une image.
  2. Utiliser une image prédéfinie de GTK.

Méthode artisanale

Dans le premier cas, utilisez GTK_New() comme vous saviez le faire puis créez une image avec un GTK_Image. Il vous suffit ensuite d'attribuer l'image à votre item à l'aide de la méthode Set_Image() :

1
2
3
4
procedure Set_Image(Menu_Item : access Gtk_Image_Menu_Item_Record;
                    Image     : access Gtk_Widget_Record'Class);
function Get_Image (Menu_Item : access Gtk_Image_Menu_Item_Record)
                    return Gtk_Widget;

Méthode pour ne pas réinventer la roue

Mais la solution de facilité est de faire appel au stock d'images intégrées dans le thème visuel de GTK. C'est très simple, il suffit d'utiliser la méthode Gtk_New_From_Stock() à la place de GTK_New() :

1
2
procedure Gtk_New_From_Stock(Widget   : out Gtk_Image_Menu_Item;
                             Stock_Id : String);

Stock_Id indique le nom de l'image et du texte à afficher. Ces noms sont normés et commencent généralement par "gtk-". Vous trouverez la liste des valeurs possibles pour Stock_Id dans le package Gtk.Stock. Pour notre menu Ouvrir, nous utiliserons "gtk-open" et pour Fermer, ce sera "gtk-close".

C'est bien sympa tout ça mais je me retrouve avec des menus en Anglais?! :(

Souvenez-vous que les GTK_Image_Menu_Item dérivent des GTK_Menu_Item et qu'ils héritent donc de leurs méthodes. Vous pourrez donc les renommer avec :

1
2
procedure Set_Label(Menu_Item : access Gtk_Menu_Item_Record;
                    Label     : String);

Créer un sous-menu

Je voulais créer un sous-menu pour la sauvegarde car je prévois deux formats différents pour enregistrer mes documents. Comment faire ?

Vous n'avez besoin de rien de plus que ce que vous connaissez déjà. Tout d'abord, ajoutons un nouvel Item pour la sauvegarde :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
...
WITH Gtk.Image_Menu_Item ;        USE Gtk.Image_Menu_Item ;


PROCEDURE MesMenus IS
      ...
   Item_Sauver  : Gtk_Image_Menu_Item ;
BEGIN
      ...

      --Création de l'item Sauver
   Gtk_New_From_Stock(Item_Sauver,"gtk-save-as") ; 
   Item_Sauver.set_label("Enregistrer au format") ; 
   Menu_Fichier.Append(Item_Sauver) ; 

      ...
END MesMenus ;

Puis, nous allons créer un second Gtk_Menu que nous ajouterons à l'item que nous venons de faire. Il ne restera plus qu'à y ajouter deux nouveaux items :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
WITH Gtk.Main ;                   USE Gtk.Main ;
WITH Gtk.Window ;                 USE Gtk.Window ;
WITH Gtk.Menu_Bar ;               USE Gtk.Menu_Bar ;
WITH Gtk.Menu ;                   USE Gtk.Menu ;
WITH Gtk.Menu_Item ;              USE Gtk.Menu_Item ;
WITH Gtk.Image_Menu_Item ;        USE Gtk.Image_Menu_Item ;


PROCEDURE MesMenus IS
   Win          : GTK_Window ; 
   Barre        : GTK_Menu_Bar ; 
   Menu_Fichier : Gtk_Menu ; 
   Menu_Sauver  : Gtk_Menu ;
   Item_Fichier : Gtk_Menu_Item ;
   Item_Ouvrir  : Gtk_Image_Menu_Item ;
   Item_Fermer  : Gtk_Image_Menu_Item ;
   Item_Sauver  : Gtk_Image_Menu_Item ;
   Item_Format1 : Gtk_Menu_Item ;
   Item_Format2 : Gtk_Menu_Item ;
BEGIN
   Init ; 
      --Création de la fenêtre
   Gtk_New(Win) ;
   Win.Set_Default_Size(250,25) ;
   Win.Set_Title("Mes menus") ;

      --Création de la barre de menu
   Gtk_New(Barre) ; 
   Win.Add(Barre) ; 

      --Création de l'item Fichier
   Gtk_New(Item_Fichier,"Fichier") ; 
   Barre.Append(Item_Fichier) ; 

      --Création du menu Fichier
   Gtk_New(Menu_Fichier) ; 
   Item_Fichier.Set_Submenu(Menu_Fichier) ; 

      --Création de l'item Ouvrir
   Gtk_New_From_Stock(Item_Ouvrir,"gtk-open") ; 
   Item_Ouvrir.set_label("Ouvrir") ; 
   Menu_Fichier.append(Item_Ouvrir) ; 

      --Création de l'item Fermer
   Gtk_New_From_Stock(Item_Fermer,"gtk-close") ; 
   Item_Fermer.set_label("Fermer") ; 
   Menu_Fichier.Append(Item_Fermer) ; 

      --Création de l'item Sauver
   Gtk_New_From_Stock(Item_Sauver,"gtk-save-as") ; 
   Item_Sauver.set_label("Enregistrer au format") ; 
   Menu_Fichier.Append(Item_Sauver) ; 

      --Création du sous-menu
   Gtk_New(Menu_Sauver) ; 
   Item_Sauver.Set_Submenu(Menu_Sauver) ; 

      --Création de l'item de format n°1
   Gtk_New(Item_Format1,"*.truc") ; 
   Menu_Sauver.append(Item_Format1) ; 

      --Création de l'item de format n°2
   Gtk_New(Item_Format2,"*.bidule") ; 
   Menu_Sauver.append(Item_Format2) ; 

      --Finalisation
   Win.Show_All ; 
   Main ; 
END MesMenus ;

Un sous-menu pour enregistrer sous différent formats

Proposer un item à cocher dans le menu

Je souhaite proposer une option "Afficher le score" dans mon menu que le joueur pourrait cocher ou décocher. Comment faire ?

Encore une fois, rien de plus simple. Nous allons faire appel au widget Gtk_Check_Menu_Item au lieu de Gtk_Menu_Item. Il s'agit d'un type dérivé bien entendu ce qui nous permettra de réutiliser les méthodes du père. Voici ce que cela pourrait donner :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
...
WITH Gtk.Check_Menu_Item ;        USE Gtk.Check_Menu_Item ;


PROCEDURE MesMenus IS
      ...
   Item_Afficher   : Gtk_Check_Menu_Item ; 
BEGIN
      ...
      --Création de l'item Afficher score
   Gtk_New(Item_Afficher,"Afficher le score") ; 
   Menu_Fichier.append(Item_Afficher) ; 
      ...   
END MesMenus ;

Admirez le dernier item du menu : une case à cocher ! (Voir la figure suivante.)

Insérer une case à cocher

Dans le package Gtk.Check_Menu_Item, vous trouverez la plupart des méthodes additionnelles, mais voici celles qui vous seront essentielles :

1
2
3
procedure Set_Active(Check_Menu_Item : access Gtk_Check_Menu_Item_Record;
                     Is_Active       : Boolean);
function Get_Active (Check_Menu_Item : access Gtk_Check_Menu_Item_Record) return Boolean;

Avec Set_Active(), vous pourrez cocher ou décocher votre item, tandis qu'avec Get_Active(), vous pourrez connaître son état. Enfin, chaque fois que l'utilisateur coche ou décoche votre item, le signal Signal_Toggled ou "toggled" est émis.

Vous aurez compris que les items à cocher (Gtk_Check_Menu_Item) sont très similaires aux boutons à cocher (Gtk_Check_Button) vus au chapitre 5. De la même manière, il existe des items radio, semblables aux boutons radio (Gtk_Radio_Button). Ils s'appellent tout simplement Gtk_Radio_Menu_Item.

Organiser vos menus

Lorsque vos menus commenceront à devenir volumineux, il sera judicieux d'utiliser des séparateurs pour que l'utilisateur visualise rapidement les groupes logiques d'item. Aussi aurez-vous besoin du widget Gtk_Separator_Menu_Item. Vous constaterez, sur la figure ci-dessous, la présence d'un petit trait séparant l'item "Afficher le score" des trois autres items.

Un Item de séparation pour organiser le menu.

La barre d'icônes

Fiches d'identité

Pour réaliser une barre d'icônes, nous aurons besoin des deux widgets GTK_Toolbar et GTK_Tool_Button. On retrouve ainsi une architecture semblable aux barres de menu : une barre servant de conteneur et des objets à y insérer.

Fiche d'identité des GTK_Toolbar

  • Widget : GTK_Toolbar
  • Package : GTK.Toolbar
  • Descendance : GTK_Widget >> GTK_Container
  • Description : La GTK_Toolbar est la barre dans laquelle nous placerons nos icônes.

Fiche d'identité des GTK_Tool_Button

  • Widget : GTK_Tool_Button
  • Package : GTK.Tool_Button
  • Descendance : GTK_Widget >> GTK_Container >> GTK_bin >> GTK_Tool_Item
  • Description : Les GTK_Tool_Button sont les boutons des icônes à insérer.

Créer notre barre d'icônes

Les méthodes élémentaires

Comme toujours, vous devez commencer par construire la barre à l'aide de la méthode :

1
procedure Gtk_New (Widget : out Gtk_Toolbar);

Puis vous devrez construire votre icône avec les méthodes GTK_New() ou GTK_New_From_Stock() :

1
2
3
4
5
procedure Gtk_New(Button      : out Gtk_Tool_Button;
                  Icon_Widget : Gtk.Widget.Gtk_Widget := null;
                  Label       : String := "");
procedure Gtk_New_From_Stock(Button   : out Gtk_Tool_Button;
                             Stock_Id : String);

En revanche, pour ajouter un icône à la barre, vous ne disposerez plus de méthode Append() ou Prepend() (celles-ci étant obsolètes). Vous devrez donc utiliser la méthode :

1
2
3
procedure Insert(Toolbar : access Gtk_Toolbar_Record;
                 Item    : access Gtk_Tool_Item_Record'Class;
                 Pos     : Gint := -1);

Si le paramètre Pos vaut 0, votre icône sera placé en première position, s'il vaut 1 en deuxième position… Et si vous n'avez aucune idée de l'endroit où cet icône doit être situé, donnez -1 comme position : GTK le placera en bout de liste.

Exemple

Pour mieux comprendre, rien de tel qu'un exemple. Nous allons construire un programme comportant une barre d'icône et deux icônes. Le code ci-dessous devrait être suffisamment simple et commenté pour que vous le déchiffriez seuls :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
WITH Gtk.Main ;                   USE Gtk.Main ;
WITH Gtk.Window ;                 USE Gtk.Window ;
WITH Gtk.Toolbar ;                USE Gtk.Toolbar ;
WITH Gtk.Tool_button ;            USE Gtk.Tool_button ; 


PROCEDURE MesMenus IS
   Win             : GTK_Window ;
   Barre           : Gtk_Toolbar ; 
   Icon_Ouvrir     : Gtk_Tool_Button ; 
   Icon_Fermer     : Gtk_Tool_Button ; 
BEGIN
   Init ;
      --Création de la fenêtre
   Gtk_New(Win) ;
   Win.Set_Default_Size(250,25) ;
   Win.Set_Title("Mes menus") ;

      --création barre d'outils
   Gtk_New(Barre) ; 
   Win.add(barre) ; 

      --Création de l'icône ouvrir
   Gtk_New_From_Stock(Icon_Ouvrir,"gtk-open") ; 
   icon_ouvrir.set_label("Ouvrir") ; 
   Barre.Insert(Icon_Ouvrir) ; 

      --Création de l'icône fermer
   Gtk_New_From_Stock(Icon_Fermer,"gtk-close") ; 
   icon_fermer.set_label("Fermer") ; 
   Barre.Insert(Icon_fermer) ; 

      --Finalisation
   Win.Show_All ;
   Main ;
END MesMenus ;

Voici, sur la figure suivante, le résultat en image.

Une barre d'icônes

Pour plus de clarté, les icônes ne sont reliés à aucun callback, mais il est évident que vous devrez connecté chacun d'entre eux à sa méthode. Le signal émis par les GTK_Tool_Button lorsque l'utilisateur clique dessus se nomme Signal_Clicked ou "clicked".

Améliorer les barres d'icônes

D'autres icônes

Existe-t-il d'autres types d'icônes, à la manière des items de menu ?

Bien sûr. Il n'existe pas que les Gtk_Tool_Button, sinon les créateurs de Gtk n'auraient pas créé de classe mère Gtk_Tool_Item. Il existe :

  • des icônes séparateurs pour séparer des groupes d'icônes : les Gtk_Separator_Tool_Item ;
  • des icônes à bascule pour activer ou désactiver un option : les Gtk_Toggle_Tool_Button ;
  • des icônes radio pour choisir entre un groupe d'options : les Gtk_Radio_Tool_Button.

Enfin, il existe un dernier type d'icône. Il s'agit d'icônes ouvrant des menus : les Gtk_Menu_Tool_Button. Pour leur adjoindre un menu, il faudra utiliser la méthode suivante :

1
2
procedure Set_Menu(Button : access Gtk_Menu_Tool_Button_Record;
                   Menu   : access Gtk_Menu_Record'Class);

Ce genre d'icône vous sera très utile si vous comptez créer de nombreux outils pour votre logiciel. Ainsi, pour les logiciels de dessin, les outils de sélection par zone, à main levée et par couleur sont généralement rassemblés sous un même icône de sélection.

Sur la figure suivante, un exemple d'utilisation d'un icône-menu avec le logiciel Paint Shop Pro

Icône-menu sur Paint Shop Pro

Ajouter une info-bulle

Si vous explorez le package Gtk.Tool_Button, vous serez déçus de ne trouver que très peu de méthodes, hormis les éternels (Get/Set)_Label(), (Get/Set)_Icon_Widget(), (Get/Set)_Stock_Id()… permettant d'obtenir ou d'éditer les paramètres essentiels du bouton. Mais en fouillant dans le package père Gtk.Tool_Item, vous trouverez les méthodes suivantes :

1
2
3
4
procedure Set_Tooltip_Text  (Tool_Item : access Gtk_Tool_Item_Record;
                             Text      : UTF8_String);
procedure Set_Tooltip_Markup(Tool_Item : access Gtk_Tool_Item_Record;
                             Markup    : UTF8_String);

Celles-ci permettent de créer des info-bulles pour vos icônes expliquant leur action. La seconde méthode permet même d'utiliser des balises de mise en forme (voir le chapitre sur les étiquettes pour rappel). Et vous n'avez pas besoin de faire appel à ce package puisque par dérivation, les Gtk_Tool_Button héritent de ces méthodes. Exemple :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
WITH Gtk.Main ;                   USE Gtk.Main ;
WITH Gtk.Window ;                 USE Gtk.Window ;
WITH Gtk.Toolbar ;                USE Gtk.Toolbar ;
WITH Gtk.Tool_Button ;            USE Gtk.Tool_Button ; 


PROCEDURE MesIcones IS
   Win             : GTK_Window ;
   Barre           : Gtk_Toolbar ; 
   Icon_Ouvrir     : Gtk_Tool_Button ; 
   Icon_Fermer     : Gtk_Tool_Button ; 
BEGIN
   Init ;
      --Création de la fenêtre
   Gtk_New(Win) ;
   Win.Set_Default_Size(250,25) ;
   Win.Set_Title("Mes menus") ;

      --Création barre d'outils
   Gtk_New(Barre) ; 
   Win.add(barre) ; 

      --Création de l'icône Ouvrir
   Gtk_New_From_Stock(Icon_Ouvrir,"gtk-open") ; 
   Icon_Ouvrir.Set_Label("Ouvrir") ; 
   Icon_Ouvrir.Set_Tooltip_Text("Permet d'ouvrir un document") ; 
   Barre.Insert(Icon_Ouvrir) ; 

      --Création de l'icône Fermer
   Gtk_New_From_Stock(Icon_Fermer,"gtk-close") ; 
   Icon_Fermer.Set_Label("Fermer") ; 
   Icon_Fermer.Set_Tooltip_Markup("<span foreground='red'><b>Ferme</b></span> le document en cours") ; 
   Barre.Insert(Icon_fermer) ; 

      --Finalisation
   Win.Show_All ;
   Main ;
END MesIcones ;

Sur la figure suivante, on constate que lorsque l'icône est survolé par la souris, une info-bulle apparaît.

Une info-bulle avec mise en forme

Améliorez la barre

De nombreuses méthodes liées aux Gtk_Toolbar sont désormais obsolètes, si bien qu'il n'en reste que peu. Mais voici quelques méthodes qui pourraient vous intéresser :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
procedure Set_Orientation(Toolbar     : access Gtk_Toolbar_Record;
                          Orientation : Gtk_Orientation);
function Get_Orientation(Toolbar : access Gtk_Toolbar_Record) return Gtk_Orientation;

procedure Set_Tooltips(Toolbar : access Gtk_Toolbar_Record;
                       Enable  : Boolean);
function Get_Tooltips(Toolbar : access Gtk_Toolbar_Record) return Boolean;

procedure Set_Show_Arrow(Toolbar    : access Gtk_Toolbar_Record;
                         Show_Arrow : Boolean := True);
function Get_Show_Arrow(Toolbar : access Gtk_Toolbar_Record)
                        return Boolean;

Avec Set_Orientation() vous pourrez indiquer si vos icônes sont alignés horizontalement (Orientation vaut alors Orientation_Horizontal) ou verticalement (Orientation_Vertical). Avec Set_Tooltips() vous pourrez autoriser ou non l'affichage des info-bulles ; enfin avec Set_Show_Arrow(), vous pourrez afficher ou non une flèche en bout de barre. Si votre barre contient trop d'icônes, cette flèche vous permettra d'ouvrir un petit menu pour avoir accès aux icône cachés. Cette flèche n'apparaît qu'en cas de besoin et est activée par défaut.

Les barres d'icônes sont aussi appelées barres d'outils. Beaucoup de logiciels permettent de déplacer ces barres d'outil pour les placer en haut, à gauche ou en bas de la fenêtre ou de les en détacher. Pour obtenir cet effet, vous pouvez combinez votre Gtk_Toolbar avec une Gtk_Handle_Box (voir chapitre sur les boîtes détachables).

Combiner menus et icônes

Dans certains logiciels, comme ceux de dessin, les icônes sont essentiels et donnent accès à des outils inatteignables autrement, comme le pinceau ou les outils de sélection. Mais la plupart du temps, ces icônes sont des raccourcis de menus déjà existants. Si nous essayons de combiner la barre de menus et la barre d'icônes que nous venons de créer, nous allons voir apparaître de sacrés doublons ! Il faudra créer un Gtk_Menu_Item et un Gtk_Tool_Button pour ouvrir un document, pour le fermer, pour en créer un nouveau, pour le sauvegarder … sans parler des callbacks qu'il faudra connecter deux fois. Une solution à ce problème est de faire appel aux actions, aussi appelées Gtk_Action.

Fiche d'identité

  • Widget : GTK_Action
  • Package : GTK.Action
  • Descendance : il ne s'agit pas d'un widget. Toutefois il dérive des Gtk_Object, tout comme les Gtk_Widget.
  • Description : définit un objet de type action qui pourra être réutiliser par la suite pour créer un item de menu ou un icône.

Mode d'emploi

L'emploi des actions pourrait être déconcertant, mais vous avez désormais l'expérience suffisante pour les aborder en toute sérénité. La partie la plus complexe est, une fois n'est pas coutume, le constructeur. Celui-ci va cumuler tous les paramètres nécessaires aux icônes et items de menu :

1
2
3
4
5
procedure Gtk_New(Action   : out Gtk_Action;
                  Name     : String;
                  Label    : String;
                  Tooltip  : String := "";
                  Stock_Id : String := "");

Le paramètre Label est le texte qui sera affiché dans le menu ou sous l'icône ; Tooltip correspond au texte qui sera affiché dans l'info-bulle ; Stock_Id est bien entendu le nom de l'image ("gtk-open", "gtk-close"…). Le paramètre Name correspond à un nom que vous devez donner à cette action. Ce nom doit être unique, de même que chaque signal à un nom unique.

La connexion aux callbacks se fait de la même façon que pour les widgets, toutefois faites attention à l'instanciation de vos packages : les actions ne sont pas des widgets ! Il s'agit un type d'objet frère mais distinct ; widgets et actions sont tous deux des Gtk_Object.

Une fois vos actions créées et connectées, leur transformation en menus, en items de menu ou en icônes pourra se faire avec l'une des méthodes suivantes :

1
2
3
4
5
function Create_Menu     (Action : access Gtk_Action_Record) return Gtk_Widget;

function Create_Menu_Item(Action : access Gtk_Action_Record) return Gtk_Widget;

function Create_Tool_Item(Action : access Gtk_Action_Record) return Gtk_Widget;

Toutefois, ces fonctions de conversion transformeront votre action en widget, mais pas spécifiquement en item, menu ou icône. Pour mieux comprendre, reprenons nos codes précédents et réalisons une fenêtre contenant une barre de menu et une barre d'icônes. Nous nous limiterons aux deux actions Ouvrir et Nouveau :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
WITH Gtk.Main ;                   USE Gtk.Main ;
WITH Gtk.Window ;                 USE Gtk.Window ;
WITH Gtk.Box ;                    USE Gtk.Box ; 
WITH Gtk.Menu_Bar ;               USE Gtk.Menu_Bar ;
WITH Gtk.Menu ;                   USE Gtk.Menu ;
WITH Gtk.Menu_Item ;              USE Gtk.Menu_Item ;
WITH Gtk.Toolbar ;                USE Gtk.Toolbar ;
WITH Gtk.Tool_button ;            USE Gtk.Tool_button ; 
WITH Glib.Convert ;               USE Glib.Convert ;
WITH Gtk.Action ;                 USE Gtk.Action ; 



PROCEDURE DoubleMenu IS
   Win             : GTK_Window ;
   Vbox            : Gtk_Vbox ; 
   Barre1          : GTK_Menu_Bar ;
   Barre2          : Gtk_Toolbar ; 
   Menu_Fichier    : Gtk_Menu ;
   Item_Fichier    : Gtk_Menu_Item ;
   Action_Nouveau  : Gtk_Action ; 
   Action_Ouvrir   : Gtk_Action ; 
BEGIN
   Init ;
      --Création de la fenêtre
   Gtk_New(Win) ;
   Win.Set_Default_Size(250,25) ;
   Win.Set_Title("Mes menus") ;

      --Création boîte
   Gtk_New_Vbox(Vbox) ; 
   Win.Add(Vbox) ; 

      --Création de la barre de menu
   Gtk_New(Barre1) ;
   Vbox.pack_start(Barre1) ;

      --Création barre d'icones
   Gtk_New(Barre2) ; 
   Vbox.Pack_Start(Barre2) ; 

      --Création de l'item Fichier
   Gtk_New(Item_Fichier,"Fichier") ;
   Barre1.Append(Item_Fichier) ;

      --Création du menu Fichier
   Gtk_New(Menu_Fichier) ;
   Item_Fichier.Set_Submenu(Menu_Fichier) ;

      --Création de l'action ouvrir
   Gtk_new(Action_Ouvrir,"action-open","Ouvrir","Ouvre un document existant","gtk-open") ; 
   Menu_Fichier.Append(GTK_Menu_item(Action_Ouvrir.Create_Menu_Item)) ; 
   Barre2.insert(gtk_tool_button(Action_Ouvrir.Create_Tool_Item)) ; 

      --Création de l'action nouveau
   Gtk_new(Action_nouveau,"action-new","Nouveau",locale_to_utf8("Crée un nouveau document"),"gtk-new") ; 
   Menu_Fichier.Append(GTK_Menu_item(Action_Nouveau.Create_Menu_Item)) ; 
   Barre2.insert(gtk_tool_button(Action_nouveau.Create_Tool_Item)) ; 

      --Finalisation
   Win.Show_All ;
   Main ;

END DoubleMenu ;

Comme vous pouvez le constater, pour créer deux items de menu et deux icônes (soit quatre widgets), je n'ai eu besoin que de deux actions (et il n'aurait fallu que deux connexions de callback au lieu de quatre, non écrits par soucis de clarté). J'attire toutefois votre attention sur les lignes 52,53,57 et 58 :

1
2
Menu_Fichier.Append(GTK_Menu_item(Action_Ouvrir.Create_Menu_Item)) ; 
Barre2.insert(gtk_tool_button(Action_Ouvrir.Create_Tool_Item)) ;
1
2
Menu_Fichier.Append(GTK_Menu_item(Action_Nouveau.Create_Menu_Item)) ; 
Barre2.insert(gtk_tool_button(Action_nouveau.Create_Tool_Item)) ;

Aux lignes 52 et 57, j'ajoute au menu Fichier mes deux actions que je convertis en widget grâce à Create_Menu_Item(). Toutefois, la méthode Append() n'attend pas un Gtk_Widget mais un Gtk_Menu_Item ! C'est pourquoi il faut effectuer une conversion supplémentaire. Le phénomène est le même aux lignes 53 et 58 où j'ai convertis les actions en widget grâce à Create_Tool_Item() puis en icône avec gtk_tool_button().

La barre de statut

Fiche d'identité

  • Widget : GTK_Status_Bar
  • Package : GTK.Status_Bar
  • Descendance : GTK_Widget >> GTK_Container >> GTK_Box >> GTK_Hbox
  • Description : La barre de statut (ou barre d'état) affiche des informations en continu pour l'utilisateur. Elle est généralement située au bas de la fenêtre.

Sur la figure suivante, au survol du second bouton, la barre de statut affiche «C'est le bouton 2»

La barre d'état

Méthodes et fonctionnement

Méthodes pour l'apparence

Les barres de statut disposent de très peu de méthodes propres. Voici celles concernant l'apparence :

1
2
3
4
5
6
7
function Get_Has_Resize_Grip(Statusbar : access Gtk_Status_Bar_Record) return Boolean;
procedure Set_Has_Resize_Grip(Statusbar : access Gtk_Status_Bar_Record;
                              Setting   : Boolean);

function Get_Orientation (Self : access Gtk_Status_Bar_Record) return Gtk.Enums.Gtk_Orientation;
procedure Set_Orientation(Self        : access Gtk_Status_Bar_Record;
                          Orientation : Gtk.Enums.Gtk_Orientation);

La méthode Set_Resize_Grip() vous permet d'indiquer si la barre contient ou non un petit carré à droite pour redimensionner la fenêtre. Par défaut, ce carré est affiché. Je ne m'attarde plus sur les méthodes Get_Orientation() et Set_Orientation() que nous avons vues et revues (retournez à la partie précédente sur la barre d'icônes si vous avez déjà oublié).

Fonctionnement

Mais le but d'une barre d'état est avant tout d'afficher des messages. Alors vous devez d'abord comprendre comment sont gérés ces messages. À chaque fois que vous souhaitez afficher un message, vous devrez l'ajouter à la liste de messages de la GTK_Status_Bar. Celle-ci lui attribuera un numéro d'identification de message, qui n'est autre qu'un entier de type Message_Id. Mais ce n'est pas tout ! Vous devrez également fournir, en plus de la chaîne de caractères, un numéro d'identification de contexte qui est également un entier, mais de type Context_Id. Ce nouveau numéro d'identification permet de classer les messages selon leur «contexte» : les messages d'erreurs porteront par exemple le numéro 0 et les messages d'aide le numéro 1.

Cet identifiant nous sera inutile car nous ne pousserons pas la difficulté si loin mais nous devons tout de même le fournir et nous en souvenir car il nous sera demandé lorsque nous souhaiterons retirer notre dernier message. En effet, la liste de messages fonctionne à la manière d'une liste de piles (voire chapitre sur les TAD) : pour retirer un message, vous fournissez le Context_Id et GTK retire de la pile correspondante le dernier message posté.

Sur la figure suivante, la représentation de la liste des messages dans une GTK_Status_Bar.

La GTK_Status_Bar

Sur le schéma précédent, on peut deviner l'ordre d'arrivée des messages et leur classement :

  1. Ajout du message n°0 dans le Context_Id n°0
  2. Ajout du message n°1 dans le Context_Id n°1
  3. Ajout du message n°2 dans le Context_Id n°2
  4. Ajout du message n°3 dans le Context_Id n°2
  5. Ajout du message n°4 dans le Context_Id n°1
  6. Ajout du message n°5 dans un Context_Id inconnu
  7. Suppression du message n°5
  8. Ajout du message n°6 dans le Context_Id n°1

Le message affiché en ce moment est donc le n°6, c'est le plus vieux. S'il était supprimé, ce serait le 4, toujours dans le Context_Id n°1, puis le 3 et ainsi de suite.

Méthodes essentielles

Venons-en maintenant aux méthodes :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
function Push(Statusbar : access Gtk_Status_Bar_Record;
              Context   : Context_Id;
              Text      : UTF8_String) return Message_Id;
procedure Pop(Statusbar : access Gtk_Status_Bar_Record;
              Context   : Context_Id);
procedure Remove(Statusbar : access Gtk_Status_Bar_Record;
                 Context   : Context_Id;
                 Message   : Message_Id);
procedure Remove_All(Statusbar : access Gtk_Status_Bar_Record;
                     Context   : Context_Id);

Si vous vous souvenez du chapitre sur les piles, les noms de ces procédures devraient vous sembler familiers : Push() ajoute un message à une pile ; Pop() retire l'élément au sommet d'une pile ; Remove() permet de supprimer un message précis d'une pile précise ; Remove_all() vide toute une pile. Vous remarquerez que toutes ces méthodes exigent un Context_Id, c'est-à-dire le numéro de la pile désirée. De plus, faites attention car Push() n'est pas une procédure mais une fonction qui renvoie le numéro du message créé (nécessaire si vous souhaitez utiliser Remove()).

Exemples d'utilisation

Exemple basique

Contrairement aux autres widgets, je vais devoir vous présenter les barres de statut avec quelques callbacks, sans quoi cela n'aurait aucun intérêt. Voici donc le code écrit pour réaliser la fenêtre d'exemple contenant deux boutons et une barre d'état :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
WITH Gtk.Main ;                   USE Gtk.Main ;
WITH Gtk.Window ;                 USE Gtk.Window ;
WITH Gtk.Box ;                    USE Gtk.Box ; 
WITH Gtk.Button ;                 USE Gtk.button ;
WITH Glib.Convert ;               USE Glib.Convert ;
WITH Gtk.Status_Bar ;             USE Gtk.Status_Bar ;
WITH Gtk.Handlers ; 


PROCEDURE MaBarreDeStatut IS

      --Objets
   Win         : GTK_Window ;
   Vbox        : Gtk_Vbox ;
   Barre       : GTK_Status_Bar ;
   Btn1, Btn2  : Gtk_Button ;
   Msg0        : Message_Id ;

      --Type nécessaire aux callbacks
   TYPE T_Data IS RECORD
      Barre : GTK_Status_Bar ;
      Id    : Integer ;
   END RECORD ; 

      --Packages
   PACKAGE P_Callback IS NEW Gtk.Handlers.User_Callback(Gtk_Button_Record,T_Data) ;
   USE P_Callback ; 

      --Callbacks
   PROCEDURE Active_Barre(Emetteur : ACCESS Gtk_Button_Record'Class ; 
                          Data     : T_Data) IS
      PRAGMA Unreferenced(Emetteur) ; 
      Msg1 : Message_Id ; 
   BEGIN
      CASE Data.Id IS
         WHEN 1 => Msg1 := Data.Barre.Push(1,"C'est le bouton 1") ; 
         WHEN 2 => Msg1 := Data.Barre.Push(1,"C'est le bouton 2") ; 
         WHEN OTHERS => NULL ; 
      END CASE ;  
   END Active_Barre ; 

   PROCEDURE Desactive_Barre(Emetteur : ACCESS Gtk_Button_Record'Class ; 
                             Data     : T_Data) IS
      PRAGMA Unreferenced(Emetteur) ; 
   BEGIN
      Data.Barre.Pop(1) ; 
   END Desactive_Barre ;

BEGIN
   Init ;
      --Création de la fenêtre
   Gtk_New(Win) ;
   Win.Set_Default_Size(250,300) ;
   Win.Set_Title("Ma barre de statut") ;

      --Création de la boîte
   Gtk_New_Vbox(Vbox) ;
   Win.Add(Vbox) ;

      --Création de la barre de statut
   Gtk_New(Barre) ;
   Msg0 := Barre.Push(0,"Passez le curseur sur un bouton") ; 
   Vbox.pack_end(Barre, expand => false) ;

      --Création des boutons
   Gtk_New(Btn1,"Premier bouton") ;
   Connect(Btn1,"enter", Active_Barre'ACCESS, (Barre,1)) ;
   Connect(Btn1,"leave", Desactive_Barre'ACCESS, (Barre,1)) ;
   Vbox.Pack_Start(Btn1) ; 

   Gtk_New(Btn2,Locale_To_Utf8("Deuxième bouton")) ;
   Connect(Btn2,"enter", Active_Barre'ACCESS, (Barre,2)) ;
   Connect(Btn2,"leave", Desactive_Barre'ACCESS, (Barre,2)) ;
   Vbox.Pack_Start(Btn2) ;

      --Finalisation
   Win.Show_All ;
   Main ;

END MaBarreDeStatut ;

Pour chaque bouton, j'effectue deux connexions. Pour le signal "enter" (émis lorsque la souris entre dans le bouton) je déclenche le callback Active_Barre() qui affiche un message particulier ; pour le signal "leave" (émis lorsque la souris quitte le bouton) je déclenche le callback Desactive_Barre() qui efface le message écrit. Le premier callback utilise la méthode push(), le second utilise pop(). Ainsi, les messages concernant les boutons n'apparaissent que si la souris est au-dessus et disparaissent sinon.

Une petite amélioration

Une barre de statut, c'est bien gentil mais ça n'est pas fondamental : tant de travail pour un tout petit message en bas ! Est-ce si utile ?

J'admets que c'est du fignolage. Mais une barre d'état peut être plus utile que vous ne le pensez. Si vous avez été attentifs à la fiche d'identité, vous avez du (ou vous auriez du) remarquer une bizarrerie : les GTK_Status_Bar dérivent des GTK_HBox ! Étonnant, non ? :o Oui mais voilà qui va nous être utile. Notre barre de statut peut donc contenir d'autres widgets ! Alors pourquoi ne pas y ajouter une barre de progression pour un éventuel téléchargement ainsi qu'une case à cocher pour une option ? (Voir la figure suivante.)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
WITH Gtk.Main ;                   USE Gtk.Main ;
WITH Gtk.Window ;                 USE Gtk.Window ;
WITH Gtk.Box ;                    USE Gtk.Box ; 
WITH Gtk.Button ;                 USE Gtk.button ;
WITH Glib.Convert ;               USE Glib.Convert ;
WITH Gtk.Status_Bar ;             USE Gtk.Status_Bar ;
WITH Gtk.Progress_Bar ;           USE Gtk.Progress_Bar ; 
WITH Gtk.Check_Button ;           USE Gtk.Check_Button ; 
WITH Gtk.Handlers ; 


PROCEDURE MaBarreDeStatus IS

      --Objets
   Win         : GTK_Window ;
   Vbox        : Gtk_Vbox ;
   Barre       : GTK_Status_Bar ;
   Btn1, Btn2  : Gtk_Button ;
   Msg0        : Message_Id ;
   Progress    : Gtk_Progress_Bar ; 
   Option      : Gtk_Check_Button ; 

      --Type nécessaire aux callbacks
   TYPE T_Data IS RECORD
      Barre : GTK_Status_Bar ;
      Id    : Integer ;
   END RECORD ; 

      --Packages
   PACKAGE P_Callback IS NEW Gtk.Handlers.User_Callback(Gtk_Button_Record,T_Data) ;
   USE P_Callback ; 

      --Callbacks
   PROCEDURE Active_Barre(Emetteur : ACCESS Gtk_Button_Record'Class ; 
                          Data     : T_Data) IS
      PRAGMA Unreferenced(Emetteur) ; 
      Msg1 : Message_Id ; 
   BEGIN
      CASE Data.Id IS
         WHEN 1 => Msg1 := Data.Barre.Push(1,"C'est le bouton 1") ; 
         WHEN 2 => Msg1 := Data.Barre.Push(1,"C'est le bouton 2") ; 
         WHEN OTHERS => NULL ; 
      END CASE ;  
   END Active_Barre ; 

   PROCEDURE Desactive_Barre(Emetteur : ACCESS Gtk_Button_Record'Class ; 
                             Data     : T_Data) IS
      PRAGMA Unreferenced(Emetteur) ; 
   BEGIN
      Data.Barre.Pop(1) ; 
   END Desactive_Barre ;


BEGIN
   Init ;
      --Création de la fenêtre
   Gtk_New(Win) ;
   Win.Set_Default_Size(400,300) ;
   Win.Set_Title("Ma barre de statut") ;

      --Création de la boîte
   Gtk_New_Vbox(Vbox) ;
   Win.Add(Vbox) ;

      --Création de la barre de statut
   Gtk_New(Barre) ;
   Msg0 := Barre.Push(0,"Passez le curseur sur un bouton") ; 
   Vbox.pack_end(Barre, expand => false) ;

      --Création des boutons
   Gtk_New(Btn1,"Premier bouton") ;
   Connect(Btn1,"enter", Active_Barre'ACCESS, (Barre,1)) ;
   Connect(Btn1,"leave", Desactive_Barre'ACCESS, (Barre,1)) ;
   Vbox.Pack_Start(Btn1) ; 

   Gtk_New(Btn2,Locale_To_Utf8("Deuxième bouton")) ;
   Connect(Btn2,"enter", Active_Barre'ACCESS, (Barre,2)) ;
   Connect(Btn2,"leave", Desactive_Barre'ACCESS, (Barre,2)) ;
   Vbox.Pack_Start(Btn2) ;

      --Création d'une case à cocher
   Gtk_New(Option,Locale_To_Utf8("Connecté")) ; 
   Barre.Pack_End(Option, Expand => False, Fill => False) ;   

      --Création d'une barre de progression
   Gtk_New(Progress) ; 
   Progress.set_fraction(0.5) ; 
   Barre.Pack_End(Progress,Expand=> False, Fill => False) ; 

      --Finalisation
   Win.Show_All ;
   Main ;

END MaBarreDeStatus ;

La barre de statut avec une barre de progression

Maintenant, libre à vous de proposer des barres d'état avec davantage d'options. Pourquoi ne pas y intégrer l'heure, des statistiques concernant votre document, un outil de zoom ou des boutons pour remplacer les boîtes de dialogue !

Le menu déroulant

Fiche d'identité

  • Widget : GTK_Combo_Box
  • Package : GTK.Combo_Box
  • Descendance : GTK_Widget >> GTK_Container >> GTK_Bin
  • Description : Le GTK_Combo_Box se présente sous la forme d'un menu déroulant permettant un choix entre différents textes.

Sur la figure suivante, le menu déroulant permet de choisir entre différentes monnaies.

Un menu déroulant

Méthodes

De nombreuses méthodes existent pour les GTK_Combo_Box, mais nous allons nous concentrer sur le cas courant : un menu déroulant ne proposant que des lignes de texte. Auquel cas, nous devrons utiliser le constructeur suivant :

1
procedure Gtk_New_Text(Combo : out Gtk_Combo_Box);

L'ajout de texte se fait à l'aide de méthodes de type Append-Prepend-Insert comme vous devez vous en douter :

1
2
3
4
5
6
7
procedure Append_Text (Combo_Box : access Gtk_Combo_Box_Record; 
                       Text : String);
procedure Prepend_Text(Combo_Box : access Gtk_Combo_Box_Record; 
                       Text : String);
procedure Insert_Text (Combo_Box : access Gtk_Combo_Box_Record;
                       Position  : Gint;
                       Text      : String);

Pour la suppression d'une ligne de texte, vous devrez faire appel à la méthode Remove_Text() et renseigner la position de la ligne souhaitée :

1
2
procedure Remove_Text(Combo_Box : access Gtk_Combo_Box_Record; 
                      Position : Gint);

Enfin, vous aurez besoin pour vos callbacks de connaître la valeur sélectionnée par l'utilisateur. Deux méthodes existent : Get_Active() renverra le numéro de la valeur choisie (0 pour la première valeur, 1 pour la seconde… -1 si aucune n'est sélectionnée) ; Get_Active_Text() renverra quant à elle le texte sélectionné (si aucune valeur n'a été sélectionnée, elle renverra un string vide). Inversement, vous pourrez définir le texte activé avec Set_Active(), par exemple pour définir une valeur par défaut. Attention toutefois, cette méthode émet automatiquement le signal Signal_Changed / "changed" indiquant que la valeur à été modifiée.

1
2
3
4
procedure Set_Active    (Combo_Box : access Gtk_Combo_Box_Record; 
                         Index : Gint);
function Get_Active     (Combo_Box : access Gtk_Combo_Box_Record) return Gint;
function Get_Active_Text(Combo_Box : access Gtk_Combo_Box_Record) return String;

Menu déroulant avec saisie

Il est également possible d'autoriser l'utilisateur à saisir une valeur non prédéfinie. Reprenons l'exemple du programme présenté dans la Fiche d'identité. L'utilisateur ne peut utiliser le rouble, la livre sterling ou la roupie ; il est limité aux quatre choix proposés : Euro, Dollar, Yen et Yuan. Si vous souhaitez laisser davantage de liberté, il faudra utiliser un widget fils : les GTK_Combo_Box_Entry. Ceux-ci n'apportent aucune méthode supplémentaire et utilisent le même signal.

Sur la figure suivante, la GTK_Combo_Box_Entry permet d'entrer une valeur supplémentaire.

Un menu déroulant avec saisie


En résumé :

  • Pour créer une barre d'icônes ou de menu, vous devez tout d'abord utiliser un premier widget comme conteneur : GTK_Toolbar ou GTK_Menu_Bar.
  • Une fois la barre créée, ajoutez-y des items : GTK_Menu_Item pour la barre de menus et GTK_Tool_Button pour la barre d'icônes.
  • Les GTK_Menu_Item ne sont en définitive que du texte. Pour qu'ils déroulent un menu, vous devrez utiliser les GTK_Menu. La même chose est réalisable avec la barre d'icônes en utilisant les Gtk_Menu_Tool_Button au lieu des Gtk_Tool_Button.
  • Les widgets présentés dans ce chapitre sont des conteneurs. Il est donc possible de les imbriquer avec d'autres conteneurs afin de combiner divers widgets et d'obtenir des barres moins classiques.