Tutoriel Gtk2Hs

Tutoriel Gtk2Hs 4.1 - Le widget bouton

Boutons normaux

Nous avons vu presque tout ce qu'il y a à voir sur le bouton widget. C'est assez simple. Cependant, il y a plus d'une façon de créer un bouton. Vous pouvez voir buttonNewWithLabel ou buttonNewWithMnemonic pour créer un bouton avec un label, utiliser buttonNewFromStock pour créer un bouton contenant une image et un texte, ou utiliser buttonNew pour créer un bouton vide. Libre à vous ensuite d'empaqueter ou dessiner dans ce nouveau bouton. Pour faire cela, créez une nouvelle boite, et empaquetez vos objets dans cette boite en utilisant boxPackStart (ou boxPackEnd), et ensuite utilisez containerAdd pour empaqueter le bouton dans la boite.

buttonNewWithMnemonic et buttonNewFromStock prennent tous les deux une chaîne de caractère comme premier argument. Utilisez le caractère underscore pour marquer le caractère comme mnémonique (raccourcis au clavier). En appuyant sur Alt et cette touche, cela active le bouton. Dans la seconde fonction, la chaîne est un stockId, c'est à dire l'identifiant d'une liste prédéfinie d'images avec des labels.

Voici un exemple d'utilisation de buttonNew pour créer un bouton avec une image et un label.

Gtk
 
Gtk2Hs
 
Button
 
with
 
image

import Graphics.UI.Gtk

main :: IO ()
main = do
  initGUI
  window <- windowNew
  set window [windowTitle := "Pix",
              containerBorderWidth := 10]
  button <- buttonNew
  onClicked button (putStrLn "button clicked")
  box    <- labelBox "info.xpm" "cool button"
  containerAdd button box
  containerAdd window button
  widgetShowAll window
  onDestroy window mainQuit
  mainGUI

labelBox :: FilePath -> String -> IO HBox
labelBox fn txt = do
  box   <- hBoxNew False 0
  set box [containerBorderWidth := 2]
  image <- imageNewFromFile fn
  label <- labelNew (Just txt)
  boxPackStart box image PackNatural 3
  boxPackStart box label PackNatural 3
  return box

La fonction labelBox peut être utilisée pour empaqueter des images et des labels dans n'importe quel widget de type conteneur. L'image provient d'un fichier en utilisant imageNewFromFile et le label vient de labelNew qui prend comme argument Maybe String. Nothing signifie pas de label.

Le widget Button possède les signaux suivant, qui sont assez explicites:

onPressed : 

émis lorsque le bouton est pressé.

onReleased : 

émis lorsque le bouton est relâché.

onClicked : 

émis lorsque le bouton est pressé puis relâché.

onEnter : 

émis lorsque le curseur passe sur le bouton.

onLeave : 

émis lorsque le curseur sort du bouton.

Boutons bascule

Les boutons bascules sont dérivés des boutons normaux et sont très similaires, sauf qu'ils seront toujours dans un état ou dans l'autre, modifiés par un clic. Lorsque vous cliquez dessus, ils se figent à l'état "pressé" et si vous cliquez à nouveau dessus ils se relâchent et restent à l'état "relâché".

Les boutons bascules sont les bases pour les cases à cocher et les boutons radio aussi, les appels utilisés pour les bascules sont hérités par les boutons radio et les cases à cocher. Nous les aborderons plus loin.

Créons un nouveau bouton bascule:

toggleButtonNew :: IO ToggleButton

toggleButtonNewWithLabel :: String -> IO Togglebutton

toggleButtonNewWithMnemonic :: String -> IO ToggleButton

Comme on pouvait l'imaginer, ils fonctionnent de façon identique aux appels du bouton "normal". Le premier crée un bouton bascule vide, et le dernier un bouton avec un label directement empaqueté dedans. De la même manière on peut créer un mnémonique avec le caractère underscore (tiret bas) devant le caractère voulu.

Pour connaître l'état du widget (ainsi que pour les cases à cocher et les boutons radio), on utilise:

toggleButtonGetActive :: ToggleButtonClass self => self -> IO Bool

Cela retourne True si le bouton est "pressé", et False s’il est "relaché"

Pour forcer l'état d'un bouton bascule ainsi que les boutons radio et les cases à cocher, on utilise la fonction:

toggleButtonSetActive :: ToggleButtonClass self => self -> Bool -> IO ()

L'appel ci-dessus peut être utilisé pour définir l'état du bouton bascule et ses descendants, les boutons radio et les cases à cocher. Le premier argument est le bouton dont on veut modifier l'état et le second, l'état du bouton que l'on veut lui imposer, True pour l'état "pressé" et False pour l'état relâché.

