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!

miércoles, 5 de noviembre de 2008

Primeros pasos con LTK (parte 2)

Hola!

Hoy vamos a seguir con la introducción a LTK que iniciamos hace unos días.

Empezaremos por comentar el ejemplo que ya vimos y que nos mostraba "Hola, mundo" en una etiqueta:

(use-package :ltk )
(with-ltk ()
(let
(
( etiqueta (make-instance 'label :master nil :text "Hola, mundo" ))
)
(pack etiqueta)
)
)

Bien. La primera línea es conocida: (use-package :ltk) simplemente importa los símbolos que necesitamos, para no tener que escribir todo el rato ltk:laFuncionQueNosInteresa.

Es en la segunda línea donde empezamos a usar ltk. La macro with-ltk inicializa la librería y ejecuta todo el código que metemos en su cuerpo. Tiene unos parámetros opcionales ( en nuestro caso, la lista vacía --()-- ) que nos permiten controlar ciertas opciones de debug.

Cada tipo de widget en ltk se representa mediante una clase. Por eso, cuando llamamos a make-instance 'label estamos creando una etiqueta. Todos los widgets de ltk tienen unas opciones de inicialización comunes:
  • master : el widget padre. Si lo dejamos a nil, ltk tomará a este widget como del nivel padre
Pack es lo que se llama un "package manager", o gestor de empaquetado. Es la función que usamos cuando queremos situar un widget sobre la pantalla, y se encarga de tareas como su posición relativa a otros widgets y (en ocasiones) su tamaño. Existen varios package managers, pero pack es el más utilizado, así que será el que comentaremos aquí. Si queréis saber más sobre el resto de managers, una forma fácil de empezar es man grid o man place.

Cuando trabajamos con pack lo que hacemos es situar los widgets en cajas. Podemos elegir si situaremos estas cajas de arriba a abajo ( por defecto en pack ), de abajo a arriba, de izquierda a derecha o de derecha a izquierda. También nos permite elegir si queremos que el widget se vea elevado sobre la caja, hundido o de diversas formas.

El widget label ( la etiqueta )

El widget label es uno de los más básicos y sencillos de utilizar. Simplemente es una etiqueta donde podemos mostrar texto.

La forma más común de crear un label es mediante

(make-instance 'label :master suPadre :text "SuTexto" )

Esto ajustará automáticamente el tamaño de la etiqueta al del texto que contiene.

A veces resulta muy conveniente, a fin de realizar interfaces más bonitas, controlar el ancho de las etiquetas para que todas tengan el mismo tamaño. Esto se hace mediante la opción de inicialización :width suAncho , dónde suAncho es un entero. El ancho de un label se mide en carácteres, por tanto :width 10 significará que queremos una etiqueta con un ancho de 10 carácteres.

Evidentemente, hay muchas más opciones interesantes para los label. man label para verlas.

El widget button ( el botón )

El widget button ofrece lo que promete: un botón. Su inicialización es muy similar a la del widget label, excepto por el hecho de que nos deja proporcionarle un argumento command que es la función que ejecutará cuando sea pulsado.

(make-instance 'button :master nil :text "Pulsame"
:command ( lambda ()
(format t "Has pulsado el boton~%" )
)

A ver si imagináis que hace el código anterior.