Ya casi hemos visto todo lo que hay que ver del widget botón. Es muy sencillo.
Sin embargo hay más de una manera de crear un botón. Puedes usar las funciones
buttonNewWithLabel
o buttonNewWithMnemonic
para crear
un botón con una etiqueta, usar buttonNewFromStock
para crear un botón
que contenga una imagen y un texto de un "stock item" o usar buttonNew
para crear un botón vacío.Es cosa tuya colocarle una etiqueta o un pixmap en este nuevo botón.
Para hacer esto, crea una nueva caja y empaqueta los objetos dentro de ella usando
la función boxPackStart
(o boxPackEnd
para empezar desde el final), que ya conoces, y después usa containerAdd
para empaquetar
la caja en el botón.
Las funciones buttonNewWithMnemonic
y buttonNewFromStock
tienen un
string como primer argumento. Usa el subrayado para marcar un caracter como el "mnemonico", que
funcionará como un acelerador vía teclado. Pulsando Alt y esa tecla se activará dicho botón, sin
necesidad de pinchar con el ratón. En la segunda función, la cadena es un stockId
, un identificador
de una lista de imágenes predefinidas con etiquetas.
Aquí tenemos un ejemplo de uso de buttonNew
para crear un botón con una imagen y una etiqueta.
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 función labelBox
se puede usar para meter imágenes y etiquetas en
cualquier widget que sea simultáneamente un contenedor (container). La imagen procede de
un fichero, usando imageNewFromFile
y la etiqueta viene de labelNew
,
que utiliza un Maybe String
como argumento. Nothing
indica que no hay etiqueta.
El widget Button
tiene las siguientes señales básicas, que casi se autoexplican (si sabes inglés claro!):
onPressed
- se emite cuando el ratón es pulsado dentro del widget Button
onReleased
- se emite cuando el ratón se deja de pulsar dentro del widget Button
onClicked
- se emite cuando el ratón se pulsa y se suelta dentro del widget Button
onEnter
- se emite cuando el ratón entra en el widget Button
onLeave
- se emite cuando el ratón sale del widget Button
Nota: Normalmente el dispositivo señalador es el ratón, por eso lo indico. Para cualquier dispositivo señalador, el funcionamiento sería el mismo, así ratón = dispositivo señalador.
Los botones Toggle se derivan de los botones normales y son muy parecidos. Su única diferencia estriba en que siempre alternan entre dos estados. La alternancia se produce al ser pulsados.
Los botones Toggle son la base de de los botones check y radio, por tanto muchas de las llamadas usadas por los botones toggle son heredadas por los botones check y radio. Ya lo recordaremos cuando lleguemos a ellos.
La creación de un boton toggle:
toggleButtonNew :: IO ToggleButton toggleButtonNewWithLabel :: String -> IO Togglebutton toggleButtonNewWithMnemonic :: String -> IO ToggleButton
Como puedes imaginar, funcionan exactamente igual que con los widget botón. El primero crea un botón toggle vacío, y los dos últimos, un botón con un widget de tipo etiqueta(label) ya empaquetado con él. La variante "mnemonica" analiza la etiqueta buscando el caracter prefijado con un "_".
Para conocer el estado del botón toggle (pulsado o no pulsado), incluyendo los botones radio y check, se emplea:
toggleButtonGetActive :: ToggleButtonClass self => self -> IO Bool
Devuelve True si el botón toggle está pulsado y False si no lo está.
Para forzar el estado de un botón toggle, o sus hijos, los botones radio y check, debes emplear:
toggleButtonSetActive :: ToggleButtonClass self => self -> Bool -> IO ()
La llamada anterior se puede usar para establecer el estado del botón toggle, y sus hijos los botones radio y check. Hay que pasarle el botón creado como primer argumento y True o False como segundo argumento, para especificar el estado an el que queremos dejar el botón. El valor por defecto es "no pulsado" o False.
Fíjate que cuando usas la función toggleButtonSetActive
, y se cambia el
estado, origina que se emitan las señales onClicked
y
onToggled
del botón.
Los botones Check heredan muchas propiedades y funciones de los botones toggle, bero su apariencia es diferente. Más que ser botones con un texto dentro de ellos, son pequeños cuadrados con el texto a su derecha. A menudo se usan para marcar las opciones de una aplicación como activadas o desactivadas.
Las funciones de creación son las mismas que las de los botones normales.
checkButtonNew :: IO CheckButton checkButtonNewWithLabel :: String -> IO Checkbutton checkButtonNewWithMnemonic :: String -> IO CheckButton
La función checkButtonNewWithLabel
crea un botón check con una etiqueta junto a él.
CheckButton
es una instancia de ToggleButtonClass
y
la señal onToggled
se usa cuando un CheckButton
se marca
o se desmarca, como en el botón toggle.
Los botones Radio son parecidos a los botones check excepto que están agrupados de modo que sólo uno puede seleccionarse en cada momento. Esto es útil para los lugares del programa donde se debe seleccionar una opción de entre varias posibles. Para crear un boton radio utilizo una de estas funciones:
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
Como has visto, las últimas tres funciones tienen un argumento extra. Se usa para unir los botones nuevos a los ya construidos en un grupo.
Es una buena opción seleccionar el botón que presenta el valor por defecto con:
toggleButtonSetActive :: ToggleButtonClass self => self -> Bool -> IO ()
Esta función se describió en los botones toggle, y funciona exactamente del mismo modo.
Una vez que los botones radio se agrupan, sólo uno del grupo puede estar activo en un momento
determinado. Si el usuario pulsa en uno de los botones, y después en otro, el primer botón
radio emitirá en primer lugar una señal onToggled
(para indicar el cambio a inactivo), y
después el segundo emitirá su señal onToggled
(para indicar su cambio a activo).
El siguiente ejemplo crea un grupo de botones radio con tres botones, y cuando
el usuario pulsa uno de los botones radio, el desactivado y el activado lo indicarán
a stdout
, mediante putStrLn
en la función setRadioState
definida al final.
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))