UNIVERSIDAD DEL ISTMO Ingeniería en computación Laboratorio de Programación de Sistemas CICLO ESCOLAR PROFESOR GRUPO 20082009B M. en C. J. Jesús Arellano Pimentel 204 NÚMERO DE PRÁCTICA 3 NOMBRE DE LA PRÁCTICA Entrada de datos interactiva mediante cuadros de diálogo y controles estándar. OBJETIVO GENERAL OBJETIVOS ESPECÍFICOS EQUIPO REQUERIDO SOFTWARE REQUERIDO Aprender a utilizar cuadros de diálogo modales y controles estándar para permitir la entrada de datos interactiva en aplicaciones Windows. - Aprender a construir plantillas de cuadros de diálogo e implementar su procedimiento de manejo de mensajes. - Conocer y utilizar controles de edición para la entrada interactiva de datos. - Aprender a utilizar controles estándar como ventanas hijas en el área cliente de la ventana principal. Computadora personal con 512 MB de RAM mínimo. - Windows XP/Vista - Microsoft Visual C++ 2008 Express Edition 1.- Fundamentos. 1.1.- Cuadros de diálogo modales Los cuadros de diálogo se utilizan para obtener entrada adicional del usuario que no se puede gestionar mediante el menú. Un cuadro de diálogo puede ser modal o no modal. El cuadro de diálogo modal es el más común. Cuando una aplicación muestra un cuadro de diálogo modal el usuario debe interactuar con este, normalmente pulsando un botón de aceptar o cancelar, antes de poder utilizar nuevamente la ventana principal [Petzold96]. Adicionar cuadros de diálogo a las aplicaciones en VC++ 2008 implica modificar tres archivos; el archivo Resourse.h para adicionar las constantes simbólicas necesarias, el archivo *.cpp de la aplicación para implementar el procedimiento del cuadro de diálogo y obviamente se debe modificar el archivo *.rc para editar la plantilla del cuadro de diálogo. 1.2.- Controles estándar Una cosa para recordar acerca de los controles es que son solo ventanas. Al igual que cualquier otra ventana tienen un window procedure, una clase ventana etc... que es registrada por el sistema [Pizarro03]. Todo lo que se puede hacer con las ventanas normales, se puede hacer con los controles. Ingeniería en Computación. M. en C. J. Jesús Arellano Pimentel 1 Los controles adicionados a una ventana se consideran ventanas hijas de la ventana padre a la cual fueron adicionados. Dado que un control es una ventana para crearlo habrá que invocar a la función CreateWindow, por ejemplo si se desea crear un botón se utiliza dicha función y con ello se evita tener que preocuparse por la lógica del ratón o la lógica de dibujar el botón o de hacer que el botón se hunda cuando se pulse. Sin embargo, estos controles casi siempre se utilizan con cuadros de dialogo así que para crearlos y configurarlos también se emplea una plantilla de especificación donde se colocan los controles necesarios para la interacción con el usuario, la Tabla 1 muestra una lista de los controles estándar empleados en aplicaciones Windows. 1.3.- La plantilla del cuadro de diálogo La plantilla del cuadro de diálogo generada automáticamente por VC++ 2008 es la siguiente: IDD_ABOUTBOX DIALOGEX 0, 0, 170, 62 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Acerca de CuadrosDlg" FONT 8, "MS Shell Dlg" BEGIN ICON IDR_MAINFRAME,IDC_STATIC,14,14,21,20 LTEXT "CuadrosDlg, versión 1.0",IDC_STATIC,42,14,114,8,SS_NOPREFIX LTEXT "Copyright (C) 2009",IDC_STATIC,42,26,114,8 "Aceptar",IDOK,113,41,50,14,WS_GROUP DEFPUSHBUTTON END La primera línea da nombre al cuadro de diálogo, en este caso IDD_ABOUTBOX. Dicho nombre en realidad es una constante simbólica almacenada en Resourse.h. El nombre es precedido de DIALOGEX y cuatro números. Los dos primero números son las coordenadas x, y de la esquina superior izquierda del cuadro de diálogo, relativas al área cliente de su padre cuando se invoca con el programa. Los dos números siguientes son el ancho y la altura del cuadro de dialogo. Estas coordenadas y tamaños no están en unidades de pixeles, sino basadas en un sistema de coordenadas especiales usado sólo por las plantillas de los cuadros de diálogo. Los números están basados en el tamaño de un carácter de la fuente del sistema: la coordenada x y la anchura se expresan en unidades de ¼ del ancho medio del carácter; mientras que la coordenada y y la altura se expresan en unidades de 1/8 la altura media del carácter [Petzold96]. La instrucción STYLE define el estilo del cuadro de diálogo, mínimo debe tener los estilos WS_POPUP y WS_MODALFRAME para ser un cuadro de diálogo de tipo modal. WS_CAPTIO( permite añadir una barra de título. WS_SYSME(U permite tener el botón de cerrar, en la barra de título. En [Salvador04] se tiene información sobre el resto de los estilos de la plantilla anterior y otros más. La instrucción CAPTIO( se utiliza para definir el título de la barra de título del cuadro de diálogo. La instrucción FO(T esta precedida del tamaño de la fuente y del nombre de la fuente. Entre las instrucciones BEGI( y E(D se colocan los controles del cuadro de diálogo. Ingeniería en Computación. M. en C. J. Jesús Arellano Pimentel 2 El formato de instrucción para definir los controles que ha de contener el cuadro de diálogo es la siguiente: tipo_control “texto” id, xPos, yPos, wAncho, yAltura [, iEstilo] [, iEstilo] es opcional; especifica estilos de ventana adicionales usando identificadores definidos en los archivos de cabecera de Windows. El tipo_control puede indicarse mediante una abreviación o simplemente como CO(TROL y [, iEstilo] con los estilos de ventana apropiada. La Tabla 1 presenta el tipo de control abreviado, la clase de ventana y el estilo de la ventana: Tipo de control PUSHBUTTON DEFPUSHBUTTON CHECKBOX RADIOBUTTON GROUPBOX LTEXT CTEXT RTEXT ICON EDITTEXT SCROLLBAR LISTBOX COMBOBOX Clase de ventana Estilo de ventana button BS_PUSHBUTTON | WS_TABSTOP button BS_DEFPUSHBUTTON | WS_TABSTOP button BS_CHECBOX | WS_TABSTOP button BS_CHECBOX | WS_TABSTOP button BS_GROUPBOX | WS_TABSTOP static SS_LEFT | WS_GROUP static SS_CENTER | WS_GROUP static SS_RIGHT | WS_GROUP static SS_ICON edit ES_LEFT | WS_BORDER | WS_TABSTOP scrollbar SBS_HORZ listbox LBS_NOTIFY | WS_BORDER | WS_VSCROLL combobox CBS_SIMPLE | WS_TABSTOP Tabla1. Especificación de tipos de controles estándar 1.3 El procedimiento del cuadro de diálogo El procedimiento del cuadro de dialogo gestiona todos los mensajes que llegan al cuadro de dialogo. Los parámetros de esta función son los mismos que los de un procedimiento de ventana normal, sin embargo estas funciones tienen sus diferencias, en particular el procedimiento de cuadro de dialogo devuelve un valor de tipo BOOL que es verdadero si procesa un mensaje y falso si no lo hace, además no necesita procesar los mensajes WM_PAI(T o WM_DESTROY y en lugar de procesar un mensaje WM_CREATE procesa un mensaje WM_I(ITDIALOG. El código del procedimiento del cuadro de dialogo generado automáticamente por VC++ 2008 es el siguiente: // Controlador de mensajes del cuadro Acerca de. INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_INITDIALOG: return (INT_PTR)TRUE; case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; } break; } return (INT_PTR)FALSE; } Ingeniería en Computación. M. en C. J. Jesús Arellano Pimentel 3 El primer mensaje que recibe o atiende el procedimiento es WM_I(ITDIALOG, para este caso en particular al solo regresar TRUE se pone el foco al primer control de cuadro de dialogo, en este caso el botón OK. El procesamiento del mensaje WM_COMMA(D simplemente cierra el cuadro de dialogo retornando el control a la ventana que lo invocó. 2.- Desarrollo 2.1 Suma de dos número introducidos mediante un cuadro de dialogo Paso 1 Iniciar el MS VC++ 2008 Express. Paso 2 Crear un nuevo proyecto. Hacer clic sobre el texto que dice Crear: Proyecto en la sección de proyectos recientes de la ventana de Inicio. Del cuadro de dialogo (uevo proyecto, en Tipos de proyecto seleccionar Win32; en Plantillas seleccionar Proyecto Win32. El nombre del proyecto o solución podría ser CdlgSuma. Presionar el botón Aceptar. Paso 3 Configurar el Proyecto Actual. Oprimir el botón Finalizar del cuadro de dialogo Asistente para aplicaciones Win32 Paso 4 Editar el código del archivo DlgSuma.cpp Declarar las siguientes variables globales para almacenar los números a sumar: int num1 = 0, num2 = 0; En la función InitInstance modificar los parámetros 6 y 7 (CW_USEDEFAULT, 0) en el llamado a la función CreateWindow por 400, 300, esto definirá el tamaño inicial para la ventana en 400 pixeles en x y 300 pixeles en y. En la función WndProc, declarar una cadena para almacenar el resultado de la operación de la siguiente forma: static TCHAR szSuma[64]; en el procesamiento del mensaje WM_COMMA(D, dentro del switch para analizar las selecciones del menú adicionar el caso correspondiente a la selección de la opción Sumar: case IDM_SUMA: DialogBox(hInst, MAKEINTRESOURCE(IDD_SUMA), hWnd, Suma); InvalidateRect(hWnd, NULL, TRUE); break; en el procesamiento del mensaje WM_PAI(T, después de la línea //TODO: Agregar código de dibujo aquí agregar el código necesario para mostrar el resultado de la operación, siempre y cuando se tenga un valor diferente de cero para cada uno de los números; dicho código es el siguiente: Ingeniería en Computación. M. en C. J. Jesús Arellano Pimentel 4 if(num1 != 0 || num2 != 0) { TextOut(hdc, 50, 50, szSuma, _stprintf(szSuma,L"%d + %d = %d", num1, num2, num1+num2)); } al principio del archivo en la sección de declaraciones de funciones se debe agregar el prototipo de la función (controlador) que ha de procesar los mensajes del cuadro de dialogo Suma de la siguiente forma: INT_PTR CALLBACK Suma(HWND, UINT, WPARAM, LPARAM); por último agregar el código para el controlador del cuadro de dialogo Suma, al final del archivo. Observe que es prácticamente el mismo código que para el controlador del cuadro de dialogo Acerca de, solo que este controlador se llama Suma y al procesar el mensaje de la pulsación del botón toma los valores editados en los controles de edición antes de cerrar el cuadro de dialogo. // Controlador de mensajes del cuadro Suma. INT_PTR CALLBACK Suma(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); BOOL bSuccess; switch (message) { case WM_INITDIALOG: return (INT_PTR)TRUE; case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { num1 = GetDlgItemInt(hDlg, IDC_NUM1, &bSuccess, FALSE); num2 = GetDlgItemInt(hDlg, IDC_NUM2, &bSuccess, FALSE); EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; } break; } return (INT_PTR)FALSE; } Paso 5 Editar el código del archivo Resource.h Se deben agregar las constantes simbólicas asociadas a la opción del menú, al cuadro de dialogo y a los controles del cuadro de dialogo teniendo cuidado de no repetir algún número. Las constantes simbólicas a agregar son las siguientes: #define #define #define #define IDM_SUMA IDD_SUMA IDC_NUM1 IDC_NUM2 200 201 202 203 //para //para //para //para la el el el opción del menú cuadro de dialogo control de edición del primer número control de edición del segundo número Paso 6 Editar el archivo de recursos DlgSuma.rc. Para adicionar la opción del menú que permitirá activar el cuadro de dialogo se debe editar el siguiente código en la plantilla del menú, después de la sección Archivo: POPUP "Suma" BEGIN MENUITEM "Sumar", END Ingeniería en Computación. IDM_SUMA M. en C. J. Jesús Arellano Pimentel 5 La plantilla para el cuadro de dialogo Sumar es la siguiente: IDD_SUMA DIALOGEX 0, 0, 100, 80 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Sumar" FONT 8, "MS Shell Dlg" BEGIN ICON IDR_MAINFRAME,IDC_STATIC,14,14,21,20 "Número 1:",IDC_STATIC,10,16,50,8 LTEXT EDITTEXT IDC_NUM1,55,14,40,14, ES_LEFT|WS_BORDER|WS_TABSTOP|ES_NUMBER LTEXT "Número 2:",IDC_STATIC,10,34,50,8 EDITTEXT IDC_NUM2,55,32,40,14, ES_LEFT|WS_BORDER|WS_TABSTOP|ES_NUMBER DEFPUSHBUTTON "Aceptar",IDOK,45,56,50,14,WS_GROUP END observe que los controles de tipo EDITTEXT corresponden a las cajas de edición que permitirán teclear los números, en este caso solo se permitirá digitar números enteros por la adición de la última bandera ES_(UMBER, si esta bandera se quita entonces las cajas de edición permitirán digitar cualquier carácter. En [Salvador04] se tiene una lista de las banderas (constantes de estilo) para el control de edición y en general para cualquier control. Paso 7 Generar y Depurar la solución (ver Figura 1). Presionar la tecla F5; si no hay errores deberá mostrarse y se realiza una suma debería presentarse algo como lo mostrado en la Figura 1. Figura 1. Ventana de la aplicación DlgSuma. 2.2 Suma de dos números introducidos mediante controles adheridos al área cliente Paso 1 Iniciar el MS VC++ 2008 Express. Paso 2 Crear un nuevo proyecto. Hacer clic sobre el texto que dice Crear: Proyecto en la sección de proyectos recientes de la ventana de Inicio. Del cuadro de dialogo (uevo proyecto, en Tipos de proyecto seleccionar Win32; en Plantillas seleccionar Proyecto Win32. El nombre del proyecto o solución podría ser VhSuma. Presionar el botón Aceptar. Paso 3 Configurar el Proyecto Actual. Oprimir el botón Finalizar del cuadro de dialogo Asistente para aplicaciones Win32 Ingeniería en Computación. M. en C. J. Jesús Arellano Pimentel 6 Paso 4 Editar el código del archivo VhSuma.cpp Definir las constantes simbólicas asociadas a los controles de edición y del botón para sumar: #define IDC_SUMA #define IDC_NUM1 #define IDC_NUM2 200 201 202 en la función WndProc declarar las siguientes variables: static HWND hNum1, hNum2, hbSuma; static int num1, num2; TCHAR szSuma[64]; agregar el siguiente caso al switch (message): case WM_CREATE: hNum1 = CreateWindow(L"edit", L"", WS_CHILD | WS_VISIBLE | WS_DLGFRAME | ES_LEFT | WS_TABSTOP | ES_NUMBER, 100, 20, 50, 22, hWnd, (HMENU)IDC_NUM1, hInst, NULL); hNum2 = CreateWindow(L"edit", L"", WS_CHILD | WS_VISIBLE | WS_DLGFRAME | ES_LEFT | WS_TABSTOP | ES_NUMBER, 100, 50, 50, 22, hWnd, (HMENU)IDC_NUM2, hInst, NULL); hbSuma = CreateWindow(L"button", L"Sumar", WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON, 20, 80, 65, 22, hWnd, (HMENU) IDC_SUMA, hInst, NULL); SetFocus(hNum1); break; agregar el siguiente caso al switch(wmId) que se procesa dentro del case WM_COMMA(D: case IDC_SUMA: num1 = GetDlgItemInt(hWnd, IDC_NUM1, NULL, FALSE); num2 = GetDlgItemInt(hWnd, IDC_NUM2, NULL, FALSE); InvalidateRect(hWnd, NULL, TRUE); break; en el procesamiento del caso WM_PAI(T colocar el siguiente código: TextOut(hdc, 20, 25, L"Numero 1:", _tcslen(L"Numero 1:")); TextOut(hdc, 20, 55, L"Numero 2:", _tcslen(L"Numero 2:")); if(num1 != 0 || num2 != 0) { TextOut(hdc, 100, 82, szSuma, _stprintf(szSuma,L"%d + %d = %d", num1, num2, num1+num2)); } Ingeniería en Computación. M. en C. J. Jesús Arellano Pimentel 7 4.- Referencias [Pizarro03] Pizarro Federico. Tutorial de theForger: Win32 API. Versión 2.0. 2003. Web: http://winprog.org/tutorial/es/. Fecha de consulta Marzo 2009. [Petzold96] Petzold Charles, et al. Programación en Windows 95. Mc Graw Hill – Microsoft Press. 1996. [Salvador04] Salvador Pozo Coronado. Win API con Clase. Aplicaciones con API 32. Disponible en http:\winapi.conclase.net Ingeniería en Computación. M. en C. J. Jesús Arellano Pimentel 8