Apunte de Visual C++
Por: Demian Panello demianpanello@yahoo.com.ar
Capítulo V
Indice rápido del capítulo 5:
DIALOGOS MODALES Y NO MODALES:
Hasta ahora hemos visto aplicaciones que sólo usaban un solo cuadro de diálogo (una sola ventana); a pesar que AppWizard nos genera un AboutBox.
Desde ya que una aplicación no se basa siempre en un solo diálogo sino que a veces necesitaremos incorporar más ventanas a nuestros programas. Crearemos entonces un proyecto al cual llamaremos Dialogos y como siempre será Dialog Based.
Una vez generada la aplicación por AppWizard verá el diálogo cotidiano con los botones Aceptar y Cancelar.
Antes de incorporar un nuevo diálogo modificaremos nuestra pantalla principal.
Coloque el botón Cancelar en el extremo inferior izquierdo del cuadro de diálogo. Acceda a las propiedades de este botón, cambie su ID por IDC_LLAMA y CAPTION por "Llamar al otro diálogo".
Ahora agregaremos un nuevo diálogo, para esto en la ventana WorkSpace debe estar activa la solapa ResourceView (seguramente está activa ésta pues estuvo modificando el botón). Haga click con el botón derecho del mouse sobre la carpeta Dialog y seleccione Insert Dialog del menú contextual.
Aparecerá un nuevo diálogo con los botones Aceptar, Cancelar y por defecto ID = IDD_DIALOG1. Si lo desea puede modificar las propiedades del diálogo, pero en este caso dejaremos todo como está.
Cuando un agrega un diálogo sólo se incorpora el recurso (archivo de recurso), que sería el aspecto visual, pero para nada está aún vinculado con la aplicación, pues necesita de una clase la cual traerá consigo las funciones miembro y los datos miembro. Por eso cada vez que inserte un cuadro de diálogo cree la clase del mismo, ¿cómo se hace esto?; simplemente presione Ctrl + W y aparecerá automáticamente antes de entrar a ClassWizard la siguiente ventana:

Se detectó que IDD_DIALOG1 es un nuevo recurso y que probablemente necesitaremos una clase para el mismo, entonces no ofrece crear una nueva o seleccionar una existente; elegiremos Create a new class y pulsamos OK.
Aparecerá una ventana pidiendo que ingresemos un nombre para la clase, allí ingresaremos CDialogo1, (por convención todas las clases comienzan con la letra C).

Automáticamente en el campo File Name aparecerá Dialogo1.cpp, (aquí se encontrará la definición de la clase) y en la lista Base Class verifique que se encuentre seleccionada Cdialog. Presione OK, pasará a ClassWizard, presione nuevamente OK para cerrar el asistente.
Ya tenemos entonces un nuevo cuadro de diálogo y una clase para el mismo, obviamente esto no hace que nuestra nueva ventana sea útil en nuestro programa, ahora deberemos escribir el código necesario para poder mostrarla.
Regresemos a la ventana principal, pues el código que llamará al nuevo diálogo estará al presionar el botón IDC_LLAMA. Pero el diálogo donde está este botón reconocerá la clase del nuevo diálogo si agregamos en el archivo de implementación del diálogo principal el archivo de cabecera del nuevo diálogo que fue generado por ClassWizard, el cual tiene el mismo nombre que el de implementación pero con extensión .h (en nuestro ejemplo sería dialogo1.h ). No se olvide, entonces, de agregar la línea #include "Dialogo1.h" en DialogosDlg.cpp.
Cuando uno muestra un cuadro de diálogo de forma MODAL, hasta tanto no se cierre el diálogo llamado con su respectivo botón cerrar o desde el menú de sistema NO SE PODRÁ ACCEDER AL RESTO DE LA APLICACIÓN y si se lo muestra NO MODAL en cambio PODRA ACCEDER A OTROS PUNTOS DE LA APLICACIÓN.
Por ejemplo: en VC++ la barra de herramientas, donde están los controles, es un diálogo NO MODAL, pues uno puede acceder a diferentes secciones de VC sin necesidad de cerrar la barra. Por otro lado ClassWizard es un diálogo, ventana, MODAL porque mientras no pulsemos OK, CANCEL o el botón de cerrar de la ventana no podremos utilizar el resto de VC++.
En principio veremos como llamar al cuadro de diálogo IDD_DIALOG1 como MODAL.
Haga doble click en el botón IDC_LLAMA, (generará automáticamente el evento OnLlama) y escriba:
void CDialogosDlg::OnLlama()
{
// TODO: Add your control notification handler code here
int r; (1)
CDialogo1 dlgDialogo1(this); (2)
r=dlgDialogo1.DoModal (); (3)
}
Este código simplemente se ajusta a llamar al diálogo de forma modal. En (2) se crea un objeto derivado de la clase CDialogo1 especificando Clase variable(this), this es un puntero que hace referencia al objeto actual, o sea el diálogo principal. Y en (3) a través de DoModal(), del objeto recién creado, se llama al diálogo, y es más, se le pasa en este punto el control del programa, de manera tal que cuando se cierre el nuevo cuadro de diálogo el flujo del programa continuará después de esta línea. Por eso DoModal() retorna un valor entero que puede ser IDOK si el nuevo diálogo al momento de cerrarlo con EndDialog(), (ver más adelante), se le pasó el parámetro IDOK.
Por esto extienda el código de IDC_LLAMA como sigue:
void CDialogosDlg::OnLlama()
{
// TODO: Add your control notification handler code here
int r;
CDialogo1 dlgDialogo1(this);
r=dlgDialogo1.DoModal ();
//al volver verificará como se cerró
if (r == IDOK)
AfxMessageBox("Usted cerró con Aceptar o Si");
else
AfxMessageBox("Usted cerró con Cancelar o NO");
}
En el nuevo diálogo agregue un botón con las siguientes propiedades:
ID = IDC_CERRAR
CAPTION = CERRAR.
void CDialogo1::OnCerrar()
{
// TODO: Add your control notification handler code here
CString Mensa;
Mensa="Seleccione para cerrar SI o No";
if (MessageBox(Mensa,MB_YESNO+ MB_ICONINFORMATION)==IDYES) (1)
EndDialog(IDOK);
else
EndDialog(IDCANCEL);
}
Cuando se presione el botón Cerrar, para cerrar el diálogo, se le informa al usuario que seleccione como quiere salir, presionando OK o CANCEL, de acuerdo a lo que se pulse.

