My projects website

I have uploaded some of my projects to dotsboxes.tk.

sábado, 27 de septiembre de 2008

Crear widgets en Dr. Scheme

Haciendo una progra en Dr Scheme (el administrador de álbumes para Ruidosa S.A.) quise usar una tabla para mostrar la información sobre los álbumes, etcétera. Investigando en la documentación descubrí la pavorosa noticia: ¡Mr. Ed NO tiene tablas!

Para solventar esto inicialmente usé varias list-box% pegadas, pero como el resultado es estéticamente feo (y quise agregar extras a la tabla) me decidí por implementar por completo mi propio widget.

Un "widget" en Scheme en realidad es una clase que extiende a otra clase que sí es un widget. Cuando hagamos nuestros widgets lo más probable es que extendamos alguna clase horizontal-panel%, vertical-panel%, o canvas%. También puede usar cualquier otro control si lo desea. La imagen es una captura de mi widget tabla. Esta permite añadir texto o imágenes a una columna, añadir filas, encabezado, cambiar el tamaño de las columnas y autoordenar por columna al hacer clic en el encabezado. Este una extensión de la clase canvas%.

Un widget tiene como ventaja que se puede programar una vez y usarse muchas veces, incluso en proyectos ajenos (obviamente si está bien diseñado). También se caracteriza porque cada instancia es independiente de las demás. Por ejemplo, podemos crear un widget formulario y los datos de cada formulario estarán aislados de los otros.

A por el código

El código propio del widget no es muy diferente a cualquier otro programa de Scheme. "Simplemente" hay que programar todo el comportamiento de este, que sucede cuando recibe el foco, cuando lo pierde, cuando recibe clics, teclasos, etc. La parte diferente viene acá:

(module advTable
  mzscheme
  
  (provide (all-defined))
  
  (require  (lib "mred.ss" "mred")
            (lib "class.ss")
            (file "sortCadenas.ss"))
  
  (define advanced-list%
    (class canvas%
      (init-field parent)
      (init-field callback)

      (super-new (parent parent)(min-width 500)(horiz-margin 2)(vert-margin 2)
                 (paint-callback (lambda (cnv dc)(Redibujar cnv dc)))
                 (style '(control-border vscroll hscroll)))

   ;...
   ;el resto del código va aquí
   ;...
   ;hay que cerrar los paréntesis :)

  1. El "module advTable" indica que se desea crear un módulo, en este caso llamado advTable.
  2. La instrucción (provide (all-defined)) indica que el módulo expone al exterior todas las funciones definidas (esto tal vez no es algo deseado, pero esto lo programé en aquellos tiempos que...).
  3. Luego vienen las instrucciones "require": las dos primeras aparentemente son necesarias, la última es de una clase auxiliar de mi programa.
  4. Luego viene la definición del widget propiamente dicha. En este caso la variable se llama advanced-list% (para seguir con los nombres de Dr. Scheme...). Como se ve el valor de la variable es una clase canvas%.
  5. Los init-field sirven para especificar valores a la hora de crear el widget en el programa (mas tarde hablaré de ellos).
  6. Para finalizar el super-new lo que hace es que instancia la clase padre del widget, en este caso un canvas%, de estos parámetros todos son los normales a la hora de crear un canvas% excepto quizá (lambda (cnv dc)(Redibujar cnv dc)). Esta es una función que redibuja la canvas% y está dentro del widget. Quizá hayan notado que hay un (init-field parent) y un (parent parent); las palabras en rojo se refieren a la misma variable.
  7. El canvas% tiene funciones propias, como on-event, on-size, entre otras. Lo que debemos hacer para implementar nuestras funciones es suplantar estas funciones. Esto se hace definiendo la función con el mismo nombre, pero en lugar de usar un define se escribe define/override. Esto indicará a Scheme que se desea suplantar la función actual por esta. Es importante verificar que nuestra función tenga la misma sintaxis que la original.

Finalmente para poder usar nuestro widget en nuestro programa debemos el siguiente código al principio del programa:

(require (file "advTable.ss") ; así se llama nuestro archivo con el widget
         ;... otras bibliotecas que se requieran...
         )

Y ya podemos usar nuestro widget como cualquier otro. Por ejemplo para crear una instancia de la tabla se usaría el siguiente código:

(define tbxRecorridos (new advanced-list%
                           (parent panRecorridos) ; formulario padre que contiene el widget
                           (callback recorridosCallback) ; función a la que se llamará 
                                                         ; cuando ocurra un evento
                           )
  )

Nótese que "parent" y "callback" son los nombres especificados en los init-field del widget.

No hay comentarios:

Publicar un comentario

Podés usar las etiquetas html "b", "i" y "a" para negrita, cursiva y vínculos respectivamente.
No agregue correos electrónicos directamente. Puede agregarlos poniendo algo como "soy fulanito con correo en hotmail, obviamente com". Se evitarán que ladrones como los de NovalGraphics les envíen spam (nadie sabe de donde roban los correos, entonces mejor prevenir).

Entradas relacionadas

Related Posts with Thumbnails