# Introducción

Esta es una guía de uso del diseñador WebUI que pueda servir como punto de partida para aprender a utilizar las funcionalidades de este componente y como material de referencia para apoyar el proceso de desarrollo dentro de proyectos basados en el diseñador.

En este documento encontrará ejemplos y descripciones de cómo utilizar el diseñador en los distintos casos de uso que resuelve. Esto incluye la definición de formularios, modelos de navegación, reporte de errores/advertencia, categorías y subcategorías, validación de datos, entre otras.

Dentro de este documento se describen las funcionalidades que brinda el diseñador WebUI. El componente, que llamamos diseñador WebUI, extiende a GeneXus (opens new window) con un lenguaje declarativo específico para diseñar interfaces de aplicaciones Web.

La interfaz del diseñador es un XML (opens new window). A través de este XML (opens new window) se constituye la “definición del objeto”, aquí se definen los elementos que van a componer la interfaz y cómo se van a comportar. Luego, el diseñador toma esta definición y genera código HTML para visualizar el objeto y también código GeneXus (opens new window) para resolver varios aspectos de comportamiento (como por ejemplo pedidos de confirmación y validaciones).

# Un Ejemplo para Comenzar

Para dar una idea inicial de cómo definir un WebPanel mostraremos un ejemplo sencillo y luego lo explicaremos. Como mencionamos en la presentación se utiliza un XML para definir la interfaz del WebPanel:

<object-definition libraryName="Dlya.Basic" libraryVersion="1.0" Designer="WebUI">
    <web-ui title="Persona" class="other">
        <Form>
            <field caption="Nombre" data="&amp;PerNom" readOnly="false" allowNull="false" />
            <line-break />
            <field caption="Apellido" data="&amp;PerApe" readOnly="false" allowNull="false" />
            <line-break />
            <value-list caption="Sexo" data="&amp;PerSex" readOnly="false">
                <items>
                    <item text="Femenino" value="F" />
                    <item text="Masculino" value="M" />
                </items>
            </value-list>
        </Form>
        <operations>
            <operation caption="Confirmar" validateData="true" />
            <operation caption="Cancelar" validateData="false" />
        </operations>
    </web-ui>
</object-definition>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

Este ejemplo consiste en una página para pedir datos básicos de una persona. La página está compuesta por un campo para el nombre, otro para el apellido y luego un cuadro que permite seleccionar el sexo de la persona. Adicionalmente, en esta página hay dos operaciones (que se representan con botones): una para confirmar los datos y otra para cancelar el ingreso de datos.

Para explorar la definición con más detalle la analizaremos línea a línea. En la línea [1] se encuentra el cabezal de la definición, que indica que se va a utilizar el diseñador WebUI de la librería Dlya.Basic, esta declaración será obligatoria en todos los objetos. En la línea [2] se define el cabezal de la interfaz, aquí se define el título de la página (“Persona”) y la clase (other). A través de la clase se indica para qué se utilizará la página, por ejemplo, si se va a utilizar como lista de selección se debe indicar la clase prompt. Sin embargo, aquí no se aplica una clase específica, por lo tanto es other.

La línea [3] contiene el elemento form. Este elemento se utiliza para indicar los campos del formulario, como campos de texto, listas de valores (ComboBox o RadioButton), casillas de chequeo (CheckBox), grillas, etc. Dentro del elemento form tenemos los campos de ingreso de datos. En la línea [4] está definido el campo que pide el nombre de la persona. Para este campo en el atributo caption se le asocia el texto “Nombre”, el cual se muestra a la izquierda del campo. En el atributo data se indica la variable en donde se almacenará el valor ingresado (observar que se pone “&” antes del nombre de la variable, esta es la forma de representar al carácter “&” en XML). Luego, el atributo readOnly con valor false indica que se puede modificar el valor del campo y el atributo allowNull con valor false indica que el campo no se puede dejar vacío al confirmar los datos.

De forma análoga se define el campo para ingresar el apellido en la línea [6]. Pero antes de esta definición, en la línea [5] encontramos el elemento line-break. Este elemento se utiliza para indicar dónde termina una línea de campos. Si no se hubiera agregado este elemento, el campo para el nombre y el del apellido se mostrarían en la misma línea. En la línea [7] hay otro line-break para que el cuadro de selección del sexo se ubique en la siguiente línea al apellido.

