En este punto de nuestro programa ya podemos ver un formulario en pantalla sin nada, por lo que nuestro siguiente paso es empezar a incluirle objetos propios de un formulario GUI. Comencemos por agregar un control básico en casi cualquier formulario, un control StaticText o Label como se conoce en otros lenguajes.
Nuestro programa ahora contiene más código:
rem "[PRG01] Mi Primer Programa en BBj rem rem "Obtiene una instancia del objeto BBjAPI rem "======================================= LET miAPI!=BBjAPI() rem rem "Abre el dispositivo SYSGUI rem "========================== SYSGUI=UNT OPEN (SYSGUI) "X0" rem rem "Obtiene la instancia del objeto BBjSysGui rem "========================================= LET miSysGui!=miAPI!.getSysGui() rem rem "Valores para crear una ventana rem "============================== X=10 Y=10 ANCHO=400 ALTO=300 TITULO$="Ejemplo de una ventana GUI" rem rem "Establece el contexto actual rem "============================ miSysGui!.setContext(0) rem rem "Crea la ventana rem "=============== window! = miSysGui!.addWindow(X,Y,ANCHO,ALTO,TITULO$) rem rem "Crea controles en el formulario rem "=============================== etiqueta1! = window!.addStaticText(101,10,40,90,20,"Codigo :",$0000$) etiqueta2! = window!.addStaticText(102,10,63,90,20,"Descripcion :",$0000$)
En pantalla veremos lo siguiente:
Como habrán notado, recurriendo a la “instancia” de la clase BBjWindow representada en nuestro programa por la variable window! hemos agregado dos controles StaticText con su respectivo ID, columna, fila, largo y alto más un texto que queremos desplegar. Al mirar nuestro programa en pantalla, veremos un formulario con dos filas de texto, una que dice código y otra descripción. Ya nuestro formulario comienza a tomar forma y poco a poco vamos entendiendo la sintaxis de objetos a la que le estamos dando uso desde el BBjAPI.
Lo siguiente ya lo imaginas, dos controles para el ingreso de información. Para esto usaremos controles InputE que tienen una sintaxis de creación muy parecida a los controles que ya hemos incluido en pantalla. Agreguemos a nuestro programa las siguientes instrucciones:
campo1! = window!.addInputE(103,103,40,080,20,$0804$) campo1! = window!.addInputE(104,103,63,200,20,$0804$)
Ahora veremos esta apariencia en nuestro formulario:
Nuestro programa empieza a tomar forma, y ya está empezando a darnos las primeras luces de cómo funciona la mayoría de los controles en BBj. Con más o menos “parámetros” vamos elaborando sobre la marcha los controles que necesitamos incluir dentro de nuestro programa.
Hasta el momento solo estamos concentrados en la creación de nuestra ventana o formulario. Esta ventana ya tiene la apariencia de lo que típicamente llamamos “mantenedor”. Ya sé lo que estás pensando: necesitamos agregar algunos botones para ejecutar algunas operaciones básicas con este programa, como grabar, eliminar y salir del programa. Creemos algunos controles BBjPushButton para tales efectos.
grabar! = window!.addButton(105,30,270,90,20,"Grabar") borrar! = window!.addButton(106,123,270,90,20,"Eliminar") salir! = window!.addButton(107,216,270,90,20,"Salir")
Confirmamos que prácticamente los controles posibles de incluir en un formulario tienen normalmente requerimientos muy parecidos para su creación. En todos los casos, realizamos una asignación de variables para “instanciar” el objeto y esto permite un doble objetivo. Por un lado, nos ahorra crear la instancia de la clase mediante declaraciones (concepto que más adelante explicaremos) y por otro nos deja el acceso necesario para comenzar próximamente a interactuar con los controles en el formulario de una manera mucho más sencilla e intuitiva que con las instrucciones habituales en Vpro5.
En este minuto nuestro formulario en pantalla se debería ver así:
Para los propósitos de nuestro ejemplo, nuestro formulario en pantalla satisface nuestros requerimientos. Hemos podido entender la creación de controles en un formulario en pantalla utilizando sintaxis de objetos en su totalidad. Todo un logro para nosotros que recién nos insertamos en este nuevo ambiente. Ahora es momento de comenzar a pensar en agregar funcionalidad a nuestro código.
Conviene entonces que comentemos algunos de los nuevos conceptos de BBj en contraste con Vpro5 y que enfatizan las ventajas del nuevo ambiente.
En Vpro5 y particularmente con la funcionalidad GUI, BASIS definió un concepto denominado cola de eventos, para señalar a un registro de todas las acciones que el usuario de un formulario realiza sobre éste. Esa cola de eventos debía controlarse a través de una instrucción READ RECORD apuntando al canal SYSGUI para “X0” y que iba leyendo los eventos y los pasaba a instrucciones sucesivas del programa que realizaban una interpretación y según los eventos que el desarrollador pretendía controlar, agregaba la funcionalidad respectiva.
Las desventajas de este modelo, se hacen sensiblemente notorias en ambientes distribuidos. Una aplicación leyendo los eventos del usuario, transmite muchos mensajes de eventos ocasionados por el usuario, aun cuando muchos de esos eventos no son relevantes de controlar por parte del usuario. El resultado, una cantidad incontable de eventos irrelevantes informados a la aplicación.
BBj resuelve el dilema de los eventos innecesarios incorporando un nuevo concepto, los “eventos registrados”. En lugar de tener un lector de la cola de eventos que informe de todos los eventos originados por el usuario, puedo definir una lista de eventos que si me interesa controlar y los registro para que el programa reaccione a ellos. Para esto aparecen dos nuevos conceptos en BBj, los CALLBACKS y la instrucción PROCESS_EVENTS y que serán nuestra próxima consideración en el ejemplo que estamos desarrollando.
El concepto de CALLBACK cómo su nombre de alguna manera permite inferir, es una llamada a una subrutina con retorno al controlador de eventos del programa y que es provocada por el evento que se registro en la instrucción CALLBACK. Como podrán constatar en la documentación de BBj, se puede hacer un registro de un evento para llamar a la subrutina respectiva de dos formas: mediante la instrucción CALLBACK o mediante el método .setCallback del control u objeto si queremos llamarlo ante el cual queremos que nuestro programa reaccione.
Mejor clarificar esta definición con un ejemplo tomado de nuestro programa en construcción. Simplificando las cosas, podríamos decir que nuestro formulario tiene 7 controles (2 BBjStaticText, 2 BBjInputE y 3 BBjButton). Para este sencillo programa necesitamos que el manejador de eventos realiza alguna operación para 3 posibles eventos importantes (a pesar de que en este pequeño formulario, ya existe la posibilidad de manejar decenas de eventos si se quisiera). Estos tienen que ver con los botones “Grabar”, “Eliminar” y “Salir”. Nos interesa que cuando el usuario pulse alguno de éstos botones, el programa realice una operación (muy seguramente alguna que refleje lo que indica el botón).
Entonces, diremos que necesitamos controlar el evento “botón pulsado”. BBj trae definidos una lista de constantes muy descriptivas para cada uno de los eventos relacionados con cada uno de los controles que podemos incluir en nuestro formulario.
De las dos formas posibles de “registrar” estos eventos, usaremos la más simple: invocando el método del control que permite registrar un evento. Veamos la sintaxis:
control!.setCallback(control!.nombreEvento,”subrutina”)
Aplicado a nuestro programa de ejemplo, hagamos el registro del evento “botón pulsado” del botón “Grabar” y que en nuestro programa esta “instanciado” en la variable objeto grabar!:
grabar!.setCallback(grabar!.ON_BUTTON_PUSH,"subrutina_guardar")
Como podemos ver, usando la variable objeto grabar! invocamos el método .setCallback que exige dos parámetros que se incluyen entre paréntesis; por un lado el evento, que si te fijas se obtiene como propiedad de la misma instancia del objeto grabar! (grabar!.ON_BUTTON_PUSH) y el segundo parámetro es el nombre de la subrutina a donde se transferirá el control del programa. Es importante destacar que la transferencia a la subrutina, es un GOSUB intrínseco, por lo tanto esa subrutina debe finalizar con una instrucción RETURN.
Pero este es sólo el registro del evento. Con solo incluir esta instrucción no es suficiente para que el evento ejecute esta subrutina. Aquí entra en acción el nuevo comando PROCESS_EVENTS, que viene a reemplazar el READ RECORD que leía la cola de eventos en Vpro5.
PROCESS_EVENTS reacciona frente a los eventos “registrados” previamente con los CALLBACKs. Esto es una gran economía en recursos internos para el programa, pues PROCESS_EVENTS ignorará todo otro evento no registrado, limitando con esto el tráfico de información innecesaria en la aplicación.
Para efectos de orden, aunque no es obligatorio, luego de la instrucción PROCESS_EVENTS podemos incluir las subrutinas necesarias para dar funcionalidad completa a nuestro programa. Para conservar la simplicidad de nuestro ejemplo, registraremos los eventos “botón pulsado” y agregaremos las subrutinas respectivas a cada botón, pero no incluiremos los comandos necesarios para realizar una grabación ó una eliminación, pues tendríamos que crear un archivo, y hacer más operaciones que en este momento no son relevantes para los aspectos que estamos aprendiendo. Simplemente, incluiremos un mensaje en pantalla, que avise la subrutina que se ha activado al pulsar alguno de los botones. Nuestro programa completo, incluyendo esto, se vería como el siguiente:
rem "[PRG01] Mi Primer Programa en BBj rem rem "Obtiene una instancia del objeto BBjAPI rem "======================================= LET miAPI!=BBjAPI() rem rem "Abre el dispositivo SYSGUI rem "========================== SYSGUI=UNT OPEN (SYSGUI) "X0" rem rem "Obtiene la instancia del objeto BBjSysGui rem "========================================= LET miSysGui!=miAPI!.getSysGui() rem rem "Valores para crear una ventana rem "============================== X=10 Y=10 ANCHO=400 ALTO=300 TITULO$="Ejemplo de una ventana GUI" rem rem "Establece el contexto actual rem "============================ miSysGui!.setContext(0) rem rem "Crea la ventana rem "=============== window! = miSysGui!.addWindow(X,Y,ANCHO,ALTO,TITULO$) rem rem "Crea controles en el formulario rem "=============================== etiqueta1! = window!.addStaticText(101,10,40,90,20,"Codigo :",$0000$) etiqueta2! = window!.addStaticText(102,10,63,90,20,"Descripcion :",$0000$) campo1! = window!.addInputE(103,103,40,080,20,$0804$) campo1! = window!.addInputE(104,103,63,200,20,$0804$) grabar! = window!.addButton(105,30,270,90,20,"Grabar") borrar! = window!.addButton(106,123,270,90,20,"Eliminar") salir! = window!.addButton(107,216,270,90,20,"Salir") rem rem "Registro de eventos utilizados por el programa rem "============================================== grabar!.setCallback(grabar!.ON_BUTTON_PUSH,"subrutina_guardar") borrar!.setCallback(borrar!.ON_BUTTON_PUSH,"subrutina_borrar") salir!.setCallback(salir!.ON_BUTTON_PUSH,"subrutina_salir") rem rem "Procesamiento de eventos rem "======================== PROCESS_EVENTS rem rem "Guardar rem "======= subrutina_guardar: x=msgbox("El usuario ha pulsado el boton Guardar",0+64+0,"Boton guardar") return rem rem "Borrar rem "======= subrutina_borrar: x=msgbox("El usuario ha pulsado el boton Borrar”,0+64+0,"Boton borrar") return rem rem "Salir rem "======= subrutina_salir: x=msgbox("El usuario ha pulsado el boton Salir",0+64+0,"Boton salir") release return
Nuestro primer programa BBj ha logrado introducirnos en la programación con sintaxis de objetos y nos permite armar un esquema básico de cómo debiera funcionar todo programa BBj bajo este nuevo paradigma. Habrás notado que, a semejanza de la programación en BBx donde dedicabas parte del código a crear una pantalla y luego agregabas procedimientos que el programa debía seguir en un orden impuesto por el usuario, en BBj también dedicas una parte del código a definir tu formulario y luego hacemos un registro de todos los “GOSUB” que queremos que nuestro programa ejecute cuando un usuario active los eventos que he decidido registrar en mi programa. Con este sencillo esquema, ya puedes comenzar a pensar la manera de adaptar tus actuales programas al modelo BBj con sintaxis de objetos.
Esta pincelada de programación BBj te ayudará mucho a comprender la mayoría de los objetos de BBj. En un corto plazo esperamos compartir una nueva entrega guía para dominar BBj.
Deja un comentario