En esta sección se discuten algunos aspectos técnicos muy específicos al desarrollo de la aplicación con la librería xforms, opengl, y la herramienta 'make'.
6.1 Recuperación del apuntador 'this' dentro de xforms.
La librería xforms es una colección de objetos gráficos que permiten la interacción con el usuario. Está escrita en lenguaje 'C' y posee una herramienta que permite la creación de ventanas de manera 'interactiva' y posteriormente la escritura del código para esas ventanas de manera automática. Sin embargo, nosotros enfrentamos un problema cuya solución no fue muy evidente, el problema fue ¿cómo encapsular la librería en C dentro del modelo?.
Cuando fdesign escribe el código correspondiente a una forma o ventana, escribe una cabecera (archivo .h) y una parte del código del programa (archivo .c). A continuación se muestra un ejemplo de estos archivos.
Cabecera:
#ifndef FD_ventana_h_Principal
#define FD_ventana_h_Principal
/* Header file generated
with fdesign. */
/**** Forms and Objects ****/
typedef struct {
FL_FORM *ventana;
FL_OBJECT *MENU_ARCHIVO;
FL_OBJECT *MENU_PROCESAR;
FL_OBJECT *MENU_DESPLIEGUE;
FL_OBJECT *canvas;
FL_OBJECT *BOTON_SALIR;
FL_OBJECT *MENU_AYUDA;
FL_OBJECT *CAMPO_TEXTO;
FL_OBJECT *BOTON_IZQ;
FL_OBJECT *BOTON_ABAJO;
FL_OBJECT *BOTON_ARRIBA;
FL_OBJECT *BOTON_DER;
FL_OBJECT *CAMPO_STATUS;
FL_OBJECT *CAMPO_NUM_IMAGEN;
FL_OBJECT *BOTON_ZOOM;
void *vdata;
long ldata;
} FD_ventana_Principal;
#endif /* FD_ventana_h_ */
Cuerpo del programa (se muestra sólo una parte):
/* Form definition file generated with fdesign. */
#include "forms.h"
#include "form_V_principal.h"
FD_ventana *create_form_ventana(void)
{
FL_OBJECT *obj;
FD_ventana *fdui
= (FD_ventana *) fl_calloc(1, sizeof(FD_ventana));
fdui->ventana
= fl_bgn_form(FL_NO_BOX, 1220, 940);
obj = fl_add_box(FL_UP_BOX,0,0,1220,940,"");
obj = fl_add_frame(FL_ENGRAVED_FRAME,10,10,260,80,"");
fdui->MENU_ARCHIVO
= obj =
fl_add_menu(FL_PULLDOWN_MENU,50,900,110,30,"Archivo");
fl_set_object_boxtype(obj,FL_FRAME_BOX);
fl_set_object_lstyle(obj,FL_BOLD_STYLE);
fl_set_object_callback(obj,Despacha_Callback,CB_MENU_ARCHIVO);
fdui->canvas = obj = fl_add_canvas(FL_NORMAL_CANVAS,10,100,1200,780,"");
fdui->MENU_AYUDA
= obj = fl_add_menu(FL_PULLDOWN_MENU,360,900,100,30,"Ayuda");
fl_set_object_boxtype(obj,FL_FRAME_BOX);
fl_set_object_lstyle(obj,FL_BOLD_STYLE);
fl_set_object_callback(obj,Despacha_Callback,CB_MENU_AYUDA);
fdui->BOTON_ZOOM
= obj = fl_add_button(FL_PUSH_BUTTON,150,50,110,30,"Zoom");
fl_set_object_lsize(obj,FL_MEDIUM_SIZE);
fl_set_object_lstyle(obj,FL_BOLD_STYLE);
fl_set_object_callback(obj,Despacha_Callback,CB_BOTON_ZOOM);
fl_end_form();
return fdui;
}
¿ Cómo realiza la interacción con el usuario xforms ? La librería provee los objetos gráficos, y permite que se asocie una función a cada uno de ellos, esta se denomina callback y se asocia por medio de la función fl_set_object_callback().
Debemos prestar atencion a la función fl_set_object_callback(). En ella se envian tres parámetros, el primero es una referencia al objeto, el segundo es un apuntador a la función que se debe llamar en caso de recibir interacción y el tercero es un parámetro.
El problema que aparece es que el callback NO PUEDE SER CUALQUIER FUNCION! Si intentamos poner alguna de las operaciones de una clase dentro del fl_set_object_callback, la operación será llamada de manera exitosa, sin embargo una vez ahí ocurriran problemas. El primero es que el parámetro que se envía parece tener un valor totalmente distinto al que pensabamos enviar. El segundo es que ya no tenemos acceso a los atributos de la clase de manera normal.
Este problema parece originarse debido a que la librería esta creada en lenguaje 'C'. La solución es que la función que se llama como callback debe ser declarada como 'static' en la declaración de la clase. Sin embargo, si declaramos una función de tipo 'static', una vez que llegamos a ella, no podemos emplear el apuntador 'this', ni tener acceso a los atributos del objeto, sin embargo, el parámetro enviado se recibe correctamente. Parece no haber solución al problema, pero lo que se debe hacer es 'recuperar el apuntador this'.
'Recuperar el apuntador this', significa que debemos almacenarlo en algun lugar al que se pueda acceder dentro de la función estática. Recordemos que los atributos del objeto no son candidatos para esto pues contienen valores aparentemente erroneos... el único candidato son los parámetros que se reciben correctamente.
Al leer la documentación de xforms, hemos encontrado que los autores planearon un apuntador 'libre' para que el usuario pudiera emplearlo para cualquier cosa necesaria. Es ese apuntador es el que vamos a emplear.
Así que dentro de la funcion AbreVentana() tendremos que 'almacenar' el apuntador, esto es al inicializar la ventana. A continuación se muestra un ejemplo de ello:
Primero, vemos parte del archivo de cabecera de la
ventana, donde se declara de manera estática la función DespachaCallback().
#include "../FORMS/forms.h"
#include "FORMS/form_V_principal.h"
[...]
#include "Ventana.h" // De esta hereda
class C_VentanaPrincipal:public
C_Ventana
{
protected:
// *** Enums locales.
*** //
// Los Identificadores
de Callbacks
enum { CB_MENU_ARCHIVO=1,CB_MENU_PROCESAR,CB_MENU_DESPLIEGUE,CB_MENU_AYUDA,
CB_MENU_RECONSTRUIR,CB_BOTON_ARRIBA,CB_BOTON_ABAJO,CB_BOTON_IZQ,
CB_BOTON_DER,CB_BOTON_ZOOM};
[...]
C_Aplicacion
*Cliente; // Esta ventana corresponde a la clase C_Aplicacion.
C_AreaGrafica
Pantalla; // El area grafica -> Agregacion.
[...]
// *** Metodos *** //
// Heredada
void Inicializa(); // Inicializaciones diversas.
// x-forms exclusivamente !
FD_ventana_Principal
*forma; // La forma
void CanvasHandler();
// Manejador del area grafica.
// Callbacks...
static void Despacha_Callback(FL_OBJECT *ob,long data); // Despachador...
void OnMenuDespliegue();
// Funciones que son llamadas dependiendo
void OnMenuProcesar();
// de las acciones.
void OnMenuArchivo();
void OnMenuAyuda();
void OnBotonZoom();
// Las funciones
siguientes no son parte del modelo especificamente sino de
// x-forms!
static int RecibeEvento(FL_OBJECT
*ob, Window win,int w,int h, XEvent *xev, void *ud);
FD_ventana_Principal
*create_form_ventana(void);
// Otras...
[...]
public:
// Constructor.
C_VentanaPrincipal(Referencia_I CliRef) {Cliente=(C_Aplicacion *)CliRef;}
// Funciones Heredadas
bool AbreVentana();
bool ActivaVentana();
bool CierraVentana();
};
Enseguida vemos cómo se guarda el apuntador a this (archivo VentanaPrincipal.cpp).
bool C_VentanaPrincipal::AbreVentana()
{
forma=create_form_ventana();
// Creacion de la forma
forma->ventana->u_vdata
= this; // Salva
el this, para que lo usen los callbacks.
Inicializa(); // Inicializa pantalla.
fl_show_form(forma->ventana,FL_PLACE_CENTER|FL_FREE_SIZE,FL_FULLBORDER,"principal"); // Muestra la forma.
DEBUGMSG("C_VentanaPrincipal::AbreVentana()\n");
return TRUE;
// Siempre...
}
Ahora se muestra cómo se recupera el apuntador a this en la función DespachaCallback()
void C_VentanaPrincipal::Despacha_Callback(FL_OBJECT
*ob,long data)
{
C_VentanaPrincipal
*ApTemp;
// Apuntador temporal
ApTemp=(C_VentanaPrincipal
*)ob->form->u_vdata; // Rescata el this
if(ApTemp->EsPrimeraVez==TRUE)
ApTemp->BorraIntro();
switch(data)
{
case(CB_MENU_ARCHIVO):
ApTemp->OnMenuArchivo();
// Ahora si; ejecuta callback!
break;
case(CB_MENU_PROCESAR):
ApTemp->OnMenuProcesar();
break;
case(CB_MENU_DESPLIEGUE):
ApTemp->OnMenuDespliegue();
break;
case(CB_MENU_AYUDA):
ApTemp->OnMenuAyuda();
break;
case(CB_BOTON_ARRIBA):
case(CB_BOTON_ABAJO):
case(CB_BOTON_IZQ):
case(CB_BOTON_DER):
ApTemp->PonCursor(COLOR_MARCO);
ApTemp->MueveCursor(data);
ApTemp->PonCursor(COLOR_CURSOR);
break;
case(CB_BOTON_ZOOM):
ApTemp->OnBotonZoom();
break;
}
}
La única manera de recuperar el 'this' es a partir de una fuente 'confiable' pero ya vimos que los miembros del objeto no lo son, sólo los parámetros pueden emplearse. Podemos apreciar que los callbacks en xforms siempre están definidos de la manera siguiente:
void NombreDelCallback(FL_OBJECT *ObjetoQueLlama,long Parametro)
No es posible enviar el apuntador a this como parámetro
(que es de tipo long), pero el objeto que llama a la función es
la vía por la cual se recupera.
Si prestamos atención a la declaración de la clase, podemos notar que DespachaCallback no es la única función declarada cómo 'static', sino que también existe otra:
static int RecibeEvento(FL_OBJECT *ob, Window win,int w,int h, XEvent *xev, void *ud);
Lo que sucede es que DespachaCallback es la función
que se llama cada que se interactua con las ventanas, pero RecibeEvento
es un callback que se asocia al área gráfica, y se llama
de manera automática cuando el área gráfica recibe
algun evento. Es por ello que RecibeEvento se tiene que declarar como static,
y dentro de ella hay que rescatar el this de manera idéntica.
Cómo vemos estas situaciones que aparecen
de 'rescate de this' no facilitan en nada el encapsulamiento de la librería
dentro del modelo, pero el resultado con esta aproximación es satisfactorio.
6.2 Pasos a seguír para implementar una nueva ventana.
Puesto que el programa puede requerir nuevas formas de interacción con el usuario, a continuación se muestra como agregar una nueva ventana.
Para agregar una nueva ventana a la aplicación, tenemos que seguir una serie de pasos. El primero es crear la forma con fdesign. A continuación se muestra una imagen de fdesign en acción la parte de abajo muestra la ventana que estamos creando.
Nota: Siempre tendremos que llamar a la forma 'ventana' (esto facilita tomar el código de otra ventana y adaptarlo), a todos los objetos se les tiene que asociar cómo callback la función 'DespachaCallback', también se debe de establecer el parámetro que identifique el objeto dentro de la forma y finalmente se les tiene que poner un nombre. La imagen a continuación muestra cómo se ve la pantalla de configuración de un objeto cuando se le aplican estas modificaciones.
#ifndef FD_ventana_h_
#define FD_ventana_h_
/* Header file generated
with fdesign. */
/**** Callback routines ****/
extern void DespachaCallback(FL_OBJECT
*, long);
/**** Forms and Objects ****/
typedef struct {
FL_FORM *ventana;
void *vdata;
long ldata;
} FD_ventana;
extern FD_ventana * create_form_ventana(void);
#endif /* FD_ventana_h_ */
Para poder incluir la ventana dentro de nuestra aplicación, se deben hacer algunas modificaciones que se muestran resaltadas a continuación.
#ifndef FD_ventana_DePrueba_h_
<- (1)
#define FD_ventana_DePrueba_h_
<- (1)
/* Header file generated
with fdesign. */
/**** Callback routines ****/
// extern void
DespachaCallback(FL_OBJECT *, long); <- (2)
/**** Forms and Objects ****/
typedef struct {
FL_FORM *ventana;
void *vdata;
long ldata;
} FD_ventana_DePrueba;
<- (3)
// extern FD_ventana * create_form_ventana(void); <- (4)
#endif /* FD_ventana_h_ */
(1) Es importante cambiar las lineas del #ifndef sino al incluir otros archivos de cabecera apareceran errores al ya estar definido FD_ventana_h_.
(2) Hay que comentar la(s) declaración(es) de DespachaCallback(), ya que esta función será redeclarada posteriormente como operación dentro de la forma.
(3) También hay que cambiar el nombre de la estructura, ya que siempre se llama FD_ventana al ser escrito el código, hay que ponerle algun extra que la diferencíe.
(4) Finalmente hay que comentar la declaración de create_form_ventana()
pues de igual forma de DespachaCallback(), será declarada dentro
de la clase correspondiente.
La cabecera esta lista para ser incluida dentro del archivo en donde
se declara la clase correspondiente a la ventana.
El paso siguiente es retomar el código en C que escribe xforms y 'encapsularlo' dentro de la clase.
A continuación se muestra el código escrito por fdesign
para el ejemplo mostrado arriba.
/* Form definition file generated with fdesign. */
#include "forms.h"
#include "prueba.h"
FD_ventana *create_form_ventana(void)
{
FL_OBJECT *obj;
FD_ventana *fdui
= (FD_ventana *) fl_calloc(1, sizeof(FD_ventana));
fdui->ventana
= fl_bgn_form(FL_NO_BOX, 600, 250);
obj = fl_add_box(FL_UP_BOX,0,0,600,250,"");
obj = fl_add_frame(FL_ENGRAVED_FRAME,480,20,110,220,"");
obj = fl_add_button(FL_NORMAL_BUTTON,490,190,90,40,"Boton1");
fl_set_object_lsize(obj,FL_MEDIUM_SIZE);
fl_set_object_callback(obj,DespachaCallback,CB_BOTON1);
obj = fl_add_slider(FL_HOR_SLIDER,20,20,260,20,"");
obj = fl_add_menu(FL_PULLDOWN_MENU,10,210,100,30,"Archivo");
fl_set_object_boxtype(obj,FL_FLAT_BOX);
obj = fl_add_canvas(FL_NORMAL_CANVAS,10,60,460,140,"");
obj = fl_add_frame(FL_ENGRAVED_FRAME,10,210,460,30,"");
obj = fl_add_button(FL_NORMAL_BUTTON,490,120,90,40,"Boton2");
fl_set_object_lsize(obj,FL_MEDIUM_SIZE);
obj = fl_add_button(FL_NORMAL_BUTTON,490,50,90,40,"Boton3");
fl_set_object_lsize(obj,FL_MEDIUM_SIZE);
obj = fl_add_text(FL_NORMAL_TEXT,290,20,180,20,"Forma
de prueba...");
fl_set_object_boxtype(obj,FL_DOWN_BOX);
fl_set_object_color(obj,FL_WHITE,FL_MCOL);
fl_end_form();
return fdui;
}
/*---------------------------------------*/
Este código tiene que quedar encapsulado dentro de la función:
FD_ventana_DePrueba *create_form_ventana(void);
De la manera siguiente (nuevamente, se resaltan las modificaciones):
FD_ventana_DePrueba
*C_VentanaDePrueba::create_form_ventana(void)
<-
(1)
{
// ____________________________PEGAR
LO QUE CREA XFORMS AQUI________________________
FL_OBJECT *obj;
FD_ventana_DePrueba
*fdui = <- (2)
(FD_ventana_DePrueba *) fl_calloc(1, sizeof(FD_ventana_DePrueba));
<-
(2)
fdui->ventana
= fl_bgn_form(FL_NO_BOX, 600, 250);
obj = fl_add_box(FL_UP_BOX,0,0,600,250,"");
obj = fl_add_frame(FL_ENGRAVED_FRAME,480,20,110,220,"");
obj = fl_add_button(FL_NORMAL_BUTTON,490,190,90,40,"Boton1");
fl_set_object_lsize(obj,FL_MEDIUM_SIZE);
fl_set_object_callback(obj,DespachaCallback,CB_BOTON1);
obj = fl_add_slider(FL_HOR_SLIDER,20,20,260,20,"");
obj = fl_add_menu(FL_PULLDOWN_MENU,10,210,100,30,"Archivo");
fl_set_object_boxtype(obj,FL_FLAT_BOX);
obj = fl_add_glcanvas(FL_NORMAL_CANVAS,10,60,460,140,"");
<-
(3)
obj = fl_add_frame(FL_ENGRAVED_FRAME,10,210,460,30,"");
obj = fl_add_button(FL_NORMAL_BUTTON,490,120,90,40,"Boton2");
fl_set_object_lsize(obj,FL_MEDIUM_SIZE);
obj = fl_add_button(FL_NORMAL_BUTTON,490,50,90,40,"Boton3");
fl_set_object_lsize(obj,FL_MEDIUM_SIZE);
obj = fl_add_text(FL_NORMAL_TEXT,290,20,180,20,"Forma
de prueba...");
fl_set_object_boxtype(obj,FL_DOWN_BOX);
fl_set_object_color(obj,FL_WHITE,FL_MCOL);
fl_end_form();
return fdui;
}
/*---------------------------------------*/
(1) La función tiene que ser definida como parte de la clase FD_ventana_DePrueba.
(2) Hay que cambiar todas las referencias a FD_ventana por FD_ventana_Nombre en donde Nombre es el nombre de la ventana en este caso es 'DePrueba'.
(3) Si se planea emplear OpenGL,el 'canvas' tiene que ser cambiado por 'glcanvas'.
Finalmente esta parte queda lista para ser incorporado dentro del archivo
de definición de la clase (.cpp).
Los pasos siguientes son los que hay que seguir para declarar la nueva
clase.
Supongamos que el cliente de la aplicación es una clase llamada
'C_ClientePrueba'.
// Este es el archivo VentanaPrincipal.h
#ifndef VENTANADEPRUEBA_H
#define VENTANADEPRUEBA_H
// Includes...
#include "General.h" <- (1)
#include "forms.h"
<- (2)
#include "Ventana.h"
<- (3)
#include "FORMS/form_V_prueba.h"
<- (4)
#include "ClientePrueba.h" <- (5)
// Defines...
class C_VentanaDePrueba:public
C_Ventana
{
protected:
// *** Enums locales.
*** //
enum {CB_BOTON_SELECCION1=1,CB_BOTON_SELECCION2}; <- (6)
// *** Atributos *** //
C_ClientePrueba
*Cliente; // Referencia al cliente <-
(7)
FD_ventana_DePrueba *forma; <- (8)
// *** Metodos *** //
// Callbacks
static void Despacha_Callback(FL_OBJECT *ob,long data);// Despachador de mensajes <- (9)
// X-forms
FD_ventana_DePrueba *create_form_ventana(void); <- (10)
// Otras
void
FuncionExtra1(); <- (11)
void
FuncionExtra2();
public:
C_VentanaDePrueba(C_ObjetoInteractivo*
CliRef) {Cliente=(C_ClientePrueba *)CliRef;} <-
(12)
// Estas son heredadas.
bool AbreVentana();
<- (13)
bool ActivaVentana();
bool CierraVentana();
};
#endif
(1) Siempre incluir el archivo 'General.h' que contiene declaraciones
necesarias.
(2) Incluir 'forms.h' que son los includes de la librería.
(3) Incluir 'Ventana.h' que es donde se declara la clase de donde
heredan todas las ventanas.
(4) Incluir el archivo de cabecera creado por fdesign y modificado
posteriormente.
(5) Incluir el archivo donde se declara la clase cliente.
(6) Crear los enums que identifican a los objetos.
(7) Tener una referencia al objeto cliente.
(8) Tener un apuntador a la forma. Esto es necesario para las
funciones de xforms.
(9) Declarar la función de despacho de callbacks.
(10)Declarar la función create_form_ventana() que contiene el
código que crea la ventana y que genera fdesign.
(11)Poner funciones extra que sean necesarias.
(12)El constructor de la ventana simplemente recibe la referencia al
cliente y la guarda en la que se declaro en (7).
(13)Las funciones heredadas a partir de C_Ventana y que detallaremos
a continuación.
Una vez que se ha declarado la clase correctamente, tememos que pasar a su implementación. Existen algunas funciónes que serán identicas para todas las ventanas, estas son AbreVentana() y CierraVentana() serán como sigue:
bool C_VentanaDePrueba::AbreVentana()
{
forma=create_form_ventana();
// Creacion de la forma
forma->ventana->u_vdata
= this;
// Salva this para uso de callbacks...
Inicializa();
// Inicializa pantalla.
fl_show_form(forma->ventana,FL_PLACE_CENTER,FL_FULLBORDER,"Ventana
de prueba"); // Muestra Ventana
return TRUE;
}
bool C_VentanaDePrueba::CierraVentana()
{
fl_hide_form(forma->ventana); // Cierra la ventana
return RetVal;
}
El siguiente paso es definir las funciones ActivaVentana() y DespachaCallback().
bool C_VentanaDePrueba::ActivaVentana()
{
FL_OBJECT *mensaje;
while(TRUE)
{
mensaje=fl_do_forms();
if(mensaje==forma->BOTON_APLICAR)
{
RetVal=TRUE;
// Espera OK.
return
TRUE;
}
if(mensaje==forma->BOTON_CANCELAR)
{
RetVal=FALSE;
return
FALSE;
}
}
}
Notese que para el ciclo de espera de eventos checamos el objeto recibido mediante su nombre, en despacha callback usaremos los enums definidos en la declaración de la clase.
// ____________________SIGUEN LAS DEFINICIONES DE LOS CALLBACKS_____________________
void C_VentanaDePrueba::Despacha_Callback(FL_OBJECT
*ob,long data)
{
C_VentanaSelAlgoritmo
*ApTemp; // Apuntador temporal
ApTemp=(C_VentanaDePrueba
*)ob->form->u_vdata; // Rescata this.
switch(data)
{
case(CB_BOTON_SELECCION1):
ApTemp->FuncionExtra1();
break;
case(CB_BOTON_SELECCION2):
ApTemp->FuncionExtra2();
break;
}
}
Nuestra ventana está lista para ser incluida al programa. Ahora tenemos que poder pedir su instancia. Hay que seguir algunos pasos sencillos.
1.- Dar un identificador a la ventana dentro del archivo General.h (se
muestra sólo la parte importante.)
[...]
// Los siguientes son los identificadores de las ventanas (IDV). 1001->1999
#define IDV_APLICACION
1001 // Ventana principal
#define IDV_SEL_ALGORITMO
1004 // La seleccion del algoritmo
#define IDV_CONF_STACK
1005 // La configuracion del stack
#define IDV_CONF_STACK_DISP
1006 // Configuracion del despliegue principal
#define IDV_CONF_SEG_UMBRAL
1007 // Configuracion del algoritmo segmentacion
por umbral
#define IDV_RECONSTRUCCION
1008 // Ventana de la reconstruccion.
#define IDV_PRUEBA
1009 // Ventana de prueba.
// Los siguientes son identificadores de dialogo (IDD) 2001->2999
#define IDD_CARGAR
2001 // Dialogo cargar
#define IDD_GUARDAR
2002 // Dialogo guardar
[...]
2.- Incluir la declaración de la clase dentro del archivo de definición del manejador.
// Este es el archivo
Manejador.cpp que contiene la definicion de la clase
// ManejadorDeVentanas.
AQUI HAY CODIGO ESPECIFICO A XFORMS!
#include "Manejador.h"
#include "Ventana.h"
#include "VentanaPrincipal.h"
#include "VentanaSelAlgoritmo.h"
#include "DialogoArchivo.h"
#include "VentanaConfStack.h"
#include "VentanaConfStackDisp.h"
#include "VentanaConfSegUmbral.h"
#include "VentanaReconstruccion.h"
#include "VentanaAcercaDe.h"
#include "VentanaDePrueba.h"
[...]
3.- Incluir también el la operación SeleccionaVentana()
el código que se encargue de instanciar esta ventana.
[...]
case IDV_RECONSTRUCCION:
VentanaActual=new
C_VentanaReconstruccion(Cliente);
Cliente->AsociaVentana(VentanaActual);
break;
case IDV_PRUEBA:
VentanaActual=new
C_VentanaDePrueba(Cliente);
Cliente->AsociaVentana(VentanaActual);
<- (1)
break;
// -- Dialogos -- //
case IDD_CARGAR:
[...]
(1) esta línea sólo es necesaria si necesitamos que el cliente pueda comunicarse con su ventana una vez que esta invoca a alguna de sus operaciones públicas(del cliente). En este caso también es necesario incluir el archivo de la declaración de la clase VentanaDePrueba dentro del archivo de definición de la clase cliente.
4.- Finalmente, podemos utilizar nuestra ventana.
Desde el cliente sólo basta con incluir la siguiente línea (notese que el cliente tiene que tener una referencia al manejador).
Manejador->SeleccionaVentana(IDV_PRUEBA,this); // Pide su ventana, esta toma el control.
Y listo!
Estos pasos se tienen que repetir siempre que se quieran agregar nuevas
ventanas, de ahí que podría ser útil una herramienta
que automatizara este proceso.