HOWTO: Crear controles y eventos dinámicamente en formularios AX

En este HOWTO me gustaría explicar el proceso completo para crear dinámicamente controles en un formulario existente (aunque también podría no existir, pero ya sería complicar demasiado) y además manejar los eventos generados por
ese control tanto dentro como fuera del formulario en sí.


Lo haremos paso a paso, de lo mas facil a lo mas complicado:


Empezaremos con un formulario nuevo de AX totalmente estándar sin ninguna propiedad modificada:


Dynamic Runtime Forms | 1


El primer paso será generar controles en este formulario de forma dinámica, es decir, mediante código en tiempo de ejecución. Para ello modificaremos el método estandar run() del
formulario de la siguiente manera:


public
void run()
{
FormButtonControl fButtonCtr;
;

super();

element.lock();

fButtonCtr = element.design().addControl(FormControlType::Button, "buttonName");
fButtonCtr.text("Ejemplo");

element.unLock();
}

Con lo que habremos añadido al diseño del formulario, un boton generado en tiempo de ejecución:


Dynamic Runtime Forms | 2


Añadimos otro control al formulario y establecemos alguna propiedad a los controles. Llevo todo este código a un nuevo método del formulario para mantener cierto orden:


public
void run()
{
super();

element.drawControls();
}

private void drawControls()
{
FormButtonControl fButtonCtr;
FormStringControl fStringCtr;
;

element.lock();

// Control de texto (StringEdit), en negrita, ancho total
fStringCtr = element.design().addControl(FormControlType::String, 'stringEditTexto');
fStringCtr.bold(10);
fStringCtr.widthMode(FormWidth::ColumnWidth);
fStringCtr.text("Ejemplo");

// Botón, con imagen incrustada y texto, ancho total
fButtonCtr = element.design().addControl(FormControlType::Button, 'buttonUp');
fButtonCtr.widthMode(FormWidth::ColumnWidth);
fButtonCtr.buttonDisplay(FormButtonDisplay::TextAndImageLeft);
fButtonCtr.normalResource(1067);
fButtonCtr.text("Subir");

// Botón, con imagen incrustada y texto, ancho total
fButtonCtr = element.design().addControl(FormControlType::Button, 'buttonDown');
fButtonCtr.widthMode(FormWidth::ColumnWidth);
fButtonCtr.buttonDisplay(FormButtonDisplay::TextAndImageLeft);
fButtonCtr.normalResource(1068);
fButtonCtr.text("Bajar");

element.unLock();
}

Esto es otra cosa!:


Dynamic Runtime Forms | 3


Bien, hasta aquí la parte fácil. Crear controles en runtime es bastante sencillo pero ahora, ¿qué hago con ellos?. Lo primero, tendremos que indicar al formulario donde puede
encontrar el código manejador de eventos de los nuevos controles,
primero la maner mas sencilla:


Lo primero que hay que hacer en cualquier caso es indicar a AX que tenemos métodos controladores de eventos propios, es decir, que estamos sobrecargando sus propios métodos controladores, igual que hacemos
cuando "anulamos" métodos en tiempo de diseño (la traducción no es muy
acertada):


public void run()
{
// Sobrecargo los métodos de control
element.controlMethodOverload(true);
// ¿Dónde están los métodos de control?: Aquí mismo (this)
element.controlMethodOverloadObject(this);

super();

element.drawControls();
}

Con el método controlMethodOverload indicamos que tenemos algún método sobrecargado, es decir, que busque primero nuestros métodos antes de ejecutar los suyos propios. El método controlMethodOverloadObject indica a AX dónde, en qué objeto, puede encontrar los métodos sobrecargados.


Hay que destacar dos puntos importantes:

  • El método se debe declarar siempre como public void
  • El nombre del método siempre ha de ser nombreObjeto_evento()
public void buttonUp_clicked()
{
;

info(element.design().controlName('stringEditTexto').valueStr());
}

Funciona! Pero hay un problema. ¿Qué sentido tiene crear controles en tiempo de ejecución de una manera dinámica -por ejemplo, basandonos en opciones configurables en una tabla- si el código asociado a ellos debe
permanecer estáticamente en el formulario? No tiene ningún sentido.