Desde la línea [8] hasta la [13] se define una lista de valores para el sexo de la persona. Este elemento se visualiza como un control de tipo ComboBox. Para las lista de valores también están disponibles los atributos caption, data y readOnly, que tienen el mismo significado que en los casos anteriores. Los valores posibles del cuadro de valores se definen en las líneas [10] y [15]. En la línea [11] se define el elemento “Masculino”, al seleccionar este elemento se asigna “M” a la variable Sexo. De forma similar se define el valor “Femenino” con valor “F” en la línea [10].

Finalmente entre la línea [15] y [18] se definen las operaciones. Las mismas se representan como botones en la página. Las operaciones se definen dentro del elemento operations de la línea [15]. Aquí se puede observar que las operaciones están al mismo nivel que el elemento form. En la línea [16] se define una operación con etiqueta “Confirmar”. Esta operación podría grabar los datos ingresados en una tabla. Debido a que para ejecutar esta operación se quiere garantizar que se hayan ingresado correctamente los datos se indicó el valor true en el atributo validateData. Este valor provoca que se validen los datos antes de ejecutar la operación. Por ejemplo, si el campo del apellido está vacío al apretar el botón “Confirmar”, se desplegará un error y no se ejecutará el código asociado a la operación como se muestra en la Figura 1-1. En la línea [17] se define una operación para cancelar, debido a que esta operación no requiere que los datos sean válidos se indicó el valor false en el atributo validateData.

Al generar el objeto el diseñador arma el código HTML de la página y escribe código GeneXus. Dentro del código que escribe el diseñador se crearán subrutinas que luego debemos implementar para completar la implementación del WebPanel. Por ejemplo, para definir el código que se ejecuta al realizar la operación “Confirmar” el diseñador crea la siguiente subrutina:

    Sub 'GU: Op -> Confirmar (Click)' //$ ... 
    // PARA HACER: Ingrese el código que se ejecuta al realizar la operación 
    EndSub // 'GU: Op -> Confirmar (Click)' 
1
2
3

En esta subrutina se deberá escribir el código asociado a la operación “Confirmar”. Al presionar el botón asociado a esta operación se invocará a la subrutina y se ejecutará el código que ingresamos aquí.

# Armando el Primer Ejecutable

A partir del ejemplo anterior ahora vamos a intentar lograr un programa ejecutable. Se describen paso a paso las acciones que se deben realizar para definir el objeto y generarlo:

  1. Ejecutar la herramienta Descartes (ver \Dlya2001\Descartes\Documentación\Guía de Instalación.pdf).

  2. Abrir la Base de Conocimiento donde se va a agregar el nuevo objeto (File->Open Knowledge Base). Se debe utilizar una Base de Conocimiento que tenga algún modelo para ejecutarse en ambiente Web. Adicionalmente, en la Base de Conocimiento deben estar consolidados y generados los objetos GeneXus que utiliza el diseñador. Estos objetos están contenidos dentro del archivo Framwork.xpz, ver la Guía de Instalación para más información.

  3. Crear un WebPanel nuevo (File->New->Object). Nota: Aquí se creará un nuevo objeto desde la herramienta Descartes, pero se puede trabajar normalmente con objetos creados desde GeneXus.

  4. Luego de crear el WebPanel este quedará abierto. En la parte inferior se pueden ver una serie de etiquetas que dicen: Definition, Rules, Source y Conditions. Al presionar sobre alguna de ellas podremos editar las reglas del objeto, su código fuente, las condiciones o la definición. Para continuar este ejemplo editaremos la definición (Definition), dentro de la definición se indica el XML que define la interfaz del objeto.

  5. Copiar el XML de la sección anterior en la definición. Nota: En el XML no se deben indicar los números que aparecen en el comienzo de cada línea del ejemplo (estos números fueron agregados únicamente con fines didácticos para explicar el significado de cada línea)

  6. Generar el objeto (F9 o Build->Generate <objeto>). Al generar el objeto se crea el código HTML que permite visualizarlo en ejecución, y adicionalmente se crea código GeneXus. Sin embargo, la primera vez que presionemos F9 en este ejemplo se producirán una serie de errores porque la definición hace referencia a variables que no están definidas.

  7. La herramienta Descartes cuando encuentra variables que no están definidas pregunta si se quieren agregar. Apretar la tecla Y o presionar el botón “Yes” para que la herramienta defina las variables faltantes.

  8. Luego de confirmar la creación de las variables, se muestra un dialogo que lista las variables creadas y sus propiedades. Cuando se definen variables con el nombre de un atributo o un prefijo más el nombre (por ejemplo, PCliCod, siendo CliCod el nombre de un atributo) la herramienta creará las variables basadas en el atributo. Sin embargo, si no se cumplen estas condiciones se crearán de tipo numérico. En este caso necesitaremos variables de tipo Character, por lo tanto debemos modificarlas. Para cambiar el tipo de una variable debemos hacer clic sobre ella en la lista de la izquierda, y luego editarle sus propiedades a la derecha. Antes de continuar al siguiente paso asignar los siguientes tipos:

     > PerApe: Type=Character, Length=30 
     > PerNom: Type=Character, Length=30
    

