Nous nous sommes arrêtés au dernier chapitre sur une déception de taille : notre fenêtre ne comporte qu'un seul gros bouton qui occupe la totalité de la place et qui est redimensionné en même temps que la fenêtre. De plus, il est impossible d'ajouter un second bouton à notre fenêtre. Alors pour avoir plusieurs boutons dans votre application, il y a une solution : les conteneurs. Ces widgets un peu particuliers font l'objet d'un chapitre à part entière.
Des conteneurs pour… contenir !
Qu'est-ce qu'un conteneur ?
Non, quand je parle de conteneur je ne parle pas de des grosses caisses métalliques voyageant sur les camions ou les bateaux !Il s'agit de widgets très particuliers, pas nécessairement visibles mais dont le seul rôle est de contenir d'autres widgets. Les fenêtres ou les boutons dérivent de la classe GTK_Container_Record
puisqu'une fenêtre peut contenir un bouton et qu'un bouton peut contenir une étiquette (du texte) et une image. Mais, quand je parlerai de conteneurs, je sous-entendrai désormais des conteneurs conçus pour organiser nos fenêtres.
L'idée est simple : une fenêtre ne peut contenir qu'un seul widget. Mais il est possible de créer des widgets appelés conteneurs pouvant contenir plusieurs autres widgets. Alors pourquoi ne pas placer tous nos widgets dans un seul conteneur que l'on placera quant à lui dans la fenêtre? Nous obtiendrions quelque chose comme cela :
Présentation de différents conteneurs
Je vais vous présenter succinctement les quelques conteneurs que nous verrons dans ce chapitre. Il en existe d'autres que nous verrons plus tard, nous allons pour l'instant nous concentrer sur les conteneurs principaux.
Les alignements
Il s'agit d'un conteneur prévu pour un seul sous-widget (ce dernier est appelé widget enfant). Mais il permet, comme son nom l'indique, d'aligner un bouton selon des critères précis, par exemple : «je veux que le bouton reste en bas à gauche de la fenêtre». Cela évite d'avoir un gros bouton tout moche qui se déforme en même temps que la fenêtre. Je sais, c'est pas folichon, mais il est essentiel de comprendre son fonctionnement avant de s'attaquer à des conteneurs plus complexes.
Les boîtes
Les boîtes peuvent quant à elles avoir plusieurs widgets alignés verticalement ou horizontalement.
Les tables
Les tables ressemblent peu ou prou aux boîtes mais proposent d'afficher plusieurs lignes ou colonnes de widgets.
Les conteneurs à position fixée
Ces conteneurs permettent de fixer un widget selon des coordonnées. Plus simple d'emploi, il est en revanche plus compliqué d'arriver à des interfaces agréables, sans bugs et portables aisément sur d'autres ordinateurs avec ces conteneurs.
Les alignements
Fiche d'identité
Nous allons voir désormais de nombreux widgets, alors afin de ne pas me répéter, je vous présenterai désormais ces nouveautés par une rapide fiche d'identité.
- Widget : GTK_Alignment
- Package : Gtk.Alignment
- Descendance : GTK_Widget >> GTK_Container >> GTK_Bin (conteneurs pour un unique widget)
- Description : Conteneur permettant d'aligner de façon fine un unique widget dans une fenêtre.
Créer un GTK_Alignment
Repartons sur un code relativement épuré pour ne pas nous mélanger les pinceaux :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | WITH Gtk.Main ; USE Gtk.Main ; WITH Gtk.Window ; USE Gtk.Window ; WITH Gtk.Enums ; USE Gtk.Enums ; WITH Gtk.Button ; USE Gtk.Button ; PROCEDURE MaFenetre IS Win : Gtk_Window ; Btn : Gtk_Button ; BEGIN Init ; Gtk_New(Win,Window_Toplevel) ; Win.Set_Title("Alignement") ; win.set_default_size(250,200) ; Gtk_New(Btn, "Bouton") ; Win.add(Btn) ; Win.Show_all ; Main ; END MaFenetre ; |
Si, comme je vous l'avais conseillé, vous avez ouvert les spécifications du package Gtk.Alignment
, vous pourrez vous rendre compte que la procédure GTK_New()
a subi quelques modifications pour les GTK_Alignment
:
1 2 3 4 5 6 | procedure Gtk_New (Alignment : out Gtk_Alignment; Xalign : Gfloat; Yalign : Gfloat; Xscale : Gfloat; Yscale : Gfloat); |
Je passe sur le type GFloat, chacun aura compris qu'il s'agit d'un type virgule flottante défini très certainement par Glib. La question est surtout : que sont tous ces paramètres ?
- Le paramètre
Xalign
permet de positionner votre conteneur horizontalement : siXalign = 0.0
alors le widget est complètement à gauche. SiXalign = 1.0
, le conteneur sera le plus à droite possible. SiXalign = 0.5
, le conteneur sera situé au milieu (horizontalement). - Le paramètre
Yalign
permet de positionner votre conteneur verticalement. SiYalign = 0.0
, votre conteneur sera tout en haut ; siYalign = 1.0
, votre conteneur sera tout en bas.
Ces deux premiers paramètres ont des valeurs entre 0.0
et 1.0
et doivent être vus comme des pourcentages : Xalign = 0.50
et Yalign = 1.00
, signifie que le conteneur est aligné à 50% selon l'horizontale et à 100% selon la verticale. Autrement dit, il se trouve au milieu en bas.
- Le paramètre
Xscale
signifie littéralement «échelle horizontale». Il correspond à «l'étalement» du conteneur horizontalement. Les images ci-dessus ont été faites avec unXscale
valant0.0
, c'est-à-dire que le conteneur ne s'étale pas, il prend le moins de place possible, la seule limite étant la place nécessaire à l'affichage du texte du bouton. SiXscale = 1.0
(sa valeur maximale), alors le conteneur prendra 100% de la place disponible horizontalement. - Le paramètre
Yscale
a lui le même rôle mais verticalement, vous l'aurez compris.
Mieux vaut une petite image pour bien comprendre. Je vais placer mon conteneur au centre (Xalign = 0.50
et Yalign = 0.50
) et faire varier Xscale
et Yscale
:
Sachant cela, nous allons créer un Alignement contenant un bouton, situé en haut au milieu et s'étalant de 10% horizontalement et 0% verticalement. Il faudra penser à ajouter l'alignement à la fenêtre puis à ajouter le bouton à l'alignement (ou l'inverse) :
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 | WITH Gtk.Main ; USE Gtk.Main ; WITH Gtk.Window ; USE Gtk.Window ; WITH Gtk.Enums ; USE Gtk.Enums ; WITH Gtk.Button ; USE Gtk.Button ; WITH Gtk.Alignment ; USE Gtk.Alignment ; PROCEDURE MaFenetre IS Win : Gtk_Window ; Conteneur : Gtk_Alignment ; Btn : Gtk_Button ; BEGIN Init ; Gtk_New(Win,Window_Toplevel) ; Win.Set_Title("Alignement") ; win.set_default_size(250,200) ; Gtk_New(Conteneur,0.5,0.0,0.1,0.0) ; Win.Add(Conteneur) ; Gtk_New(Btn, "Bouton") ; Conteneur.add(Btn) ; Win.Show_all ; Main ; END MaFenetre ; |
Ces paramètres pourront être modifiés plus tard grâce à la méthode conteneur.set()
:
1 2 3 4 5 6 | procedure Set (Alignment : access Gtk_Alignment_Record; Xalign : Gfloat; Yalign : Gfloat; Xscale : Gfloat; Yscale : Gfloat); |
Le padding
Le padding correspond à l'écart séparant le bord du conteneur du bord du bouton. Pour l'instant, le padding est de 0 pixels, ce qui veut dire que le conteneur enserre parfaitement le bouton. Pour créer un peu d'air (et éviter à terme que d'autres widgets viennent se coller à votre conteneur) nous pouvons utiliser cette méthode :
1 2 3 4 5 6 | procedure Set_Padding (Alignment : access Gtk_Alignment_Record; Padding_Top : Guint; --espace au dessus du bouton Padding_Bottom : Guint; --espace en dessous du bouton Padding_Left : Guint; --espace à gauche du bouton Padding_Right : Guint); --espace à droite du bouton |
Je vous conseille d'avoir un padding de seulement quelques pixels (3 par exemple) : «conteneur.set_padding(3,3,3,3)
».
Les boîtes
Boîtes classiques
Fiche d'identité
- Widgets : GTK_Box, GTK_HBox, GTK_VBox
- Package : Gtk.Box
- Descendance : GTK_Widget >> GTK_Container
- Description : Conteneurs permettant d'aligner plusieurs widgets horizontalement (HBox) ou verticalement (VBox).
Créer des boîtes
Si vous regardez en détail le début des spécifications du package, vous remarquerez qu'il y a trois widgets : GTK_Box
et deux sous-types GTK_HBox
et GTK_VBox
. Ce sont ces deux derniers que nous allons utiliser : GTK_HBox
est une boîte horizontale et GTK_VBox
est une boîte verticale. Il existe donc un constructeur pour chacun de ces widgets : GTK_New_HBox()
et GTK_New_VBox()
.
1 2 3 4 5 6 7 8 | procedure Gtk_New_Hbox (Box : out Gtk_Hbox; Homogeneous : Boolean := False; Spacing : Gint := 0); procedure Gtk_New_Vbox (Box : out Gtk_Vbox; Homogeneous : Boolean := False; Spacing : Gint := 0); |
Si le paramètre Homogeneous vaut TRUE
, alors les widgets auront des tailles similaires, homogènes. Le paramètre Spacing
est similaire au paramètre Padding
des alignements : il indique le nombre de pixels (l'espace) qui séparera les widgets enfants. Ces deux paramètres pourront être modifiés plus tard grâce aux méthodes Set_Homogeneous()
et Set_Spacing()
. Créons par exemple une boîte verticale homogène avec un espacement de 3 pixels.
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 | WITH Gtk.Main ; USE Gtk.Main ; WITH Gtk.Window ; USE Gtk.Window ; WITH Gtk.Enums ; USE Gtk.Enums ; WITH Gtk.Button ; USE Gtk.Button ; WITH Gtk.Box ; USE Gtk.Box ; PROCEDURE MaFenetre IS Win : Gtk_Window ; Boite : Gtk_VBox ; Btn1, Btn2, Btn3 : Gtk_Button ; BEGIN Init ; Gtk_New(Win,Window_Toplevel) ; Win.Set_Title("Boite verticale") ; win.set_default_size(250,200) ; Gtk_New_VBox(Boite, homogeneous => true, spacing => 3) ; Win.Add(Boite) ; Gtk_New(Btn1, "Bouton 1") ; Gtk_New(Btn2, "Bouton 2") ; Gtk_New(Btn3, "Bouton 3") ; -- Ici, nous ajouterons les trois boutons dans notre boite Win.Show_all ; Main ; END MaFenetre ; |
Ajout de widgets
Reste maintenant à intégrer nos trois boutons à notre boîte verticale. La méthode add()
est inopérante avec les boîtes : ajouter des widgets, c'est bien gentil, mais où et comment les ajouter ? Pour cela, imaginez une grande boîte en carton posée devant vous. Vous posez un objet au centre puis, pour gagner de la place, vous le poussez soit vers le haut du carton, soit vers le bas. C'est exactement ce que nous allons faire avec nos widgets en les «poussant autant que possible» soit vers le début (le haut pour les VBox, la gauche pour les HBox), soit vers la fin (le bas ou la droite). Pour «pousser» un widget vers le haut de notre GTK_VBox
, vous utiliserez la méthode Pack_start()
. Pour «pousser» un widget vers le bas, vous utiliserez la méthode Pack_end()
.
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.Enums ; USE Gtk.Enums ; WITH Gtk.Button ; USE Gtk.Button ; WITH Gtk.Box ; USE Gtk.Box ; PROCEDURE MaFenetre IS Win : Gtk_Window ; Boite : Gtk_VBox ; Btn1, Btn2, Btn3 : Gtk_Button ; BEGIN Init ; Gtk_New(Win,Window_Toplevel) ; Win.Set_Title("Boite verticale") ; win.set_default_size(250,200) ; Gtk_New_VBox(Boite, homogeneous => true, spacing => 3) ; Win.Add(Boite) ; Gtk_New(Btn1, "Bouton 1") ; Boite.Pack_End(Btn1) ; Gtk_New(Btn2, "Bouton 2") ; Boite.Pack_End(Btn2) ; Gtk_New(Btn3, "Bouton 3") ; Boite.Pack_End(Btn3) ; Win.Show_all ; Main ; END MaFenetre ; |
Si l'ordre obtenu vous déplaisait, vous pouvez repositionner certains widgets. Par exemple, Boite.reorder_child(Btn1,2) repositionnerait le Bouton 1 en deuxième position.
Si vous testez le code ci-dessus, vous remarquerez que Btn1 est le premier bouton placé à la fin : ce sera donc le bouton le plus en bas.
Paramétrez vos widgets enfants
Maintenant, si vous avez regardé les spécifications de ces méthodes, vous aurez remarqué qu'elles comportent trois autres paramètres : Expand
, Fill
et Padding
.
- Vous savez désormais ce qu'est le padding, les méthodes
Pack_End()
etPack_Start()
vous proposent unPadding
supplémentaire pour certains widget,Padding
qui s'ajoute auSpacing
de la boîte. - Le paramètre
Expand
, s'il vautTRUE
, indique que l'encart contenant votre widget va pouvoir «prendre ses aises» et s'étendre autant qu'il le peut, même au détriment de ses camarades. Si la fenêtre est redimensionnée, l'encart le sera aussi. Ce paramètre n'a aucun intérêt si vous avez paramétréHomogeneous
àTRUE
. - Le paramètre
Fill
, s'il vautTRUE
, indique que le widget doit occuper tout l'espace disponible dans son encart. S'il vautFALSE
, le widget se limitera à l'espace dont il a réellement besoin. Ce paramètre n'a d'intérêt que siExpand
vautTRUE
.
Pour mieux comprendre, reprenons notre exemple :
1 2 3 4 5 6 7 8 | ... Gtk_New_VBox(Boite, homogeneous => false, spacing => 3) ; Gtk_New(Btn1, "Bouton 1") ; Boite.Pack_End(Btn1, Expand => false, Fill => false) ; Gtk_New(Btn2, "Bouton 2") ; Boite.Pack_End(Btn2, Expand => true, Fill => false) ; Gtk_New(Btn3, "Bouton 3") ; Boite.Pack_End(Btn3, Expand => false, Fill => false) ; |
Pour le bouton2, Expand = true
, donc son encart prend toute la place disponible, au détriment des autres.
1 2 3 4 | ... Gtk_New(Btn1, "Bouton 1") ; Boite.Pack_End(Btn1, Expand => false, Fill => false) ; Gtk_New(Btn2, "Bouton 2") ; Boite.Pack_End(Btn2, Expand => true, Fill => true) ; Gtk_New(Btn3, "Bouton 3") ; Boite.Pack_End(Btn3, Expand => false, Fill => false) ; |
Cette fois, Expand = TRUE
et Fill = TRUE
, donc son encart prend toute la place disponible et le bouton remplit l'encart.
Avec plusieurs types de widgets
Un avantage des boîtes, c'est qu'elles peuvent contenir divers widgets, pas nécessairement de même type. Par exemple, nous allons remplacer le troisième bouton par un GTK_Label, c'est-à-dire une étiquette (du texte quoi) :
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 | WITH Gtk.Main ; USE Gtk.Main ; WITH Gtk.Window ; USE Gtk.Window ; WITH Gtk.Enums ; USE Gtk.Enums ; WITH Gtk.Button ; USE Gtk.Button ; WITH Gtk.Box ; USE Gtk.Box ; WITH Gtk.Label ; USE Gtk.Label ; PROCEDURE MaFenetre IS Win : Gtk_Window ; Boite : Gtk_VBox ; Btn1, Btn2 : Gtk_Button ; Lbl : GTK_Label ; BEGIN Init ; Gtk_New(Win,Window_Toplevel) ; Win.Set_Title("Boite verticale") ; win.set_default_size(250,200) ; Gtk_New_VBox(Boite, homogeneous => false, spacing => 3) ; Win.Add(Boite) ; Gtk_New(Btn1, "Bouton 1") ; Boite.Pack_End(Btn1, Expand => false, Fill => false) ; Gtk_New(Btn2, "Bouton 2") ; Boite.Pack_End(Btn2, Expand => true, Fill => true) ; Gtk_New(Lbl, "Ceci est du texte") ; Boite.Pack_End(Lbl, Expand => False, Fill => False) ; Win.Show_all ; Main ; END MaFenetre ; |
Avoir tous ces différents widgets ne posera pas de soucis à GTK ni à notre boîte.
Nous reverrons les GTK_Label
plus en détail, rassurez-vous.
Mélanger le tout
Ça veut dire que mes widgets seront soit à l'horizontale, soit à la verticale, mais qu'il n'y a pas moyen de panacher… c'est un peu limité quand même.
Allons, soyez imaginatifs. Les conteneurs sont des widgets faits pour contenir d'autres widgets. Il n'est donc pas interdit qu'un conteneur contienne un autre conteneur ! Par exemple, notre GTK_VBox
, pourrait contenir une GTK_HBox
à l'emplacement du bouton 2 !
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 | WITH Gtk.Main ; USE Gtk.Main ; WITH Gtk.Window ; USE Gtk.Window ; WITH Gtk.Enums ; USE Gtk.Enums ; WITH Gtk.Button ; USE Gtk.Button ; WITH GTK.Label ; USE Gtk.Label ; WITH Gtk.Box ; USE Gtk.Box ; PROCEDURE MaFenetre IS Win : Gtk_Window ; VBoite : Gtk_HBox ; HBoite : Gtk_HBox ; Btn1, Btn2, Btn3 : Gtk_Button ; lbl : Gtk_Label ; BEGIN Init ; Gtk_New(Win,Window_Toplevel) ; Win.Set_Title("Boite horizontale") ; win.set_default_size(250,200) ; Gtk_New_VBox(VBoite, homogeneous => false, spacing => 3) ; Win.Add(VBoite) ; --On remplit la boite verticale Gtk_New(Btn1, "Bouton 1") ; Gtk_New_HBox(HBoite, homogeneous => false, Spacing => 3) ; Gtk_New(Btn3, "Bouton 3") ; VBoite.Pack_End(Btn1) ; VBoite.Pack_End(HBoite) ; VBoite.Pack_End(Btn3) ; --On remplit la boite horizontale Gtk_New(Btn2, "Bouton 2") ; Gtk_New(Lbl, "Ceci est toujours du texte") ; HBoite.Pack_Start(Btn2) ; HBoite.Pack_Start(Lbl) ; Win.Show_all ; Main ; END MaFenetre ; |
Comme vous pouvez le constater, la GTK_VBox
comprend deux boutons ainsi qu'une GTK_HBox
, laquelle contient une étiquette et un bouton.
Boîtes à boutons
Fiche d'identité
- Widgets : GTK_HButton_Box et GTK_VButton_Box
- Package : GTK.Button_Box, GTK.HButton_Box et GTK.VButton_Box
- Descendance : GTK_Widget >> GTK_Container >> GTK_Box >> GTK_Button_Box
- Description : Conteneurs spécifiquement prévu pour organiser les boutons de façon harmonieuse, horizontalement ou verticalement.
Créer et remplir une boîte à boutons
Nos boîtes, si elles sont très pratiques, ne sont malheureusement pas très esthétiques. Nos boutons sont soit écrasés soit énormes. Et cela ne s'arrange pas si l'on agrandit la fenêtre. Pour pallier à ce problème existe un deuxième type de boîte : les boîtes à boutons. Comme pour les boîtes classiques, il existe un modèle vertical et un modèle horizontal. Toutefois, chacun a son package spécifique. Celles-ci dérivant du type GTK_Button_Box
, lui-même dérivant du type GTK_Box
, les méthodes pack_end()
et pack_start()
vues précédemment restent valides :
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 | WITH Gtk.Main ; USE Gtk.Main ; WITH Gtk.Window ; USE Gtk.Window ; WITH Gtk.Enums ; USE Gtk.Enums ; WITH Gtk.Button ; USE Gtk.Button ; WITH Gtk.HButton_Box ; USE Gtk.HButton_Box ; PROCEDURE MaFenetre IS Win : Gtk_Window ; Boite : Gtk_HButton_Box ; Btn1, Btn2, Btn3 : Gtk_Button ; BEGIN Init ; Gtk_New(Win,Window_Toplevel) ; Win.Set_Title("Boite a boutons horizontale") ; win.set_default_size(350,200) ; Gtk_New(Boite) ; Win.Add(Boite) ; Gtk_New(Btn1, "Bouton 1") ; Boite.Pack_End(Btn1) ; Gtk_New(Btn2, "Bouton 2") ; Boite.Pack_End(Btn2) ; Gtk_New(Btn3, "Bouton 3") ; Boite.Pack_End(Btn3) ; Win.Show_all ; Main ; END MaFenetre ; |
Ainsi, les boutons sont positionnés de manière agréable sans avoir à se soucier des Padding et autres Spacing. Malgré l'agrandissement de la fenêtre, les boutons garderont un aspect normal.
Paramétrages spécifiques à la boîte à boutons
Les boîtes à boutons présentent de nouveaux paramètres pour affiner la présentation. Tout d'abord avec la méthode Set_Layout()
(package GTK.Button_Box
) ou la méthode Set_Layout_Default()
(packages GTK.HButton_Box
et GTK.VButton_Box
). Celles-ci proposent différents placements par défaut pour vos boutons. Ces placements sont de type Gtk.Enums.Gtk_Button_Box_Style
(encore Gtk.Enums
!) dont voici les valeurs possibles :
- Buttonbox_Spread : les boutons sont placés de manière régulière dans la boîte.
- Buttonbox_Edge : les boutons sont placés de manière régulière, mais le premier et le dernier boutons sont collés aux bords de la boîte.
- Buttonbox_Start : les boutons sont placés le plus près possible du début de la boîte (le haut pour les boîtes verticales, la gauche pour les boîtes horizontales).
- Buttonbox_End : les boutons sont placés le plus près possible de la fin de la boîte (le bas pour les boîtes verticales, la droite pour les boîtes horizontales).
Autre personnalisation possible : rendre secondaire certains boutons. Cela est souvent utiliser pour les boutons «Aide» ou «Options». Ces derniers sont mis à l'écart des autres. Les GTK_Button_Box
permettent cela grâce à la méthode Set_Child_Secondary()
. Par exemple, si nous modifions notre code pour que les boutons soient alignés sur la gauche et que le bouton n°3 soit secondaire, cela nous donnerait :
1 2 3 4 5 6 7 8 9 | ... Gtk_New(Boite) ; Boite.set_layout(Buttonbox_Start) ; Win.Add(Boite) ; Gtk_New(Btn1, "Bouton 1") ; Boite.Pack_Start(Btn1) ; Gtk_New(Btn2, "Bouton 2") ; Boite.Pack_Start(Btn2) ; Gtk_New(Btn3, "Bouton 3") ; Boite.Pack_Start(Btn3) ; Boite.set_child_secondary(child => Btn3, Is_secondary => true) ; |
Les tables
Fiche d'identité
- Widget : GTK_Table
- Package : Gtk.Table
- Descendance : GTK_Widget >> GTK_Container
- Description : Conteneur permettant de stocker plusieurs widgets répartis sur plusieurs lignes et plusieurs colonnes.
Créer une table de widgets
Vous devriez rapidement comprendre le fonctionnement du constructeur à la lecture de sa spécification :
1 2 3 4 5 | procedure Gtk_New (Table : out Gtk_Table; Rows : Guint; Columns : Guint; Homogeneous : Boolean); |
En créant votre table, vous devrez indiquer le nombre de lignes (rows), de colonnes (columns) et indiquer si la table sera homogène (relire la partie sur les boîtes si vous avez déjà oublier ce que cela signifie). Pour information, les types Guint
sont encore des types entiers comme les Gint
et signifient «Glib Unsigned Integer», autrement dit, des entiers positifs. En cas d'erreur, vous pourrez toujours revoir ces paramètres à l'aide des deux méthodes suivantes :
1 2 3 4 5 6 7 | procedure Resize (Table : access Gtk_Table_Record; Rows : Guint; Columns : Guint); procedure Set_Homogeneous (Table : access Gtk_Table_Record; Homogeneous : Boolean); |
Vous pouvez également régler l'écart entre les colonnes ou entre les lignes avec les deux méthodes ci-dessous. L'écart correspond bien entendu au nombre de pixels.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | procedure Set_Col_Spacings --définit l'espace entre toutes les colonnes (Table : access Gtk_Table_Record; Spacing : Guint); procedure Set_Col_Spacing --définit l'espace entre deux colonnes spécifiques (Table : access Gtk_Table_Record; Column : Guint; Spacing : Guint); procedure Set_Row_Spacings --définit l'espace entre toutes les lignes (Table : access Gtk_Table_Record; Spacing : Guint); procedure Set_Row_Spacing --définit l'espace entre deux lignes spécifiques (Table : access Gtk_Table_Record; Row : Guint; Spacing : Guint); |
Voici le code initial de notre fenêtre :
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 | WITH Gtk.Main ; USE Gtk.Main ; WITH Gtk.Window ; USE Gtk.Window ; WITH Gtk.Enums ; USE Gtk.Enums ; WITH Gtk.Button ; USE Gtk.Button ; WITH Gtk.Table ; USE Gtk.Table ; PROCEDURE MaFenetre IS Win : Gtk_Window ; Tableau : Gtk_Table ; Btn1, Btn2, Btn3 : Gtk_Button ; Btn4, Btn5, Btn6 : Gtk_Button ; BEGIN Init ; Gtk_New(Win,Window_Toplevel) ; Win.Set_Title("Table a widgets") ; win.set_default_size(350,200) ; Gtk_New(Tableau,3,2,True) ; Tableau.Set_Row_Spacings(1) ; Tableau.Set_Col_Spacings(2) ; Win.Add(Tableau) ; --Nous ajouterons ici les boutons à notre table Win.Show_all ; Main ; END MaFenetre ; |
Ajouter des widgets
Avant de commencer à ajouter des boutons à notre table, vous devez savoir qu'un widget peut occuper plusieurs cases alors que son voisin n'en occupera qu'une seule. Cette liberté offerte au programmeur va quelque peu alourdir notre code car nous devrons renseigner où se situe les bords gauche, droite, haut et bas du widget. Pour comprendre de quoi je parle, regardez la spécification (allégée) de la méthode pour ajouter des widgets :
1 2 3 4 5 6 7 | procedure Attach --ou Attach_Default (Table : access Gtk_Table_Record; Widget : access Gtk.Widget.Gtk_Widget_Record'Class; Left_Attach : Guint; Right_Attach : Guint; Top_Attach : Guint; Bottom_Attach : Guint); |
Vous devez vous imaginer que chaque bordure ou séparation de la table porte un numéro. La première bordure, celle du haut ou de gauche, porte le numéro 0. La bordure de droite porte le numéro du nombre de colonnes ; la bordure du bas porte le numéro du nombre de lignes :
Ainsi, on peut affirmer que le bouton n°2 s'étend de 0 à 1 horizontalement et de 1 à 2 verticalement, ce qui se traduit en langage Ada par :
1 2 3 4 5 6 | Tableau.Attach( Widget => Btn2 ; Left_Attach => 0 ; Right_Attach => 1 ; Top_Attach => 1 ; Bottom_Attach => 2); |
Pour obtenir la table de widgets donnée en exemple, voici donc ce que j'ai écrit :
1 2 3 4 5 6 7 | ... Gtk_New(Btn1, "Bouton 1") ; Tableau.attach(Btn1,0,1,0,1) ; Gtk_New(Btn2, "Bouton 2") ; Tableau.attach(Btn2,0,1,1,2) ; Gtk_New(Btn3, "Bouton 3") ; Tableau.attach(Btn3,0,1,2,3) ; Gtk_New(Btn4, "Bouton 4") ; Tableau.Attach(Btn4,1,2,0,1) ; Gtk_New(Btn5, "Bouton 5") ; Tableau.Attach(Btn5,1,2,1,2) ; Gtk_New(Btn6, "Bouton 6") ; Tableau.attach(Btn6,1,2,2,3) ; |
Les paramètres supplémentaires
Malheureusement, je vous ai bien dit que le constructeur que je vous avais transmis était allégé. Le véritable constructeur a plutôt la spécification suivante :
1 2 3 4 5 6 7 8 9 10 11 | procedure Attach (Table : access Gtk_Table_Record; Child : access Gtk.Widget.Gtk_Widget_Record'Class; Left_Attach : Guint; Right_Attach : Guint; Top_Attach : Guint; Bottom_Attach : Guint; Xoptions : Gtk.Enums.Gtk_Attach_Options := Expand or Fill; Yoptions : Gtk.Enums.Gtk_Attach_Options := Expand or Fill; Xpadding : Guint := 0; Ypadding : Guint := 0); |
Vous vous souvenez du padding ? Nous l'avions vu avec les alignements. Il s'agit du nombre de pixels séparant le bord de l'encart et le widget qui s'y trouve. Xpadding
indique donc l'écart horizontal, Ypadding
l'écart vertical. Attention, le padding n'influe pas sur le conteneur (sauf si la fenêtre est trop petite) mais sur la taille du widget enfant.
Les paramètres Xoptions et Yoptions correspondent au comportement du widget à l'horizontale et à la verticale : notre bouton doit-il prendre le maximum ou le minimum de place ? Les valeurs possibles sont les suivantes (disponibles avec Gtk.Enums
, encore et toujours) :
- Expand : déjà vu avec les boîtes. Le widget tente de maximiser la place occupée par son encart. N'a vraiment de sens que pour une table non homogène.
- Fill : déjà vu avec les boîtes. Le widget remplit entièrement l'encart qui lui est réservé.
- Expand or fill : permet de combiner les deux caractéristiques précédentes. D'ailleurs, c'est la valeur par défaut du paramètre.
- Shrink : indique que le widget ne prendra que la place strictement nécessaire.
Dans les faits, soit vous ne modifierez pas ces paramètres et votre bouton occupera tout l'espace alloué, soit vous utiliserez la valeur shrink
pour restreindre la taille du widget au maximum. Modifions notre code pour y voir plus clair et supprimons l'un des boutons :
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.Enums ; USE Gtk.Enums ; WITH Gtk.Button ; USE Gtk.Button ; WITH Gtk.Table ; USE Gtk.Table ; PROCEDURE MaFenetre IS Win : Gtk_Window ; Tableau : Gtk_Table ; Btn1, Btn2, Btn3 : Gtk_Button ; Btn4, Btn5 : Gtk_Button ; BEGIN Init ; Gtk_New(Win,Window_Toplevel) ; Win.Set_Title("Table a widgets") ; win.set_default_size(350,200) ; Gtk_New(Tableau,3,2,false) ; Tableau.Set_Row_Spacings(1) ; Tableau.Set_Col_Spacings(2) ; Win.Add(Tableau) ; Gtk_New(Btn1, "Bouton 1") ; Tableau.attach(Btn1,0,1,0,1, Xoptions => shrink, Yoptions => fill) ; Gtk_New(Btn2, "Bouton 2") ; Tableau.attach(Btn2,0,1,1,2, Xoptions => shrink, Yoptions => shrink) ; Gtk_New(Btn3, "Bouton 3") ; Tableau.attach(Btn3,0,1,2,3, Xoptions => fill, Yoptions => fill) ; Gtk_New(Btn4, "Bouton 4") ; Tableau.Attach(Btn4,1,2,0,1, Xpadding => 25, Xoptions => fill, Yoptions => shrink) ; Gtk_New(Btn5, "Bouton 5") ; Tableau.Attach(Btn5,1,2,1,3, Xoptions => expand or fill, Yoptions => expand or fill) ; Win.Show_all ; Main ; END MaFenetre ; |
Je vous laisse comparer les effets des différents paramètres sur les boutons de ma nouvelle fenêtre :
Le widget pour position fixe
Fiche d'identité
- Widgets : GTK_Fixed
- Package : GTK.Fixed
- Descendance : GTK_Widget >> GTK_Container
- Description : Conteneur de taille infinie permettant de positionner divers widgets à partir de coordonnées.
Utilisation des GTK_Fixed
Ce sera certainement le widget le plus simple de ce chapitre. Son constructeur se nomme simplement Gtk_New()
et n'a aucun paramètre particulier. Pour positionner un widget à l'intérieur d'un GTK_Fixed
, la méthode à employer s'appelle simplement put()
. Ses paramètres sont simplement les coordonnées $(x;y)$ du coin supérieur gauche de votre widget.
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 | WITH Gtk.Main ; USE Gtk.Main ; WITH Gtk.Window ; USE Gtk.Window ; WITH Gtk.Enums ; USE Gtk.Enums ; WITH Gtk.Button ; USE Gtk.Button ; WITH Gtk.Fixed ; USE Gtk.Fixed ; PROCEDURE MaFenetre IS Win : Gtk_Window ; Couche : Gtk_Fixed ; Btn1, Btn2, Btn3 : Gtk_Button ; BEGIN Init ; Gtk_New(Win,Window_Toplevel) ; Win.Set_Title("Fixes") ; win.set_default_size(150,100) ; Gtk_New(Couche) ; Win.Add(Couche) ; Gtk_New(Btn1, "Bouton 1") ; Couche.put(Btn1,20,50) ; Gtk_New(Btn2, "Bouton 2") ; Couche.put(Btn2,30,60) ; Gtk_New(Btn3, "Bouton 3") ; Couche.put(Btn3,200,150) ; Win.Show_all ; Main ; END MaFenetre ; |
Vous remarquerez deux choses : ce conteneur autorise le chevauchements de widgets. C'est à vous de faire en sorte qu'il n'y ait pas de souci d'affichage, ce qui est plus contraignant qu'avec les boîtes ou les tables. Ensuite, le Bouton n°3 aurait du être en dehors de la fenêtre : en effet, celle-ci a une taille de $150 \times 100$ alors que le bouton 3 est situé au point $(200 ; 150)$, soit en dehors. Mais le GTK_Fixed
a agrandi automatiquement la fenêtre pour pouvoir l'afficher. Il existe un conteneur similaire, les GTK_Layout
, qui fonctionne de la même façon mais pour lequel la fenêtre ne serait pas agrandielui ne s'embêtera pas avec cela.
Enfin, si l'un de vos widgets devait être déplacé, il suffirait d'utiliser la méthode move()
qui fonctionne comme put()
.
En résumé :
- Utilisez les
GTK_Alignment
pour positionner finement un unique widget. - Pour positionner plusieurs widgets, utilisez les
GTK_Box
,GTK_Button_Box
ouGTK_Table
. - Si vous avez besoin de positionner manuellement vos widgets (au pixel près) optez pour les
GTK_Fixed
mais pensez que le rendu ne sera pas forcément le même sur un autre ordinateur. - N'hésitez pas à imbriquer divers conteneurs les uns dans les autres pour obtenir la présentation souhaitée.