Es por esto que se hace necesaria la segunda opción, llevar tódo el código fuera del formulario, por ejemplo, a una clase, como es el caso. El formulario pués se libera del código y queda de una manera muy
sencilla (e independiente totalmente de los controles añadidos en runtime):


public class FormRun extends ObjectRun
{
// Clase manejadora de eventos
JAEBaseForm_Mngr baseFormMngr;
}

public void init()
{
super();

// Construyo una instancia de la clase manejadora asociada a
// la instancia actual de este formulario
baseFormMngr = JAEBaseForm_Mngr::construct(this);
}

public void run()
{
// Sobrecargo los métödos de control
element.controlMethodOverload(true);

// ¿Dónde están los métödos de control?: Aquí mismo (this)
element.controlMethodOverloadObject(baseFormMngr);

super();

// Crear los controles
baseFormMngr.drawControls();
}

Y es la clase la que contiene todo el codigo dinámico, de manera que es posible reutilizarla en diferentes formularios:


class JAEBaseForm_Mngr
{
FormRun element;
}

private void new(FormRun _formRun)
{
element = _formRun;
}

public static JAEBaseForm_Mngr construct(FormRun _element)
{
return new JAEBaseForm_Mngr(_element);
}

public void drawControls()
{
FormButtonControl fButtonCtr;
FormStringControl fStringCtr;
;

element.lock();

// Control de texto (StringEdit), en negrita, ancho total
fStringCtr = element.design().addControl(FormControlType::String, 'stringEditTexto');
fStringCtr.bold(10);
fStringCtr.widthMode(FormWidth::ColumnWidth);
fStringCtr.text("Ejemplo");

// Botón, con imagen incrustada y texto, ancho total
fButtonCtr = element.design().addControl(FormControlType::Button, 'buttonUp');
fButtonCtr.widthMode(FormWidth::ColumnWidth);
fButtonCtr.buttonDisplay(FormButtonDisplay::TextAndImageLeft);
fButtonCtr.normalResource(1067);
fButtonCtr.text("Subir");

// Botón, con imagen incrustada y texto, ancho total
fButtonCtr = element.design().addControl(FormControlType::Button, 'buttonDown');
fButtonCtr.widthMode(FormWidth::ColumnWidth);
fButtonCtr.buttonDisplay(FormButtonDisplay::TextAndImageLeft);
fButtonCtr.normalResource(1068);
fButtonCtr.text("Bajar");

element.unLock();
}

public void buttonUp_clicked()
{
FormStringControl fStringCtr = element.design().controlName('stringEditTexto');
;

fStringCtr.text("Arriba!");
}

public void buttonDown_clicked()
{
FormStringControl fStringCtr = element.design().controlName('stringEditTexto');
;

fStringCtr.text("Abajo!");
}

De esta manera conseguimos el objetivo. El objeto Form es estático y contendrá su propia funcionalidad que no cambiará en runtime. Sin embargo ejecuta métodos de la clase controladora que se encarga de toda
la parte dinámica, tanto generar los controles, como manejar sus
eventos.


Las posiblidades son enormes. Desde generar pequeños formularios a modo de diálogos, a construir formularios dinámicos basados en datos de tablas en la base de datos, igual que el estándar hace con el Configurador de Productos.
De hecho las clases que generan el formulario del modelo de producto
(las que empiezan por PBA*) son un buen banco de ejemplos sobre este
tema.


Adjunto un proyecto con los dos objetos por si pudiera ser de utilidad.



Fuente y descarga de proyecto XPO de ejemplo:

http://www.jaestevan.com/2010/07/howto.crear.controles.y.eventos.di...



Visitas: 56

Etiquetas: ax, events, forms, runtime, x++

Comentar

¡Necesitas ser un miembro de El Rincón Dynamics para añadir comentarios!

Participar en El Rincón Dynamics

© 2014   Creado por Antonio Gilabert.

Emblemas  |  Reportar un problema  |  Términos de servicio