Nota

Cuando se selecciona una propiedad que tiene una lista de valores (por ejemplo, Type), para asignar más rápidamente un valor podemos escribir parte de él con el teclado.

  1. Cerrar el dialogo de edición de variables (presionar el botón “Close”).
  2. Presionar nuevamente el botón F9 para volver a generar. En esta ocasión la generación se realizará con éxito debido a que están definidas todas las variables necesarias.
  3. Declarar el objeto como “main” (Build->Is Main Object)
  4. Grabar el objeto (Ctrl+S o File->Save <objeto>)

En este momento ya generamos el objeto con la herramienta y los transferimos a la Base de Conocimiento. Ahora debemos abrir el modelo en GeneXus, especificar el objeto, generarlo, compilarlo y ejecutarlo. Al grabar el objeto quedará en el modelo de Diseño de la Base de Conocimiento, por lo tanto, antes de poder especificarlo y generarlo en GeneXus debemos transferirlo al modelo de Prototipo o Producción en el que vayamos a trabajar. Para hacer esto se puede hacer un análisis de impacto o se puede impactar directamente el objeto (Build->Impact Objects desde GeneXus, teniendo el modelo de Prototipo o Producción seleccionado). Otra alternativa es abrir el objeto en el modelo de Prototipo o Producción, GeneXus detectará que ha cambiado y preguntará si queremos actualizarlo, al contestarle que sí se cargaran los datos del objeto desde el modelo de diseño. Esta última opción es la más rápida y fácil para trabajar con objetos modificados en la herramienta Descartes, por lo tanto se recomienda utilizar este mecanismo para actualizar los objetos de un modelo de Prototipo o Producción, sin embargo, sólo la podremos realizar si el objeto está disponible en el modelo (es decir, si lo creamos desde el modelo, o ya lo habíamos manualmente impactado antes al menos una vez).

# Análisis Introspectivo

Al ejecutar el objeto generado anteriormente no veremos un programa muy funcional, ya que no hemos programado la lógica de las operaciones. Sin embargo, sirve como ejemplo para ver cómo luce el objeto generado y para entender mejor cómo funciona la herramienta Descartes. Con este último fin vamos a analizar los elementos que fueron generados.

Cuando generamos un objeto con Descartes se define:

  • El formulario Web: Consiste en el código HTML que define el aspecto visual del objeto.
  • Eventos y Subrutinas: Comprenden eventos y subrutinas que se crean para resolver parte de la lógica de la interfaz (por ejemplo, validación de campos nulos). Las subrutinas generadas también incluyen modelos de subrutinas para que implementemos. Por ejemplo, por cada operación se genera una subrutina para que escribamos el código que se ejecuta al presionar la operación. En otros casos, como veremos más adelante, el generador sugiere el código que debemos escribir y luego podremos hacerle modificaciones. Sin embargo, no se pueden modificar todas las subrutinas generadas, sólo se pueden modificar las que tienen prefijo “GU” porque si no al volver a generar se perderán los cambios.
  • Variables: Dentro de los elementos generados también se incluyen variables que utiliza el diseñador de forma interna, y otras que sirven como interfaz entre lo que es generado y lo que tenemos que programar nosotros. Por ejemplo, al utilizar una grilla para desplegar una lista de datos el diseñador nos carga una variable con la cantidad de registros cargados, que podemos utilizar luego para recorrerla.

