Tutoriel Gtk2Hs:

3.3 Empaquetage en utilisant des grilles

Voyons maintenant une autre façon d’empaqueter : les grilles. Elles peuvent être extrêmement utiles dans certaines situations. En utilisant les grilles, on crée une grille sur laquelle on peut placer les widgets. Les widgets prennent la place qu’on leur alloue.

La première chose à voir, est la fonction tableNew:

tableNew :: Int -> Int -> Bool -> IO Table

Le premier argument est le nombre de lignes à créer dans la grille, alors que le second est le nombre de colonnes.

L’argument booléen homogeneous traite de la façon dont les boites de la grille sont dimensionnées. Si homogeneous est mis à True, les boites de la grille sont redimensionnées à la taille du widget le plus large de la grille. Si homogeneous et mis à False, la taille d’une boite de la grille est imposée par le widget le plus grand dans la même ligne et le plus large dans la même colonne.

Les lignes et les colonnes sont numérotées de 0 à n ou n est le numéro spécifié dans l’appel à tableNew. Donc si vous spécifiez rows = 2 et columns = 2, l’agencement ressemblera à quelque chose comme cela:

 0          1          2
0+----------+----------+
 |          |          |
1+----------+----------+
 |          |          |
2+----------+----------+

Notez que le système de coordonnées commence dans le coin en haut à gauche. Pour placer un widget dans une boite, utilisez la fonction suivante:

tableAttach :: (TableClass self, WidgetClass child)
  => self            -- self         - The table.
  -> child           -- child        - The widget to add.
  -> Int             -- leftAttach   - The column number to attach the left
                     --                side of a child widget to.
  -> Int             -- rightAttach  - The column number to attach the right
                     --                side of a child widget to.
  -> Int             -- topAttach    - The row number to attach the top of a
                     --                child widget to.
  -> Int             -- bottomAttach - The row number to attach the bottom
                     --                of a child widget to.
  -> [AttachOptions] -- xoptions     - Used to specify the properties of the
                     --                child widget when the table is
                     --                resized.
  -> [AttachOptions] -- yoptions     - The same as xoptions, except this
                     --                field determines behaviour of
                     --                vertical resizing.
  -> Int             -- xpadding     - An integer value specifying the
                     --                padding on the left and right of the
                     --                widget being added to the table.
  -> Int             -- ypadding     - The amount of padding above and below
                     --                the child widget.
  -> IO ()

Le premier argument self est la grille que vous avez crée et le second child est le widget que vous souhaitez placer dans la grille.

Les arguments leftAttach et rightAttach spécifient où placer le widget et combien de boites à utiliser. Si vous voulez un bouton dans le logement en bas à droite de notre grille 2x2 et qu’il remplisse ce logement seulement, leftAttach devra être = 1, rightAttach =2, topAttach = 1, et bottomAttach= 2.

Maintenant, si vous vouliez qu’un widget prenne toute la ligne du haut de notre grille 2x2, vous devrez utiliser leftAttach = 0, rightAttach = 2, topAttach = 0, et bottomAttach = 1.

Les xoptions et yoptions sont utilisés pour spécifier les options d’empaquetage et la liste peut contenir plusieurs options à utiliser.

Ces options sont:

Fill
Si la boite de la grille est plus large que le widget et que Fill est spécifié, le widget va s’agrandir pour utiliser tout l’espace disponible. Shrink
Si le widget de la grille prend moins d’espace qu’il n’en demande (typiquement après un redimensionnement de fenêtre), alors le widget devrait normalement être poussé hors de la fenêtre et disparaître. Si Shrink est spécifié, les widgets vont rétrécir avec la grille. Expand
Ceci poussera la grille à s’agrandir pour utiliser tout l’espace restant dans la fenêtre.

L’espacement est exactement comme dans les boites, il créé un espace vide (en pixels) autour du widget

tableAttach a plusieurs options, voici un extrait:

tableAttachDefaults :: (TableClass self, WidgetClass widget)
  => self   -- self         - The table.
  -> widget -- widget       - The child widget to add.
  -> Int    -- leftAttach   - The column number to attach the left side of
            --                the child widget to.
  -> Int    -- rightAttach  - The column number to attach the right side of
            --                the child widget to.
  -> Int    -- topAttach    - The row number to attach the top of the child
            --                widget to.
  -> Int    -- bottomAttach - The row number to attach the bottom of the
            --                child widget to.
  -> IO ()

Les valeurs utilisées pour les paramètres [AttachOptions] sont [Expand, Fill], et l’espacement est mis à 0. Le reste des arguments est identique à la fonction précédente.

Il y a aussi tableSetRowSpacing et tableSetColSpacing. Il place de l’espace dans les lignes et les colonnes désirées.

tableSetRowSpacing :: TableClass self=> self-> Int -> Int -> IO ()
tableSetColSpacing :: TableClass self => self -> Int -> Int -> IO ()

Le premier argument Int est le numéro de ligne (ou de colonne) et le second est l’espace en pixels. Notez que pour les colonnes, l’espace va à droite de la colonne et pour les lignes l’espace va en dessous de la ligne.

On peut également définir un espacement constant pour toutes les lignes (ou colonnes) avec:

tableSetRowSpacings :: TableClass self=> self-> Int -> IO ()

et:

tableSetColSpacings :: TableClass self => self -> Int -> IO ()

Notez qu’avec ces appels, la dernière ligne et la dernière colonne n’ont pas d’espace.

Exemple d’empaquetage avec une grille

Maintenant, nous allons faire trois boutons dans une grille 2x2. Les deux premiers boutons seront placés dans la ligne du haut. Un troisième bouton (Quit) sera placé dans le ligne du bas, occupant deux colonnes, ce qui ressemblera à quelque chose comme ça:

Gtk Gtk2Hs Table packing

Voici le code source :

import Graphics.UI.Gtk


main :: IO ()
main = do
  initGUI
  window  <- windowNew
  set window [windowTitle := "Table", containerBorderWidth := 20,
              windowDefaultWidth := 150, windowDefaultHeight := 100]
  table   <- tableNew 2 2 True
  containerAdd window table
  button1 <- buttonNewWithLabel "On"
  onClicked button1 (buttonSwitch button1)
  tableAttachDefaults table button1 0 1 0 1
  button2 <- buttonNewWithLabel "Off"
  onClicked button2 (buttonSwitch button2)
  tableAttachDefaults table button2 1 2 0 1
  button3 <- buttonNewWithLabel "Quit"
  onClicked button3 mainQuit
  tableAttachDefaults table button3 0 2 1 2
  onDestroy window mainQuit
  widgetShowAll window
  mainGUI

buttonSwitch :: Button -> IO ()
buttonSwitch b = do
  txt <- buttonGetLabel b
  let newtxt = case txt of
                 "Off" -> "On"
                 "On"  -> "Off"
  buttonSetLabel b newtxt

La fonction buttonSwitch est connectée aux deux boutons de la ligne du haut. La fonction buttonGetLabel est un exemple de la façon d’obtenir les attributs d’un widget. Il y a également une alternative plus générale avec get qui prend un widget et un attribut comme argument. Dans l’exemple ci-dessus, cela serait:

txt <- get b buttonLabel

Avec le même résultat.