Ejemplo: dlg_two
Ahora ech�mosle un vistazo a CreateDialog( ), la hermana de DialogBox( ). La diferencia es que mientras DialogBox() implementa su propio bucle de mensajes y no retorna hasta que el di�logo sea cerrado, CreateDialog() act�a de manera mas parecida a una ventana creada con CreateWindowEx(), la cual retorna inmediatamente y depende de tu bucle de mensajes enviar los mensajes a tu ventana principal. Esto es llamado Modelamiento mientras que DialogBox() crea
di�logos Modales.
Podemos crear el recurso di�logo de la misma manera que lo hicimos en el ejemplo anterior, tambi�n debemos asignar el estilo extendido "Tool Window" (ventana de herramientas) para darle a la barra de titulo el t�pico t�tulo peque�o de las barras de herramientas. El recurso di�logo que he creado es el siguiente:
IDD_TOOLBAR DIALOGEX 0, 0, 98, 52
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION
EXSTYLE WS_EX_TOOLWINDOW
CAPTION "My Dialog Toolbar"
FONT 8, "MS Sans Serif"
BEGIN
PUSHBUTTON "&Press This Button",IDC_PRESS,7,7,84,14
PUSHBUTTON "&Or This One",IDC_OTHER,7,31,84,14
END
Habr�s observado que el editor de recursos ha reemplazado DIALOG con DIALOGEX indicando que queremos asignar un EXSTYLE en nuestro di�logo.
A continuaci�n, queremos crear el di�logo cuando el programa se ejecuta y ademas queremos que el di�logo sea visible, por lo tanto hacemos esto en WM_CREATE. Tambi�n queremos declarar una varialbe global para almacenar el handle retornado por CreateDialog( ), que usaremos luego. DialogBox( ) no retorna un handle debido a que cuando �ste retorna, el di�logo ha sido destruido.
HWND g_hToolbar = NULL;
case WM_CREATE:
g_hToolbar = CreateDialog(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_TOOLBAR),
hwnd, ToolDlgProc);
if(g_hToolbar != NULL)
{
ShowWindow(g_hToolbar, SW_SHOW);
}
else
{
MessageBox(hwnd, "CreateDialog returned NULL", "Warning!",
MB_OK | MB_ICONINFORMATION);
}
break;
Es una buena idea chequear siempre los valores de retorno, y si son v�lidos (distintos de NULL) mostramos la ventana usando ShowWindow(), con DialogBox( ) esto no es necesario debido a que el sistema llama a ShowWindow() por nosotros.
Ahora necesitamos un Dialog Procedure para nuestra barra de herramientas.
BOOL CALLBACK ToolDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
switch(Message)
{
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDC_PRESS:
MessageBox(hwnd, "Hi!", "This is a message",
MB_OK | MB_ICONEXCLAMATION);
break;
case IDC_OTHER:
MessageBox(hwnd, "Bye!", "This is also a message",
MB_OK | MB_ICONEXCLAMATION);
break;
}
break;
default:
return FALSE;
}
return TRUE;
}
La mayor�a de las reglas de procesamiento de mensajes se aplican a los di�logos creados con CreateDialog( ) y al igual que con DialogBox( ) no llamamos a DefWindowProc( ), retornamos FALSE en los mensajes que no procesamos y TRUE en los que si lo hacemos.
Un cambio es que, en los di�logos de modelamiento, no llamamos a EndDialog( ), simplemente usamos DestroyWindow( ) como lo hac�amos con las ventanas regulares. En este caso, destru�mos el di�logo cuando la ventana principal es destru�da. En el WndProc() de la ventana principal...
case WM_DESTROY:
DestroyWindow(g_hToolbar);
PostQuitMessage(0);
break;
Por �ltimo, pero no menos importante, queremos ser capaz de mostrar y ocultar nuestra barra de herramientas cada vez que el usuario lo desee, por lo tanto agregamos dos comandos al men� y los procesamos as�:
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_DIALOG_SHOW:
ShowWindow(g_hToolbar, SW_SHOW);
break;
case ID_DIALOG_HIDE:
ShowWindow(g_hToolbar, SW_HIDE);
break;
//... other command handlers
}
break;
Hasta aqu�, debes ser capaz de crear tu propio men� usando el editor de recursos o manualmente, si no es as� (como pasa siempre) puedes observar el ejemplo dlg_two que viene junto a este tutorial.
Cuando ejecutes el programa, debes ser capaz de acceder a la ventana de di�logo y a la ventana pricipal al mismo tiempo.
Si ejecutaste el programa e intentaste correr el foco entre los dos botones usando la tecla tab, probablemente habr�s observado que esto no funciona, como asi tampoco funciona activar los botones presionando Alt-O o Alt-P. �Por que no? DialogBox() implementa su propio bucle de mensajes y procesa estos eventos por default, pero CreateDialog( ) no lo hace. Podemos hacerlo nosotros, llamando a IsDialogMessage( ) en nuestro bucle de mensajes, el cual har� los procesos por default en lugar nuestro.
while(GetMessage(&Msg, NULL, 0, 0))
{
if(!IsDialogMessage(g_hToolbar, &Msg))
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
}
Aqui, primero pasamos el mensaje a IsDialogMessage( ), si el mensaje est� destinado a nuestra barra de herramientas (indicado por el handle que le pasamos) el sistema realizar� los procesamientos por default y retornar� TRUE. Si es el caso en que los mensajes ya han sido procesados, entonces no llamamos a TransalateMessage( ) o DispatchMessage( ) y si el mensaje es para otra ventana, lo procesamos de la manera usual.
Es importante notar que IsDialogMessaje( ) tambi�n puede ser usado con ventanas que no son di�logos, con la intenci�n de darles el comportamiento de un di�logo. Recuerda que un di�logo es una ventana y la mayor�a (por no decir todas) de las API's para di�logos funcionar�n correctamente en cualquier ventana.
Un aspecto para destacar es �que pasa si tienes mas de una barra de herramientas? Bien, una posible soluci�n es tener una lista (o un arreglo) y ciclar en nuestro bucle de mensajes pasando cada handle a IsDialogMessage( ) hasta que encontremos el correcto y si no lo es, hacemos el procesamiento regular. Este es un problema de programaci�n gen�rico y no uno que est� relacionado con Win32, por lo tanto se deja como ejercicio para el lector.
Versi�n en Espa�ol: Federico Pizarro - 2003