La generación de eventos, subrutinas y variables se realiza analizando los elementos que están definidos en el objeto, agregando los que faltan y quitando los que fueron generados previamente y no son necesarios. Se puede hacer una analogía con los análisis de impacto de GeneXus. Es decir, en tiempo de generación el diseñador define todos los eventos, subrutinas y variables que necesita, luego se determinan que cambios hay que hacerle al objeto y finalmente se impacta el objeto.

Como se mencionó previamente, dentro de las subrutinas generadas hay algunas que podemos modificar y otras que no. Existen varios tipos de alcances en eventos, subrutinas y variables; al crear dichos elementos el diseñador les asocia un alcance según el uso que le dé, y esto nos determina si podemos modificarlo o no y cómo tenemos que utilizarlo. A continuación se muestra una lista de los alcances y una guía de cómo reconocerlos:

  • Usuario: Este alcance se presenta únicamente en subrutinas, y agrupa a las subrutinas que crea el diseñador pero que quedan a cargo del programador mantenerlas. Un ejemplo de estas subrutinas son las que se generan por operación. El diseñador por cada operación crea una subrutina pero luego debemos escribir en ella el código que se ejecuta al presionar el botón de la operación. El mantenimiento de las subrutinas de usuario están a cargo de nosotros, por lo tanto, si volvemos a generar la definición no se modificará el código de las subrutinas de usuario que ya estén creadas. Las subrutina de usuario se pueden reconocer porque tienen prefijo “GU” (Generated - User), por ejemplo, “GU: Op -> Confirmar (Click)”.
  • Publico: El alcance público se aplica a subrutinas y variables. Los elementos con este alcance representan los elementos que crea el diseñador para que utilicemos pero que el diseñador se encarga de mantenerlo. Si bien podemos hacer referencia a estos elementos (ya sea porque invocamos a una subrutina, o consultamos el valor de una variable pública) no podemos modificarlos. Si volvemos a generar se descartan los cambios hechos y el generador vuelve a escribir el código de estos elementos. Las variables y subrutinas publicas tienen el prefijo “GP” (Generated - Public), por ejemplo, variable GP_Mensaje y subrutina “GP: Reportar mensaje”.
  • Interno: Este alcance comprende los eventos, subrutinas y variables que crea el diseñador para utilizar de forma interna. Los elementos que son creados con este alance no los podemos modificar, ni tampoco podemos hacer referencia a ellos porque podrían desaparecer en futuras versiones del diseñador, ya que se asume que únicamente los utiliza el diseñador de forma interna. Los elementos que tienen este alcance tienen prefijo “ZG”, por ejemplo, variable ZG1_I1 y subrutina 'ZG1: Check page integrity'.

Como se mencionó previamente el generador analiza qué subrutinas, eventos y variables son necesarias, y elimina las que no son necesarias. Por ejemplo, si definimos una operación y generamos el diseñador crea una subrutina para implementar la operación; si luego borramos la operación de la definición y volvemos a generar, se detectará que la subrutina ya no es necesaria y se preguntará si se quiere eliminar (únicamente se pide confirmación para las subrutinas de usuario, el resto son eliminados sin pedido de confirmación). Para poder mantener la relación entre las subrutinas generadas y los elementos de la definición se agrega automáticamente el atributo id en los elementos de la definición. Si observamos la definición del objeto luego de generar podremos ver que se le agregó un identificador a cada elemento, y luego los eventos, subrutinas y variables generadas quedan asociados al identificador del elemento. De esta forma se puede determinar cuáles son necesarios y cuales no al cambiar la definición y volver a generar. Por lo tanto, si se copia un elemento de un lugar a otro de la definición, y no se quiere perder el código que tiene asociado, se debe mantener el atributo id con su valor. En caso que se copie un elemento para tenerlo como base para crear uno nuevo, se debe borrar el atributo id o asignar uno nuevo (si se detecta al generar que hay dos elementos con el mismo identificador, se muestra un dialogo para asignarle uno nuevo a alguno de ellos).

# Contenido

