Tutorial Tcl/Tk =========================================== Danilo Pacheco Martins Fernando Wuthstrack Jueves, 21 de Enero del 2003 Resumen: ======= Este tutorial tiene como objetivo ser una referencia en el aprendizaje del uso de Tcl/Tk. Es una herramienta óptima para desarrollo gráfico y proporciona una gran ventaja al poder ser ejecutado en varias plataformas sin que sea necesario modificar los archivos fuentes. Dudas, críticas y sugerencias favor dirigirlas al e-mail:danilo@infocont.com.br. -------------------------------------------------------------------------------- Contenido: 1.- ¿Qué es Tcl/Tk?. 2.- Conceptos básicos de Tcl/Tk. 3.- Haciendo a Cobol "conversar" con Tcl/Tk. 4.- Apéndice. -------------------------------------------------------------------------------- 1.- ¿Qué es Tcl/Tk?. Tcl (Tcl Command Language) es un lenguaje de scripts usado por medio millón de programadores alrededor del mundo y se ha tornado en un componente crítico en miles de corporaciones. Tiene una sintaxis simple y sus programas pueden ser usados como aplicaciones "standalone" o incrustadas (embedded) en otras aplicaciones. Lo mejor de todo es que Tcl es Open Source y por tanto completamente libre y gratis. Tk es un "toolkit" para crear interfaces gráficas de usuario, posibilitando así crear GUI's poderosas e increíblemente rápidas, al contrario de aplicaciones desarrolladas en otros lenguajes interpretados y hasta compilados. Ha probado ser tan popular que ahora está incorporado en todas las distribuciones Tcl. Tanto Tcl como Tk fueron desarrollados por John Ousterhout. Programadores del mundo entero han seguido el ejemplo y construyen sus propias extensiones de Tcl. Hay centenares de extensiones de Tcl para todas las necesidades de las aplicaciones. Tcl y Tk son altamente portátiles y son ejecutados en prácticamente todos los sabores de Unix, (Linux, Solaris, IRIX, AIX, *BSD*). No podemos dejar de decir que tienen soporte para Windows y Macintosh. Hay varias empresas que proveen binarios de precompiladores para varias plataformas. Tcl/Tk 8.3.4 era la versión estable para cuando se escribió este tutorial. Para esa versión fueron incluidas varias características que hacen de Tcl un lenguaje de scripts altamente recomendado para aplicaciones comerciales. Tcl/Tk 8.4a4 era la versión de desarrollo más reciente para cuando se escribió este documento. Tcl/Tk son Open Source y están en desarrollo continuo, entre los ingenieros de Scriptics (www.stripctics.com) y usuarios de la comunidad de Tcl. Striptics mantiene un repositorio CVS con el código fuente de Tcl/Tk. Todos pueden enviar adiciones y correcciones a ese código fuente de Tcl/Tk. En caso de que encuentre algún error en Tcl/Tk, usted podrá comunicarlo directamente a Scriptics utilizando un repositorio de Bugs. 1.1.- Tcl: Una plataforma de integración: Hoy en día, uno de los grandes problemas enfrentados por los desarrolladores de soluciones es la diversidad de plataformas que pueden ser encontradas en las empresas. Tcl es llamado el programa para la integración de aplicaciones. Para proyectos, la plataforma de integración resulta estratégicamente importante en cuanto al Sistema Operativo y a los Bancos de Datos. Tcl es la mejor plataforma de integración debido a su velocidad, cantidad de funcionalidades y características para proyectos de desarrollo rápido como lineas de seguridad, internacionalización y comportamiento multiplataforma. La más reciente versión de Tcl provee todas las características para satisfacer las necesidades de cualquier proyecto e incluye toda la integración necesaria en un lenguaje de scripts. Los comentarios hechos arriba tienen como base el sitio web: http://tclbrasil.cipsga.org.br/tcltk.h -------------------------------------------------------------------------------- 2.- Conceptos básicos de Tcl/Tk. 2.1.- VENTANA PRINCIPAL. 2.1.1.- Definiendo Título de la Ventana: wm title . "título de la ventana" 2.1.2.- Definiendo Tamaño de la Ventana: wm geometry . XXXxYYY Ejemplo: wm geometry . 500x500 2.2.- VARIABLES. 2.2.1.- Declarando las Variables que vienen de Cobol: Las variables recibidas de un programa Cobol tienen obligatoriamente que ser del tipo "string" y tener el mismo tamaño declarado en ambos (tanto en el programa en Cobol como en el script Tcl/Tk). La forma de pasar parámetros de Cobol a Tcl/Tk y viceversa será tratada más adelante. La siguiente declaración de grupo "cobol_fields" es obligatoria y no puede ser alterada: set cobol_fiels { variable1 5 variable2 25 variable3 40 } Observación: Un número par de nombres con su tamaño. 2.2.2.- Definiendo el valor de una Variable: Para definir el valor de una variable deberá usar la siguiente sintaxis: vnome set Jose En este caso el valor "Jose" es insertado en la variable "vnome". El valor especificado _no_ requiere estar entre comillas dobles ("") a no ser que se quiera que el valor a insertar contenga _más_ de una palabra. Ej: "Jose Da Silva". 2.2.3.- Recibiendo el valor de una Variable: Siempre que quiera recibir el valor de una variable, ésta tendrá que estar precedida por el signo dolar ($). Ej: vnome1 set $vnome2 En este caso la variable "vnome1" recibirá el valor de la variable "vnome2". 2.3.- INSERTANDO UNA CONDICIÓN: El comando "if" es utilizado para evaluar una condición pudiendo el resultado ser "verdadero" o "falso". En caso de que la condición sea verdadera se ejecutarán una serie de comandos, pero si es falsa, se ejecutarán entonces otros comandos, todo de acuerdo a lo definido por el programador. Sintaxis: if {condición1} [then] {cuerpo si verdadera} [else {cuerpo si falsa} [elseif {condición 2} {cuerpo}]] donde: {condición1}, es la primera condición a ser evaluada. [then], es opcional para la condición que será evaluada, es utilizado para indicar que es lo que será ejecutado en caso de que la condición sea verdadera. {cuerpo si verdadera}, comandos que serán ejecutados si la condición es verdadera. [else], es utilizado para indicar algo que deberá ser hecho si la condición es evaluada como falsa. {cuerpo si falso}, comandos que será ejecutados cuando la condición evaluada resulte falsa. [elseif], es utilizado para hacer una segunda verificación condicional dentro del mismo "if". {condición2}, es una segunda condición que será evaluada si existe el "elseif". {cuerpo}, lo mismo que "cuerpo si verdadera". 2.4.- INSERTANDO UNA RUTINA DE REPETICIÓN: El comando "while" permitirá ejecutar una serie de comandos en caso de que la primera condición sea verdadera. Si se verifica que dicha condición es falsa, no será ejecutado ningún comando del cuerpo de la instrucción. Es semejante al PERFORM de Cobol. Sintaxis: while {condición} {cuerpo} donde: {condición}, será la condición verificada en cada "loop" o ciclo y que indicará si continua o no el lazo o bucle de repetición. {cuerpo}, son los comandos que deberán ser repetidos en cada "loop" (ciclo). Ejemplo: set var1 0 while {$var1 < 10} incr var1 } 2.5.- PROCEDIMIENTOS: Es posible en Tcl crear Procedimientos (semejante a PERFORM en Cobol), con la siguiente sintaxis: proc asigna_valor {a b c} { set valor1 a set valor2 b set valor3 c } Una llamada al procedimiento anterior sería hecha de la siguiente manera: asigna_valor vara varb varc 2.6.- BIND: El comando "bind" es utilizado para asociar eventos del teclado o del mouse a objetos de Tk. Ejemplo: label .lab entry .entcodigo bind .entcodigo {.lab configure -text "Ha ingresado al campo de código"} bind .entcodigo {.lab configure -text "Ha salido del campo código"} En este ejemplo, cuando el cursor entra en "entcodigo" o pasa sobre la etiqueta "lab", se mostrará el mensaje "Ha ingresado al campo código" y cuando el cursor sale de allí, se mostrará el mensaje "Ha salido del campo código". 2.7.- COMPONENTES TK: Existen varios componentes de Tk. En nuestro tutorial usamos: "entry", "label", "button" y "listbox". Todo nombre atribuido a un componente debe ser precedido por un punto ".". 2.7.1.- LABEL: Label es un componente de texto usado para mostrar textos (ej: identificación de campos). Grotescamente podría ser comparado con el DISPLAY de Cobol. La sintaxis para crear un "label" es la siguiente: label nombre_del_label Ejemplo: label .codigo En este caso se ha creado un "label" (etiqueta) con el nombre "codigo". Existen varias propiedades para un "label", como por ejemplo: -text, -foreground, -background, etc. Ejemplo: label .codigo -text "Código" -foreground blue -background white En este caso el valor del [label] "codigo" será "Código" y estará escrito con letra de color azul con fondo blanco. Observación: Si Usted quiere que el texto del "label" tenga más de una palabra, deberá encerrarlo entre comillas dobles (" "). Ejemplo: -text "InfoCont Sistemas Integrados" Para asociar la propiedad -text a una variable deberá declarar dicha variable de la siguiente manera: -textvariable var En este caso, siempre que la variable "var" cambie su valor el texto del "label" también será modificado. 2.7.2.- ENTRY: Entry es un componente que permite atribuir valor y propiedades a texto introducido mediante teclado. Semejante a ACCEPT de Cobol. La sintaxis para crear un "entry" es como sigue: entry nombre_del_entry Ejemplo: entry .direccion Acá se ha creado un "entry" con el nombre "direccion". Existen varias propiedades para un "entry" como: -text, -foreground, -background, etc. Ejemplo: entry .direccion -text "Domicilio" -foreground blue -background white En este ejemplo el [entry] "direccion" actualizará el valor de la variable "Domicilio" cuyo texto lucirá con letra de color azul y fondo blanco. 2.7.3.- BUTTON: Button es un componente que ejecuta un procedimiento cuando es accionado. Su sintaxis es como sigue: button .nombre_del_botón Ejemplo: button .but En este caso se está creando un botón con el nombre "but". Existen varias propiedades para un botón, así tenemos: -text -foreground, -background, -command, etc. Ejemplo: button .but -text "Salir" -foreground blue -command {exit} Aquí, el rótulo (etiqueta) del botón "but" será "Salir" con letra azul y cerrará el panel (ventana) cuando sea pulsado. Si desea ejecutar más de un proceso cuando un botón es accionado deberá separar un proceso de otro mediante ";" (punto y coma). 2.7.4.- LISTBOX: Es un componente que muestra una lista de items. La sintaxis para crear un "listbox" es la siguiente: listbox .lista En este caso se ha creado un "listbox" con el nombre "lista". Existen varias propiedades para un "listbox", así tenemos: -selectmode, -yscrollcommand, etc. Ejemplo: listbox .lista -selectmode browse -yscrollcommand {-rolagemv set} En este ejemplo se ha definido el tipo de selección como "browse" y se asoció a una barra de desplazamiento vertical, la cual será usada cuando el número de items sea superior al tamaño físico del componente (vide scrollbar). 2.7.5.- SCROLLBAR: Es un componente que sirve como barra de desplazamiento para otros componentes. Su sintaxis es: scrollbar nombre_del_scrollbar Existen varias propiedades para un "scrollbar", a saber: -orient y -command. Ejemplo: listbox .lista -selectmode browse -yscrollcommand {-rolagemv set} scrollbar .rolagemv -orient vertical -command {.lista view} En este caso se crea una "listbox" y una "scrollbar", donde la "scrollbar" es vertical y se moverá hacia arriba y/o hacia abajo de la "lista" definida con el comando "listbox". 2.7.6.- TOPLEVEL: Es un comando que crea una nueva ventana y responde a la siguiente sintaxis: toplevel .nueva_ventana Ejemplo: toplevel .catastro Con este comando se crea una nueva ventana de nombre "catastro". Para asignar la altura a la ventana se utiliza el parámetro "-height altura_ventana", y para especificar el ancho de la ventana se usa "-width ancho_ventana". Si quiere crear algún componente dentro de la ventana, deberá colocar el nombre de esta última antes del nombre del componente, por ejemplo: button .catastro.but -text "Salir" -command {exit} En este ejemplo se crea un botón llamado "but" dentro de la ventana llamada "catastro". El rótulo o título del botón será "Salir" y cuando sea presionado se procederá a terminar el programa. 2.7.7.- PLACE: Es un comando cuya utilidad es la de posicionar objetos dentro de una ventana. Su sintaxis es como sigue: place objeto -x pos_horz -y pos_vert -height alto -width ancho Descripción de Parámetros: -x : indica cuantos pixels horizontales abarcará el objeto. -y : " " " verticales " " " . -height : indica la altura del objeto en pixels. -width : " el ancho " " " " . Ejemplo: place .label -x 10 -y 15 -height 20 -width 170 En el ejemplo, el objeto "label" estará a 10 pixels del lado izquierdo y a 15 pixels del lado superior de la ventana creada y medirá 20 pixels de alto y 170 pixels de ancho. 2.9.- Paquete IWIDGETS: El IWidget es una biblioteca que provee acceso a otros componentes, como: Combobox y EntryField (campos editados). Antes de utilizar un componente del paquete IWidgets tendrá que declarar que va a usar componentes de esa biblioteca; para hacer esto digite el siguiente comando: package require Iwidgets iwidgets::tipo_de_componente nombre_del_componente Recordando que todo componente debe ser precedido por un punto ".". En nuestro programa usamos dos componentes de IWidgets: combobox y entryfield. 2.9.1.- Componente IWidgets ENTRYFIELD: Para insertar un "entryfield" deberá usar la siguiente sintaxis: iwidgets::entryfield nombre_del_componente En nuestro tutorial usamos las siguientes opciones para crear un "entryfield": -validate y -textvariable. La opción -validate es ejecutada cuando se pulsa cualquier tecla. En nuestro programa llamamos un procedimiento de la siguiente forma: -validate {verificacion %W "%c"}. En este caso se llamará al procedimiento "verificacion" partiendo del hecho de que "%W" es el nombre del componente y "%c" es el caracter que fué insertado (digitado). 2.9.2.- Componente IWidgets COMBOBOX: Para insertar un "combobox" debe seguirse la siguiente sintaxis: iwidgets::combobox nombre_del_componente En nuestro tutorial usamos la opción -selection command, la cual disparará un comando cuando una opción sea seleccionada, Ejemplo: -selection command {set tcluf "[.cbuf getcurselection]"} En este caso, cuando una opción es seleccionada, la variable "tcluf" recibirá el valor del item seleccionado en el "combobox" (.cbuf). Para insertar un item al final de la lista del "combobox" se usa la siguiente sintaxis: nombre_combobox insert list end item_a_ser_insertado Ejemplo: .cbuf insert list end Dom Lun Mar Mie Jue Vie Sab Acá serán ingresados (agregados) los días de la semana. Para referenciar un item cuyo nombre tenga más de una palabra, deberá colocar su nombre entre comillas dobles (" "). Para definir un valor para un "combobox" deberá hacerse mediante el siguiente comando: nombre_combobox selection set item Ejemplo: .cbuf selection set $tclsem En este caso el valor definido para el "combobox" es la variable "tclsem" recordando que este item atribuido al "combobox" debe existir en la lista. En caso contrario se producirá un error, por ello debe tenerse cuidado cuando se asigna un item a una variable. -------------------------------------------------------------------------------- 3.- Haciendo a Cobol "conversar" con Tcl. 3.1.- Trabajando con las variables en Cobol: Las variables asociadas a Tcl/Tk deberán ser declaradas en el WORKING-STORAGE SECTION. Usted deberá declarar una variable de nivel 01 a la cual pertenecen las variables cuyos valores serán intercambiados. Los nombres de dichas variables quedan a su criterio. También será necesario declarar una variable de tipo COMP PIC 9(12) que servirá para contener la suma de los tamaños de las variables que serán intercambiadas Cobol <--> Tcl/Tk. Además será necesaria una variable más del tipo PIC X(64) que contendrá el nombre del programa(script) en Tcl/Tk. A continuación un ejemplo: 01 VARIABLES-TCL. 03 TCL-CODIGO PIC X(04). 03 TCL-NOMBRE PIC X(40). 03 TCL-DIRECCION PIC X(40). 01 SUMA-VARIABLES COMP PIC 9(12). 01 NOMBRE-VENTANA PIC X(64). En este ejemplo declaramos la variable "VARIABLES-TCL" en la cual están incluidas todas las variables que Tcl/Tk usará. Es imprescindible que el tamaño de las variables de Cobol sea el mismo que el de las variables declaradas en Tcl/Tk, siendo estas últimas obligatoriamente alfanuméricas (PIC X) debido a que Tcl/Tk no permite declarar campos numéricos. Luego declaramos la variable "SUMA-VARIABLES" cuyo contenido corresponderá a la suma de los tamaños de las variables declaradas en el grupo "VARIABLES-TCL". En el ejemplo de arriba, esta variable tendrá un valor igual a 84 el cual procede de (4 + 40 + 40 = 84). Posteriormente declaramos la variable "NOMBRE-VENTANA" que contendrá el nombre del programa (script Tcl/Tk) que será llamado. Digamos que hacemos un script para manejar una ventana y le damos el nombre de "catastro.tcl", entonces la variable "NOMBRE-VENTANA" recibirá ese mismo valor (catastro.tcl). Vea el punto siguiente (3.2.-) para conocer como son usadas las variables aquí definidas. 3.2.- Invocando a una Ventana: Antes que todo Usted tendrá que llamar al programa "initTcl" el cual inicializa el ambiente gráfico. Esto debe hacerse al comienzo del programa, antes de cualquier rutina. La llamada a la ventana (Tcl/Tk) es hecha a través de la rutina "chamatcl", que es un programa escrito en lenguaje C (chamatcl.c), el cual posee un interpretador de scripts Tcl/Tk. El es el responsable de mostrar la ventana y de trasladar los contenidos de las variables desde Cobol a Tcl/Tk y viceversa. Para mostrar una ventana deberá ejecutar el programa "chamatcl" mediante la sentencia CALL acompañada de las variables definidas bajo "VARIABLES-TCL", que son los campos que se intercambian entre Cobol y Tcl/Tk. La variable "SUMA-VARIABLES", que contiene la suma de los tamaños de las variables de intercambio y la variable "NOMBRE-VENTANA", que contiene el nombre del archivo script Tcl/Tk que será llamado. Usando el mismo ejemplo anterior (3.1.-): 01 VARIABLES-TCL. 03 TCL-CODIGO PIC X(04). 03 TCL-NOMBRE PIC X(40). 03 TCL-DIRECCION PIC X(40). 01 SUMA-VARIABLES COMP PIC 9(12). 01 NOMBRE-VENTANA PIC X(64). Digamos que la ventana que Usted quiere invocar se llama "catastro.tcl", entonces en Cobol haríamos de la siguiente manera: MOVE 84 TO SUMA-VARIABLES. MOVE "catastro.tcl" TO NOMBRE-VENTANA. CALL "chamatcl" USING VARIABLES-TCL SUMA-VARIABLES NOMBRE-VENTANA. Esto funciona así, cuando la sentencia CALL es ejecutada, ésta llama al programa(script) de Tcl/Tk "catastro.tcl" en el cual las variables "cobol_fields" reciben los valores de las variables definidas en Cobol ("VARIABLES-TCL"). 3.3.- Regresando a Cobol: Retornar a Cobol desde Tcl/Tk es muy simple, solo tiene que ejecutar el comando "do_exit". Haciendo esto cerrará la ventana abierta por Tcl/Tk moviendo las variables de "cobol_fields" a las variables de Cobol conforme se declararon en el WORKING-STORAGE SECTION. Aquí Ud. debe elaborar una rutina para que Cobol reciba los valores y retorne a llamar nuevamente al programa (script) en Tcl/Tk para mostrar los nuevos valores de las variables una vez éstos han sido procesados. 3.4.- ¿Cómo funciona el programa Cobol ejemplo de este Tutorial?: En el ejemplo de nuestro tutorial ("catastro.cob") tenemos una variable declarada con el nombre "TCL-OPCION" con la correspondiente "tclopcion" en Tcl/Tk ("catastro.tcl"). El programa Cobol llama al programa Tcl/Tk a través de "chamatcl" para mostrar la ventana. Cuando se pulsa algún botón o se quita el foco del campo "Código", se le atribuye una acción a la variable "tclopcion" y se ejecuta el comando "do_exit". Este comando hace que se retorne al programa en Cobol recibiendo en el proceso el contenido de las variables que vienen del script Tcl/Tk. El programa Cobol lee la variable "TCL-OPCION" y ejecuta la rutina correspondiente en base al valor de ésta, retornando luego al script Tcl/Tk para mostrar la ventana nuevamente. En el programa Cobol encontramos en el WORKING-STORAGE SECTION a la variable "SUMA-VARIABLES" con un valor preasignado de "234", que es el resultado de la suma de los tamaños de las variables que se intercambian y a la variable "NOMBRE-VENTANA" con un valor preasignado igual a "catastro.tcl" que es el nombre del programa (script) en Tcl/Tk. Al inicio del programa Cobol ejecutamos la sentencia CALL "initTcl" que nos servirá para inicializar el ambiente gráfico. Antes de llamar a la ventana objeto de este ejemplo por primera vez, inicializamos las variables que serán usadas para intercambiar datos entre Cobol y Tcl/Tk con el objetivo de que la ventana muestre los campos vacíos. Como las variables "SUMA-VARIABLES" y "NOMBRE-VENTANA" tienen sus valores preasignados, llamamos a la ventana de la siguiente forma: CALL "chamatcl" USING VARIABLES-TCL SUMA-VARIABLES NOMBRE-VENTANA. Esta sentencia invocará al programa(script) "catastro.tcl", el cual nos permitirá manipular la ventana. Digamos que un Usuario quiere grabar un registro, entonces primero rellenará los campos de datos y luego pulsará el botón "GRABAR". Cuando hace esto el script Tcl/Tk asignará el valor "gra" a la variable "tclopcion" y ejecutará el comando "do_exit" (-command {set tclopcion gra ; exit}) lo cual hará que el procesamiento retorne al programa Cobol con los nuevos valores de las variables. Ya en Cobol, se leerá la variable "TCL-OPCION" la cual tendrá el valor "gra" y se ejecutará un PERFORM a la rutina "1000-GRABAR", donde los valores de las variables recibidas de Tcl/Tk serán movidas al archivo FD "CATASTRO" efectuando luego la grabación del registro. A continuación la secuencia del programa inicializará las variables (que van al script Tcl/Tk), asignará un mensaje de texto a la variable "TCL-MENSAJE" describiendo el resultado del proceso de grabación y saldrá de la rutina retornando al programa(script) en Tcl/Tk. La ventana será mostrada con los nuevos valores venidos de Cobol. En el script Tcl/Tk hay una etiqueta que está vinculada a la variables "tclmensaje" la cual será actualizada en cada retorno mostrando al Usuario el resultado de la acción. En resúmen, Cobol llama a Tcl/Tk, el Usuario modifica los valores de las variables escribiendo sobre los campos en la ventana y luego el control retorna al programa en Cobol. En este punto el programa en Cobol identifica el deseo del Usuario y a continuación ejecuta el proceso correspondiente retornando luego al programa(Script) Tcl/Tk. -------------------------------------------------------------------------------------- 4 - Apéndice. 4.1 - Agradecimientos. - Carlucio Lopes que, mediante su tutorial, nos permitió dar los primeros pasos con Tcl/Tk; - Rildo Pragana por los primeros ejemplos con Tcl/Tk y con TinyCobol y por la paciencia en ayudarnos a superar algunas barreras encontradas; - John Ousterhout por crear el lenguaje Tcl y el toolkit gráfico TK. - A Wesley R. Braga, creador del sitio tclbrasil.cipsga.org.br 4.2 Colaboradores. - Danilo Pacheco Martins - Fernando Wuthstrack - Carlucio Lopes - Rildo Pragana - Wesley R. Braga