Notez que lorsque vous utilisez la fonction toggleButtonSetActive et que l'état est modifié, cela cause l'émission des signaux onClicked et onToggled depuis le bouton.

Cases à cocher

Les cases à cocher héritent de plusieurs propriétés et fonctions des boutons bascules, mais ont un aspect un peu différent. Plutôt que d'être des boutons avec du texte à l'intérieur, ce sont de petites cases avec du texte à leur droite. Elles sont souvent utilisées dans des applications pour activer ou non certaines options.

Les fonctions de création sont similaires au bouton classique.

checkButtonNew :: IO CheckButton

checkButtonNewWithLabel :: String -> IO Checkbutton

checkButtonNewWithMnemonic :: String -> IO CheckButton

La fonction checkButtonNewWithLabel crée une case à cocher avec un label à côté d'elle.

CheckButton est une instance de ToggleButtonClass et le signal onToggled est utilisé lorsq'un CheckButton est coché ou décoché, comme le bouton bascule.

Boutons radio

Les boutons radio sont similaires aux cases à cocher sauf qu'ils sont regroupés de telle sorte qu'un seul peut être sélectionné à la fois. Ils sont adaptés pour les choix dans une courte liste d'options. Créer un nouveau bouton radio se fait avec un de ces appels:

radioButtonNew :: IO RadioButton

radioButtonNewWithLabel :: String -> IO RadioButton

radioButtonNewWithMnemonic :: String -> IO RadioButton

radioButtonNewFromWidget :: RadioButton -> IO RadioButton

radioButtonNewWithLabelFromWidget :: RadioButton -> String -> IO RadioButton

radioButtonNewWithMnemonicFromWidget :: RadioButton -> String -> IO RadioButton

Vous noterez la présence d'un argument supplémentaire dans les trois dernières fonctions. Il est utilisé pour lier les nouveaux boutons à ceux déjà créés plus tôt dans un groupe.

C'est aussi une bonne idée de définir explicitement quel est le bouton qui doit être "pressé" par défaut avec:

toggleButtonSetActive :: ToggleButtonClass self => self -> Bool -> IO ()

Ceci est décrit dans la section des boutons bascules et fonctionne de la même manière. Une fois que les boutons radio sont groupés ensemble, seulement un bouton du groupe peut être activé à la fois. Si l'utilisateur clique sur un bouton radio, et ensuite sur un autre, le premier bouton radio émettra d'abord un signal onToggled (pour signaler le passage à l'état inactif), puis le second émettra un signal onToggled (pour signaler le passage à l'état actif).

L'exemple suivant crée un groupe de boutons radio avec trois boutons.Lorsque l'utilisateur presse un des boutons radio, ceux qui sont déclenchés écriront sur la sortie standard stdout en utilisant putStrLn dans la fonction setRadioState définie plus loin.

Gtk
 
Gtk2Hs
 
Radio
 
buttons

import Graphics.UI.Gtk

main :: IO ()
main = do
  initGUI
  window  <- windowNew
  set window [windowTitle := "Radio Button", containerBorderWidth := 5,
              windowDefaultWidth := 200, windowDefaultHeight := 150]
  box1    <- vBoxNew False 0
  containerAdd window box1
  box2    <- vBoxNew False 10
  containerSetBorderWidth box2 10
  boxPackStart box1 box2 PackNatural 0
  button1 <- radioButtonNewWithLabel "button 1"
  boxPackStart box2 button1 PackNatural 0
  button2 <- radioButtonNewWithLabelFromWidget button1 "button 2"
  boxPackStart box2 button2 PackNatural 0
  button3 <- radioButtonNewWithLabelFromWidget button2 "button 3"
  boxPackStart box2 button3 PackNatural 0
  toggleButtonSetActive button2 True
  onToggled button1 (setRadioState button1)
  onToggled button2 (setRadioState button2)
  onToggled button3 (setRadioState button3)
  sep     <- hSeparatorNew
  boxPackStart box1 sep PackNatural 0
  box3    <- vBoxNew False 10
  containerSetBorderWidth box3 10
  boxPackStart box1 box3 PackNatural 0
  closeb  <- buttonNewWithLabel "close"
  boxPackStart box3 closeb PackNatural 0
  onClicked closeb mainQuit
  widgetShowAll window
  onDestroy window mainQuit
  mainGUI

setRadioState :: RadioButton -> IO ()
setRadioState b = do
  state <- toggleButtonGetActive b
  label <- get b buttonLabel
  putStrLn ("State " ++ label ++ " now is " ++ (show state))