Vamos a aprender otro modo de empaquetar: las tablas. Pueden ser extremadamente útiles en determinadas situaciones. Usando tablas, creamos una cuadrícula (grid) en la que podemos situar los widgets. Los widgets pueden ocupar tantos espacios como especifiquemos.
En primer lugar consideraremos la función tableNew
(Nueva tabla)):
tableNew :: Int -> Int -> Bool -> IO Table
El primer argumento es el número de filas que tendrá la tabla, y el segundo, el número de columnas.
El argumento booleano (homogéneo) indica como se establece el tamaño de las cajas de la tabla. Si homogéneo se establece a True, entonces las cajas se crean al tamaño del mayor widget de la tabla, y todas iguales. Si homogéneo se establece a False, el tamaño de las cajas de la tabla está determinado por el widget más alto de su fila, and el widget más ancho de su columna. Por ejemplo, supón que tienes una matríz de 10x10 botones cada uno etiquetado con los numeros del 1 al 100. Así, te aparecen tres posibles anchuras, la de los números del 1 al 9, la de los números del 10 al 99 y la del 100. Si has establecido en True el valor de homogéneo, todos los botones serán iguales y el ancho corresponderá al del botón 100. Sin embargo, si el valor que has puesto es Falso, la última columna mantendrá el ancho del botón de 100 y las otras el de los botones correspondientes al 10 al 99. En este ejemplo las alturas de los botones serían iguales con las dos opciones, ya que sólo tenemos una posible altura.
Las filas y colunas se numeran desde 0 hasta n, donde
n es el número especificado en la llamada a tableNew
. Así
si especificas filas = 2 y columnas =
2, la distribución parecerá algo así:
0 1 2 0+----------+----------+ | | | 1+----------+----------+ | | | 2+----------+----------+
Fíjate en que el sistema de coordenadas empieza en la esquina superior izquierda. Para colocar un widget en una caja, usa la siguiente función:
tableAttach :: (TableClass self, WidgetClass child) => self -- self - La tabla. -> child -- child - El widget a añadir. -> Int -- leftAttach - El número de la columna para situar el lado izquierdo -- del widget a colocar. -> Int -- rightAttach - El número de la columna para situar el lado derecho -- del widget a colocar. -> Int -- topAttach - El número de la fila donde situar la parte superior del -- widget a colocar. -> Int -- bottomAttach - El número de la fila donde situar la parte inferior del -- widget a colocar. -> [AttachOptions] -- xoptions - Se emplea para indicar las propiedades del widget hijo -- cuando la tabla modifica su tamaño (horizontales) -> [AttachOptions] -- yoptions - Igual que xoptions, exceptuando que el campo determina -- el comportamiento vertical -> Int -- xpadding - Un valor entero que especifica el espacio en blanco a -- izquierda y derecha de la tabla del widget que se añade. -> Int -- ypadding - El espacio arriba y abajo del widget. -> IO ()
El primer argumento, (self), es la tabla que has creado y el segundo, (child), es el widget que quieres colocar en la tabla.
Los argumentos izquierdo y derecho (leftAttach, rightAttach) indican donde debe ponerse el widget, y cuantas cajas usar. Si quieres poner un botón en la parte de abajo a la derecha de tu tabla de 2x2, y quieres colocar solo esa entrada, leftAttach debería ser = 1, rightAttach = 2, topAttach = 1, y bottomAttach = 2.
Ahora, si quieres que un widget llene completamenta la fila superior de nuestra tabla de 2x2, deberías susar los siguientes valores: leftAttach = 0, rightAttach = 2, topAttach = 0, and bottomAttach = 1.
xoptions y yoptions se usan para indicar las opciones de empaquetado y la lista puede contener más de una para permitir múltiples opciones.
Las posibles opciones son:
Fill
Fill
,
el widget se expandirá hasta ocupar todo el espacio disponible. (como un gas cualquiera).
Shrink
Shrink
los widgets de reducirán con la tabla.
Expand
El padding funciona como en las cajas, dejando un área libre alrededor del widget, del tamaño especificado en píxeles
tableAttach
tiene muchas opciones, así que ponemos un resumen:
tableAttachDefaults :: (TableClass self, WidgetClass widget) => self -- self - La tabla. -> widget -- widget - El widget a añadir. -> Int -- leftAttach - El número de la columna en el que se situará el lado -- izquierdo del widget a añadir. -> Int -- rightAttach - El número de la columna en el que se situará el lado -- derecho del widget a añadir. -> Int -- topAttach - El número de la fila en el que se situará el lado superior -- del widget. -> Int -- bottomAttach - El número de la fila en el que se situará el lado inferior -- del widget. -> IO ()
Los valores usados para los parámetros de [AttachOptions]
son
[Expand, Fill], y el espacio (padding) se fija en 0. El resto de los
argumentos son los mismos que para la función previa.
También tenemos tableSetRowSpacing
y
tableSetColSpacing
. Estas funciones colocan espacios en la fila (row) o columna (col) indicada.
tableSetRowSpacing :: TableClass self=> self-> Int -> Int -> IO ()
tableSetColSpacing :: TableClass self => self -> Int -> Int -> IO ()
El primer argumento Int
es la fila/columna y el segundo es el espacio
en píxeles. Fíjate que en el caso de las columnas, el espacio se situa a la derecha de
la columna y en las filas, bajo la fila.
Puedes fijar un espacio fijo para todas las filas y/o las columnas con:
tableSetRowSpacings :: TableClass self=> self-> Int -> IO ()
y:
tableSetColSpacings :: TableClass self => self -> Int -> IO ()
Fíjate que con estas llamadas, la última fila y la última columna no consiguien ningún espacio.
Vamos a hacer una ventana con tres botones en una tabla 2x2. Los primeros dos botones se colocarán en la fila de arriba. Un tercer botón (Quit) se colocará en la fila de abajo, ocupando ambas columnas. Quedará así:
Aquí está el código fuente:
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 función buttonSwitch
es asocia a ambos botones de la fila superior.
La función buttonGetLabel
es un ejemplo de cómo conseguir un atributo
de un widget usando un método estándar. Hay una alternativa más general get
(análoga a set
) que toma un widget y un atributo.
En el ejemplo anterior sería:
txt <- get b buttonLabel
con el mismo resultado.