jueves, 27 de noviembre de 2008

Primeros pasos con LTK (parte 3)

A vueltas con el pack

Hoy vamos aprender a colocar nuestros widgets en la pantalla. Quizás no sea un tema muy atractivo, pero sí es absolutamente necesario, así que pongámonos manos a la obra.

Vamos a empezar por crear unas cuantas etiquetas que iremos posicionando de distintas maneras.

(let
(
(marco (make-instance 'frame :master nil ))
(etiqueta1 (make-instance 'label :master marco :text "Etiqueta 1"))
(etiqueta2 (make-instance 'label :master marco :text "Etiqueta 2" ))
(etiqueta3 (make-instance 'label :master marco :text "Etiqueta 3" ))
(etiqueta4 (make-instance 'label :master marco :text "Etiqueta 4" ))
)
)


El código de arriba nos crea las etiquetas pero no se ocupa de posicionarlas en la pantalla. Es ahora cuando entra en juego el pack. Empecemos por ver cómo las posiciona por defecto:

(with-ltk ()
(let*

(
(marco (make-instance 'frame :master nil ))

(etiqueta1 (make-instance 'label :master marco :text "Etiqueta 1"))
(etiqueta2 (make-instance 'label :master marco :text "Etiqueta 2" ))
(etiqueta3 (make-instance 'label :master marco :text "Etiqueta 3" ))
(etiqueta4 (make-instance 'label :master marco :text "Etiqueta 4" ))

)
(pack marco)
(pack etiqueta1 )
(pack etiqueta2 )
(pack etiqueta3 )
(pack etiqueta4 )
)
)

Por defecto, pack coloca los widgets de arriba a abajo. El resultado del código anterior es lo siguiente:


Es importante darse cuenta de que LTK no muestra los widgets en el orden en que fueron creados, sino en el orden en que se llama a pack. En el ejemplo anterior, ha puesto arriba a etiqueta1 porque ha sido la primera con la que hemos llamado a pack, pero podríamos hacerlo de cualquier otra manera:





(let*
(
(marco (make-instance 'frame :master nil ))
(etiqueta1 (make-instance 'label :master marco :text "Etiqueta 1"))
(etiqueta2 (make-instance 'label :master marco :text "Etiqueta 2" ))
(etiqueta3 (make-instance 'label :master marco :text "Etiqueta 3" ))
(etiqueta4 (make-instance 'label :master marco :text "Etiqueta 4" ))
)
(pack marco)
(pack etiqueta4 )
(pack etiqueta2 )
(pack etiqueta1 )
(pack etiqueta3 )
)
y el resultado sería que los widgets se muestran en otro orden, que no tiene nada que ver con el orden en el que fueron creados:


Ahora vamos a situar los widgets lateralmente. Para ello sólo debemos hacer uso de la opción :side del pack. Veamos un ejemplo:

(with-ltk ()
(let*
(
(marco (make-instance 'frame :master nil ))
(etiqueta1 (make-instance 'label :master marco :text "Etiqueta 1"))

(etiqueta2 (make-instance 'label :master marco :text "Etiqueta 2" ))
(etiqueta3 (make-instance 'label :master marco :text "Etiqueta 3" ))
(etiqueta4 (make-instance 'label :master marco :text "Etiqueta 4" ))
)

(pack marco)
(pack etiqueta1 :side :left)
(pack etiqueta2 :side :left)
(pack etiqueta3 :side :left)
(pack etiqueta4 :side :left)
)
)

El resultado es que los widgets se situan de izquierda a derecha:

También podemos situarlos de derecha a izquierda usando :side :right:

(with-ltk ()
(let*

(
(marco (make-instance 'frame :master nil ))
(etiqueta1 (make-instance 'label :master marco :text "Etiqueta 1"))
(etiqueta2 (make-instance 'label :master marco :text "Etiqueta 2" ))
(etiqueta3 (make-instance 'label :master marco :text "Etiqueta 3" ))
(etiqueta4 (make-instance 'label :master marco :text "Etiqueta 4" ))
)
(pack marco)
(pack etiqueta1 :side :right)
(pack etiqueta2 :side :right)
(pack etiqueta3 :side :right)
(pack etiqueta4 :side :right)
)
)

Fijáos cómo la etiqueta1 ahora está a la derecha:


Por último, veremos cómo poner las etiquetas de abajo a arriba. Esto no suele ser muy útil porque es lo mismo que ponerlas de arriba a abajo llamando a pack en orden inverso, pero lo pongo por completitud. Se hace justo como suponéis, usando :side :bottom:
(with-ltk ()
(let*

(

(marco (make-instance 'frame :master nil ))
(etiqueta1 (make-instance 'label :master marco :text "Etiqueta 1"))
(etiqueta2 (make-instance 'label :master marco :text "Etiqueta 2" ))
(etiqueta3 (make-instance 'label :master marco :text "Etiqueta 3" ))
(etiqueta4 (make-instance 'label :master marco :text "Etiqueta 4" ))
)
(pack marco)
(pack etiqueta1 :side :bottom)
(pack etiqueta2 :side :bottom)
(pack etiqueta3 :side :bottom)
(pack etiqueta4 :side :bottom)
)
)
Esto es todo lo que veremos hoy sobre pack. Con lo que ya sabéis podéis crear interfaces complicadas. ¿Cómo? Solamente habéis de crear marcos y meter los widgets en ellos en el orden adecuado. En el capítulo sobre el widget frame veremos como hacer esto.

El grid

Aunque en principio no pensaba tratarlo, voy a hablar un poco sobre grid. Es un geometry manager distinto a pack. No deben mezclarse pack y grid en el mismo marco porque podemos crear un pequeño desastre con la colocación de los widgets. De todas formas, grid es útil porque lo que hace es situar los widgets en una cuadrícula, de forma que nos simplifica la vida en aplicaciones tipo hojas de cálculo y similares. Su sintaxis básica es muy sencilla:

(grid widget fila columna)

Fila y columna son enteros, representan el número de fila y columna (lógico). La primera fila es la 0, al igual que la primera columna. Veamos cómo situar nuestras 4 etiquetas en una rejilla 2x2:

(with-ltk ()
(let*

(
(marco (make-instance 'frame :master nil ))
(etiqueta1 (make-instance 'label :master marco :text "Etiqueta 1" ))
(etiqueta2 (make-instance 'label :master marco :text "Etiqueta 2" ))
(etiqueta3 (make-instance 'label :master marco :text "Etiqueta 3" ))
(etiqueta4 (make-instance 'label :master marco :text "Etiqueta 4" ))
)
(pack marco)
(grid etiqueta1 0 0)
(grid etiqueta2 0 1)

(grid etiqueta3 1 0)
(grid etiqueta4 1 1)
)
)

El resultado es el esperado:



Para finalizar os voy a enseñar un pequeño truco. Si os fijáis en el ejemplo anterior, no se distinguen unas etiquetas de las otras. Eso es porque no tienen relieve. Pues bien, vamos a añadirlo! Todo widget tiene una opción llamada :relief que puede tomar varios valores. Os pongo un código de ejemplo y tratad de averiguar que hace:
(with-ltk ()
(let*
(
(marco (make-instance 'frame :master nil ))

(etiqueta1 (make-instance 'label :master marco :text "Etiqueta 1" :relief :sunken))
(etiqueta2 (make-instance 'label :master marco :text "Etiqueta 2" :relief :sunken))
(etiqueta3 (make-instance 'label :master marco :text "Etiqueta 3" :relief :sunken))
(etiqueta4 (make-instance 'label :master marco :text "Etiqueta 4" :relief :sunken))
)
(pack marco)
(grid etiqueta1 0 0)
(grid etiqueta2 0 1)
(grid etiqueta3 1 0)
(grid etiqueta4 1 1)
)
)

Hemos hundido las etiquetas, de forma que la separación entre ellas queda visible. Se pueden hacer cosas más bonitas :-)

Nos vemos en el próximo post!

2 comentarios:

Anónimo dijo...

Hola, ante todo darte las gracias por compartir tus conocimientos de lisp.
Ahora a ver si puedes resolverme una duda con LTK. ¿Es posible crear botones redondos con el widget 'button en vez de cuadrados?

Muchas gracias.

Anónimo dijo...

Pues ahora mismo me has pillado. El look and feel de los botones depende de qué sistema operativo estás usando. En linux los botones de TK son feísimos. Ahora mismo no sé si se podría redondear un poco con alguna opción, pero sería sólo un poco.

Una opción más viable sería crear nosotros mismos un widget botón redondeado. Hay varias formas de hacer esto. Por ejemplo, podemos dibujar un óvalo y hacer que responda a los eventos como lo haría un botón. Esto no sería difícil, quizás lo comente en el próximo post (por cierto, perdonad por la tardanza en publicar, es que estoy de exámenes).

Otra manera de hacerlo sería crear una imagen bonita y insertarla, por ejemplo, en una etiqueta. Si hacemos que responda a los eventos que nos interesan, también tendremos un bonito botón.

Luego te miro lo de los estilos.

Adew!