Translate

viernes, 2 de noviembre de 2012

Crear Interfaces Gráficas en Lisp con LTK (cuarta parte)

Responder a Eventos

Para responder a eventos como ratón o teclado, etc. se puede usar bind, la sintaxis del comando es asi:

> (bind nombre-control "<nombre-evento>" (función))
Nota: En LTK los controles son llamados "widgets"

Los nombres de los eventos van encerrados siempre entre dobles comillas "" y los caracteres < y >. Por ejemplo, para cambiar de color una etiqueta cada vez que se entra con el puntero del ratón:

> (bind etiqueta "<Enter>" (lambda(x) (configure etiqueta :foreground "green")))

Si queremos que se produzca una acción, luego de haber presionado el botón izquierdo del ratón:

> (bind boton "<Button-1>" (lambda(x) (do-msg "te amo Maria")))

Que nos muestra un bonito mensaje, al presionar un botón
El siguiente ejemplo nos muestra algunos eventos comunes:

Para probarlo, copie el siguiente texto y guárdelo en un archivo "eventos.lisp" luego carguelo o ejecutelo con su lisp.

;;;----------------------------------------------------------------------------------------------------------------

(load "~/ltk-0.96/ltk.fas")           

(use-package :ltk)                       


(with-ltk()                           
    (let* ((entrada (make-instance 'entry :width 20))       
           (etiqueta (make-instance 'label :text "Gol de Messi"))
       (marco (make-instance 'frame))                 
       (boton (make-instance 'button :master marco :text "Aceptar"))) 
             

      (bind etiqueta "<Enter>" (lambda(x) (configure etiqueta :foreground "green")))   
      (bind etiqueta "<Leave>" (lambda(x) (configure etiqueta :foreground "red")))   
      (bind boton "<Button-1>" (lambda(x) (do-msg "te amo Maria")))              
      (bind etiqueta "<Double-Button-1>" (lambda(x) (do-msg "Doble click del ratón")))       
      (bind boton "<Button-3>" (lambda(x) (do-msg "Botón derecho del ratón")))   
      (bind boton "<Button-2>" (lambda(x) (do-msg "Botón central del ratón")))
      (bind entrada "<Key-a>" (lambda(x) (do-msg "Has presionado la tecla a")))            
      (bind entrada "<Key-t>" (lambda(x) (do-msg "Has presionado la tecla t"))) 
      (bind entrada "<Control-Key-t>" (lambda(x) (do-msg "Has presionado Ctrl + t")))
      (bind entrada "<Control-Alt-Key-m>" (lambda(x) (do-msg "Has presionado Ctrl + Alt + m")))
      (bind entrada "<Escape>" (lambda(x) (do-msg "Has presionado la tecla Escape")))

      (pack etiqueta)                       
      (pack entrada)                       
      (pack marco)                       
      (pack boton)                       
      (configure marco :borderwidth 3)               
      (configure marco :relief :raised)))           
  
;;;----------------------------------------------------------------------------------------------------------------
    



- Esto de los eventos, me da curiosidad...

La siguiente tabla muestra los eventos y sus modificadores:



Evento
Descripción
Modificadores
(los modificadores van separados entre guiones "-" )
ButtonPres, Button, B Se ha presionado uno de los botones del ratón. "<Button-1>": Se presiona el botón izquierdo del ratón
"<Button-2>" Se presiona el boto central del ratón
"<Button-3>" Se presiona el botón derecho del ratón
Double: Doble click con uno de los botones del ratón.
Ejemplo:
"<Double-Button-1>": Doble click con el botón izquierdo
Triple: Triple click con uno de los botones del ratón.
Buttonrelease Se ha dejado de presionar uno de los botones del ratón.

Configure El control ha cambiado de tamaño, posición, etc.

Destroy El control ha sido destruido

Enter El puntero del ratón ha entrado en el control

Leave El puntero del ratón ha abandonado el control

FocusIn El control ha tomado el foco.

FocusOut El control ha perdido el foco.

KeyPress, Key, K Se ha presionado una tecla. Va acompañado de la tecla que se presiona, por ejemplo:
"<Key-a>" "<Key-b>" "<Key-m>"
Los modificadores son: Control, Shift, Lock y Alt para las teclas: control, mayúsculas, bloqueo de mayúsculas y Alt, respectivamente. Ejemplos:
"<Control-Key-t>" Se ha presionado Control + t.
"<Shift-Key-b>" Se ha presionado Shift + b.
"<Control-Alt-Key-m>" Se ha presionado Control + Alt + m.
También existen unas teclas ya definidas, tales como:
"<Return>", "<Escape>", "<BackSpace>", "<Tab>", "<Up>", "<Down>", "<Left>", "<Right>", etc.
KeyRelease Se ha soltado la tecla presionada.

Motion El puntero del ratón se mueve sobre el control.

Map La ventana ha sido desplegada.

Unmap La ventana ha sido iconificada.


En este sitio hay un tutorial muy bueno sobre LTK de una universidad española:
 tutorial - capitulo 12

Saludos, comenten :-P

sábado, 8 de septiembre de 2012

Funciones de mapeo sobre listas

Si se tiene una lista, y se desea realizar operaciones o modificaciones para cada elemento de dicha lista, obteniendo otra de la misma longitud, se puede utilizar una función de mapeo. mapcar es la mas común de tales funciones. mapcar toma una función y uno o más listas, y aplica esa función a cada elemento de la lista, produciendo una nueva lista resultante.

 > (setq una-lista '(1 2 3 4 5))

UNA-LISTA

> (defun doble (n) (* n 2))

DOBLE

> (setq otra-lista (mapcar #'doble una-lista))

(2 4 6 8)

Observe el signo #' antes de la función doble. DOBLE es el nombre del símbolo, (definido previamente con defun), que contiene a la función. La notación #' permite acceder al espacio de función del símbolo DOBLE y pasarla como argumento a mapcar.





- Maestro, ¿¡se pueden pasar funciones como argumentos...!?

- Si, pequeño saltamontes, pues las funciones son tipos de datos en Lisp, sigue practicando...

Otro ejemplo:


> (setq cadenas '("argentina gano tres a uno" "Messi hizo un gol" "Paraguay concreto de penal"))

("argentina gano tres a uno" "Messi hizo un gol" "Paraguay concreto de penal")

> (defun cambia-letra (una-cadena) (substitute  #\@ #\e una-cadena))

CAMBIA-LETRA

> (cambia-letra "cielo celeste")

“ci@lo c@l@st@”

> (setq nuevas (mapcar #'cambia-letra cadenas)


("arg@ntina gano tr@s a uno" "Lio M@ssi hizo un gol d@ tiro libr@" "Paraguay concr@to d@ p@nal")
Para no tener que definir funciones a cada rato, existe la función "sin nombre", lambda que puede pasarse como argumento a mapcar, ahí mismo donde se define.
Para el primer ejemplo de la función doble, sería asi:

> (setq otra-lista (mapcar 

                                      #'(lambda (n) (* n 2)) 
                                      una-lista))
(2 4 6 7)

Para el segundo:

(setq nuevas (mapcar 
                       #'(lambda (una-cadena) (substitute #\@ #\e una-cadena)) 
                       cadenas))

("arg@ntina gano tr@s a uno" "Lio M@ssi hizo un gol d@ tiro libr@" "Paraguay concr@to d@ p@nal") 
Bien, lambda es la función sin nombre. Permite definir de manera instantánea la función que se va a pasar como argumento. Se usa de la siguiente manera:

(lambda (argumento) (cuerpo de la función))

some

Devuelve una valor booleano (T o NIL) si algún elemento de la lista verifica la función aplicada.

> (some #'(lambda (x) (> x 9)) '(1 2 3 4 4 6 78 13))
T

Solo basta que la función que se le pasa como argumento sea booleana, es decir que devuelva T o NIL. Aquí otro ejemplo, no se desespere:

> (some #'(lambda (x) (equal x 'futbol)) '(futbol basquet voley handball golf))
T

every

Esta es como la anterior, pero todos los elementos de la lista deben cumplir con la función que se le pasa de argumento.
> (every #'(lambda (x) (atom x)) '("agua" "gota" "barco" "cielo"))
T

atom pregunta si algo es un atomo o una lista. Si es un atomo tal como pueden ser un número, una cadena e incluso una variable, es decir es un solo elemento, devuelve T, si se trata de una lista devuelve NIL.

> (setf lista ‘(1 3 6 45 2))
> (every #'(lambda (x) (>= x 3)) lista)
NIL

apply

Su nombre mismo lo indica, “apply”ca la función a todos los elementos, solo que esta devuelve un solo valor, el valor acumulado.

> (apply #’+ lista)
57

> (apply #’append ‘((a b c) (1 5 9) (“Armando” “Esteban” “Quito”)))
(A B C 1 5 9 "Armando" "Esteban" "Quito")

remove-if

No modifica la lista actual, pero devuelve una lista como resultado de haber eliminado los elementos que verifican la función que se le pasó como argumento.

> (remove-if #'(lambda (x) (> x 5)) lista)
(1 3 2)

>  (remove-if #'atom '("Laurita" 5 ("Jose" valor) (4.1 19 #c(2 3)) “renegado”))
(("Jose" VALOR) (4.1 19 #C(2 3)))

Saludos. Comenten.  :-D

martes, 17 de julio de 2012

Crear Interfaces Graficas en Lisp con LTK (tercera parte)


Voy a mostrar un ejemplo de una aplicación con interfaz grafica:

cortar aqui
;----------------------------------------------------------------------------------------------------------------

(load "~/Descargas/ltk-0.96/ltk.fas")            ;cargo ltk desde la ruta donde lo guarde :)

(use-package :ltk)                        ;para usar los paquetes ltk


(with-ltk()                           
    (let* ((entrada (make-instance 'entry :width 20))        ;crea cuadro de entrada de ancho 20
           (etiqueta (make-instance 'label :text "Gol de Messi")) ;crea etiqueta
       (marco (make-instance 'frame))                  ;crea marco
       (boton (make-instance 'button :master marco :text "Aceptar"  ;crea boton dentro de marco
        :command (lambda() (do-msg "te amo Talia :-)")))))      ;al pulsar envia un mensaje


      (pack etiqueta)                     ;coloca la etiqueta dentro del form
      (pack entrada)                     ;coloca el cuadro de entrada
      (pack marco)                       ;coloca el marco
      (pack boton)                        ;coloca el boton
      (configure marco :borderwidth 3)                ;ajusta el ancho del borde del marco
      (configure marco :relief :raised)                ;ajusta el estilo del marco
        
      ))

;-------------------------------------------------------------------------------------------------------------

Se copia el texto de arriba en un archivo y se guarda como "ejemplo.lisp"
Para ejecutarlo (con clisp) se abre una terminal y se teclea:

> clisp ~/ejemplo.lisp



No debería ser muy distinto con otros sistemas Lisp. Obviamente se debe  colocar la ruta completa donde quedó guardado el archivo.
Mas adelante veremos como manejar eventos como hacer click con el mouse sobre un objeto, pasar con el raton por encima, presionar una tecla, etc.

domingo, 15 de julio de 2012

Listas (cuarta parte): Diversas funciones utiles


¿Es una Lista...?

 Para saber si un objeto es una lista o no, usamos la función Listp. Los valores devueltos pueden ser T (verdadero) o nil (falso).

 > (setq una-lista '("hola" "estoy a 200 km de casa" "vacaciones"))
("hola" "estoy a 200 km de casa" "vacaciones")

> (listp una-lista)
T

> (setq valor 38)
38

> (listp valor)
NIL

> (setq valor "grados")
"grados"

> (listp valor)
NIL

Lista vacía

La función null nos dirá si una lista esta vacía, es decir, que no tiene elementos. null devuelte T si la lista está vacía, caso contrario devuelte NIL. 

> (set 'lista '("hola" "como" "estas")
("hola" "como" "estas")

> (null lista)
NIL

> (set 'lista nil)
NIL

> (null lista)
T

Longitud de una lista


La longitud de una lista se obtiene con la función length:

> (setq una-lista '("uno" "dos" 3 "cuatro" 5.0 6e00))
("uno" "dos" 3 "cuatro" 5.0 6.0)

> (length una-lista)
6

Obtención de parte de una lista

subseq es una función común que se usa para devolver parte de una lista. Toma al menos dos argumentos, una lista y un entero que indica la posición desde donde empezar. También toma un tercer argumento optativo, un entero que indica la posición donde detenerse. Observe que la posición indicada por este tercer argumento no se incluye en el la sub-lista devuelta:

> (setq una-lista '("uno" "dos" "tres" "cuatro" "cinco"))
("uno" "dos" "tres" "cuatro" "cinco")

> (setq otra-lista (subseq una-lista 1 3))
("dos" "tres")

> (setq otra-lista (subseq una-lista 0 2))
("uno" "dos")

> (setq otra-lista (subseq una-lista 1))
("dos" "tres" "cuatro" "cinco")

Unir varias listas en una sola


Las listas se pueden unir con append:

> (setq lista-uno '(1 2 3 4 5 6))
(1 2 3 4 5 6)

> (setq lista-dos '("esto" "es" "una" "lista"))
("esto" "es" "una" "lista")

> (setq lista-tres '("Maria" "te" "amo"))
("Maria" "te" "amo")

> (setq lista-unica (append lista-uno lista-dos lista-tres))
(1 2 3 4 5 6 "esto" "es" "una" "lista" "Maria" "te" "amo")

Ordenar listas


Las listas se ordenan con sort:

> (setq lista-valores '(23 15 33 789 3 102 18))
(23 15 33 789 3 102 18)

> (sort lista-valores #'<)
(3 15 18 23 33 102 789)

> (sort lista-valores #'>)
(789 102 33 23 18 15 3)

El resto de una lista

La función rest devuelve la misma lista pero sin el primer elemento, es decir, devolverá el resto de la lista, luego de extraer el primer elemento. Su valor deberá ser almacenado debido a que rest es no destructiva:

> (set 'primos '(2 3 5 7 11 13 17 19 23))
(2 3 5 7 11 13 17 19 23)

> (set 'resto (rest primos))
(3 5 7 11 13 17 19 23)

Listas (tercera parte): Remover y Agregar elementos


Para remover elementos de una lista se usa la función remove:

> (setq una-lista '(15 33 "edad" 7/8))
(15 33 "hoy es domingo" 7/8)

 > una-lista
(15 33 "hoy es domingo" 7/8)

>  (remove 33 una-lista)
(15 "hoy es domingo" 7/8)

Se ha removido 33 de la lista. Sin embargo la función remove es no destructiva, por lo que no se ha modificado una-lista.

> una-lista
(15 33 "hoy es domingo" 7/8)


Por lo tanto deberíamos guardar la lista devuelta por la función:

> (setq una-lista (remove 33 una-lista))
(15 "hoy es domingo" 7/8)

> una-lista
(15 "hoy es domingo" 7/8)

Para agregar elementos se puede usar la función cons:

> (setq una-lista (cons "mañana es lunes..." una-lista))
("mañana es lunes..." 15 "hoy es domingo" 7/8)

> una-lista
("mañana es lunes..." 15 "hoy es domingo" 7/8)

Otra manera de agregar elementos es usando push. Una lista se puede tratar como una estructura de pila LIFO. Antes de poner cualquier valor, la lista debe tener algún elemento o estar vacía (tener el valor nil). 

Primero me aseguro de crear una lista vacía:

> (setf una-lista nil) 
NIL

> (push "hola" una-lista)
("hola")

> (push 23 una-lista)
(23 "hola")

> (push () una-lista)
(NIL 23 "hola")

> (push "te amo Maria" una-lista)
("te amo Maria" NIL 23 "hola")

> (push 8.5 una-lista)
(8.5 "te amo Maria" NIL 23 "hola")

Para sacar usamos pop:

> (pop una-lista)
8.5

Pero los valores que quitamos se perderían de no ser asignados:

> (setq hermosa (pop una-lista))
"te amo Maria"

> hermosa
"te amo Maria"

Listas (segunda parte) Acceder a los elementos de una lista


Para acceder al primer elemento se usa first:

> (setq una-lista '("uno" "dos" "tres" "cuatro" "cinco"))
("uno" "dos" "tres" "cuatro" "cinco")

> (setq cadena (first una-lista))
"uno"

Accede al primer elemento de la lista una-lista y guarda el valor devuelto en el simbolo cadena.

> cadena
"uno"

Para acceder al segundo y al tercero, second y third, respectivamente:

> (setq cadena (second una-lista))
"dos"

> (setq cadena (third una-lista))
"tres"

Para obtener cualquier elemento de una lista, se puede usar nth:

> (setq cadena (nth 4 una-lista))
"cinco"

> (setq cadena (nth 0 una-lista))
"uno"

> (setq cadena (nth 2 una-lista))
"tres"

Al primer elemento se accede con 0 al segundo con 1, y asi sucesivamente.

Para acceder al ultimo elemento de una lista se puede usar last:

> (setq cadena (last una-lista))
"cinco"




martes, 10 de julio de 2012

Crear Interfaces Gráficas en Lisp con LTK (Segunda parte)

Voy a mostrar algunos ejemplos de interfaces graficas. Son ejemplos tontos que escribí hace ya algun tiempo experimentando con LTK. Es nada mas que para mostrar las funcionalidades.

Con el archivo ltk.fas previamente cargado y estando dentro del paquete ltk, cargamos el archivo hola.lisp.

Que podes descargarlo desde aca:  hola.lisp

1. Entra al Lisp:
> clisp
>

2. Ahora carga el ltk.fas:

> (load "~/Descargas/ltk.fas")

3. Tenes que estar dentro del paquete ltk:

> (in-package :ltk)

4. Carga el archivo hola.lisp que descargaste:

> (load "~/Descargas/hola.lisp")

5. Ya está. Listo para probar los ejemplos

> (hola-1)
-----------------------------------------
> (hola-2)
-----------------------------------------
> (test)
-----------------------------------------
> (test-2)
-----------------------------------------
> (test-3)
Y asi sucesivamente, hasta test-6 inclusive.
 
Dentro del archivo de texto "hola.lisp" podes ver el codigo de los ejemplos con cualquier editor de textos. Ok, :-) 
Aquí una guía en ingles para ltk, ltk.doc.