El resto de este manual se encuentra organizado por secciones que describen las funcionalidades del diseñador. Se recomienda hacer una lectura general de todas las secciones para conocer que ofrece el diseñador, y luego utilizar este manual como referencia para resolver cada caso concreto que se presente. Las secciones son:

  • Elemento web-ui: Dentro del elemento web-ui se encuentran varios atributos generales de las interfaces Web. En esta sección se describen estos atributos y se explica cómo debe definirse el elemento web-ui según el caso.
  • Componentes básicos de un formulario: Aquí se describen los elementos que ofrece el diseñador para armar un formulario. A partir de estos elementos se define el ingreso y la visualización de datos.
  • Operaciones: Describe los atributos de las operaciones y analiza cómo deben utilizarse según el caso.
  • Grillas: Las grillas permiten mostrar una tabla con datos. El diseñador ofrece una serie de elementos que permiten resolver varias situaciones comunes, como filtros, paginado y edición de valores. En esta sección se hace una exploración de todas las funcionalidades y se muestra cómo utilizarlas.
  • Datos ocultos: Debido a la naturaleza sin estado de la arquitectura Web, para no perder los valores de las variables es necesario almacenarlos en algún lado. Una forma de hacer esto es a través de datos ocultos. Esta sección explica como definirlos.
  • Categorías y subcategorías: Para diseñar páginas con muchos datos el diseñador ofrece la posibilidad de organizarlos en categorías y subcategorías, aquí se explorará este tema.
  • Navegación: En una aplicación Web se le llama navegación a la proceso de ir de una página a otra. Dentro de esta sección se examinan los mecanismos que ofrece el diseñador para navegar entre páginas.
  • Reporte de errores/advertencias: Explica cómo se deben reportar errores y advertencias.
  • Propiedades dinámicas: Varios elementos de la interfaz tienen propiedades que pueden cambiar de valor según el estado de la página. El diseñador permite definir los valores de estas propiedades en función de expresiones, por ejemplo, podemos definir que el campo “Código” está habilitado según el valor de la variable Mode. En esta sección se explica cómo funciona este mecanismo y cuales son las propiedades dinámicas.
  • Validaciones: El diseñador ofrece también algunos atributos que permiten hacer validaciones de datos automáticas. Esta sección explora cómo utilizar estas funcionalidades para escribir menos código de validación.

# Organización

Las secciones de esta guía se desarrollan introduciendo primero los conceptos básicos sobre cada tema, y a medida que se profundiza se irán presentando usos más complejos y avanzados del diseñador.

Los conceptos básicos intentan identificar el problema que se estudiará en la sección, y luego rápidamente se presentaran los elementos que ofrece el diseñador para resolver los escenarios más comunes. Al llegar al final de la sección se habrán presentado todos los elementos que ofrece el diseñador para resolver los distintos escenarios del problema que se analiza en la sección.

El material se presenta como una guía que intenta asistir al lector para resolver cada una de las situaciones que abarcar el diseñador. Con este fin, se incluyeron una buena cantidad de ejemplos y se intentó agrupar en un único lugar toda la información necesaria para resolver cada problema concreto.

# ¿Cómo Leer este Material?

Este material sirve como referencia de todas las funcionalidades que ofrece el diseñador. Por lo tanto una buena forma de aprender a utilizar adecuadamente el diseñador es hacer una lectura profunda de todo este material.

Sin embargo, se recomienda aprender a utilizar el diseñador por sucesivas aproximaciones. Como primera lectura se recomienda abarcar los conceptos básicos que se incluyen al comienzo de cada sección, y luego hacer una lectora rápida del resto del contenido. Esto permitirá tener una idea general del uso del diseñador en las situaciones más usuales, y tener una idea básica del resto de las funcionalidades más avanzadas. De esta forma, cuando se nos presente un problema de diseño de interfaces Web sabremos si el diseñador tiene una solución para la misma y luego podremos profundizar en la sección que corresponda para aprender a aplicarla.

# Conocimientos Previos Necesarios

Dentro de esta guía se asume que se tienen buenos conocimientos de GeneXus, y al menos conocimiento básico de cómo funciona una aplicación en ambiente Web. En la guía no se hará un análisis detallado de la arquitectura Web, únicamente se harán pequeñas menciones a conceptos básicos para introducir funcionalidades del diseñador. Debido a que la definición de las páginas Web se hace a través de un XML, también es necesario tener una idea básica de cómo construir un XML.

Dentro de GeneXus Developer Library se pueden encontrar algunos artículos que explican las diferencias entre el ambiente Windows y Web:

▪ http://www.artech.com.uy/gxdlsp/pub/iehelp.htm?genexus/internet/technicalpape rs/conversion _de_aplicaciones_gui_a_web.htm

▪ http://www.artech.com.uy/gxdlsp/pub/iehelp.htm?genexus/internet/technicalpape rs/comparacio n_gui_web.htm