Resumiendo:
Descargar archivos fuentes del ejemplo: dialogos.zip
DIALOGOS NO MODALES:
Ahora veamos como llamar a diálogos NO MODALES.
ID = IDC_LLAMAR y CAPTION = Llamar a diálogo no modal.
ID = IDC_CERRAR y CAPTION = Cerrar diálogo no modal.
En el evento OnLlamar escriba:
CDialogoNoModal* dlgNoModal =NULL; (1)
void CNomodalDlg::OnLlamar()
{
// TODO: Add your control notification handler code here
if (dlgNoModal == NULL) (2)
dlgNoModal = new CDialogoNoModal(this); (3)
}
En la línea (1) antes de comenzar la función se declara un puntero a la clase del nuevo diálogo (global) y por defecto se le asigna el valor NULL. Este puntero servirá para crear una instancia de la clase que será la forma por la cual manipularemos luego el diálogo.
Precisamente en (2) si el puntero es NULL se crea la instancia por medio del operador new (3) el cual reserva memoria para el objeto descendiente de this o sea el diálogo que lo llama.
Con esto la aplicación no va a funcionar, hace falta llamar a la función Create() y ShowWindow() desde el constructor del nuevo formulario. Lo escrito en el constructor será los primero en ejecutarse al ocurrir la línea (3).
Al constructor del nuevo diálogo se accede por medio de la solapa ClassView de la ventana WorkSpace. Expanda la clase del nuevo diálogo y haga doble click donde dice: CDialogoNoModal(CWnd* pParent =NULL); y escriba:
CDialogoNoModal::CDialogoNoModal(CWnd* pParent /*=NULL*/)
: CDialog(CDialogoNoModal::IDD, pParent)
{
//{{AFX_DATA_INIT(CDialogoNoModal)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
//Crear la ventana del cuadro de diálogo no modal
if (Create(CDialogoNoModal::IDD, pParent)) (1)
ShowWindow(SW_SHOW); (2) //Si se pudo crear, se muestra
}
Cuando, en el diálogo principal, se pulsa el botón que llama al nuevo diálogo (usando new ), se ejecuta el código del constructor del objeto dlgNoModal, donde habitualmente se inicializan, por ejemplo variables miembros, pero en este caso se intenta crear el diálogo (1) y de ser posible lo muestra (2).
Si ejecuta la aplicación y pulsa el botón que dice: "Llamar a diálogo no modal" accederá al nuevo diálogo no modal que permite acceder indistintamente a sus controles como a los del diálogo principal.

Faltaría escribir el código en el botón que permite cerrar el diálogo no modal desde la ventana que lo llamó. Escriba el siguiente código en IDC_CERRAR del diálogo principal:
void CNomodalDlg::OnCerrar()
{
// TODO: Add your control notification handler code here
if (dlgNoModal != NULL)
{
delete dlgNoModal;
dlgNoModal = NULL;
}
}
Acá se averigua si la variable objeto CnomodalDlg no contiene NULL, porque si no es NULL es porque ha sido referenciada ya una vez, lo que implica que se está mostrando aún el diáologo, entonces elimina la memoria reservada y le vuelve a asignar NULL.