[ contenidos | #winprog ]

Aplicación Parte 1: Crear Controles en Tiempo de Ejecución

Example: app_one

[images/app_one.gif]

Pienso que dar un ejemplo sobre crear controles en ejecución, si bien es muy usado, podría ser en vano a menos que la aplicación realmente haga algo útil, por lo tanto en esta sección voy a comenzar con el desarrolo de un editor de texto y lo iremos desarrollando hasta que alcanzemos un programa útil que soporte abrir, editar y guardar archivos de textos.

El primer paso, el cual es cubierto por esta sección, será simplemente crear la ventana y el control EDIT que servirá como centro de nuestro programa.

Comenzaremos con el esquelto del código de la aplicación Simple Window, agregaremos un #define para el ID de nuestro control y los siguientes dos manejadores de mensajes en nuestro window procedure:

#define IDC_MAIN_EDIT	101
    case WM_CREATE:
    {
        HFONT hfDefault;
        HWND hEdit;

        hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "", 
            WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL, 
            0, 0, 100, 100, hwnd, (HMENU)IDC_MAIN_EDIT, GetModuleHandle(NULL), NULL);
        if(hEdit == NULL)
            MessageBox(hwnd, "Could not create edit box.", "Error", MB_OK | MB_ICONERROR);

        hfDefault = GetStockObject(DEFAULT_GUI_FONT);
        SendMessage(hEdit, WM_SETFONT, (WPARAM)hfDefault, MAKELPARAM(FALSE, 0));
    }
    break;
    case WM_SIZE:
    {
        HWND hEdit;
        RECT rcClient;

        GetClientRect(hwnd, &rcClient);

        hEdit = GetDlgItem(hwnd, IDC_MAIN_EDIT);
        SetWindowPos(hEdit, NULL, 0, 0, rcClient.right, rcClient.bottom, SWP_NOZORDER);
    }
    break;

Crear los controles

Para crear los controles, al igual que lo hacemos para cualquier otra ventana, utilizamos la API CreateWindowEx( ). Pasamos una clase pre-registrada, en este caso la clase del control "EDIT", y obtenemos un control edit estándar. Cuando usamos diálogos para crear nuestros controles, básicamente estamos escribiendo una lista de controles a crear, tal que, cuando llamamos a DialogBox( ) o CreateDialog( ) el sistema lee la lista de controles en el recurso diálogo y por cada uno llama a CreateWindowEx( ), con la posición y estilo con que fueron definidos.
    hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "", 
        WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL, 
        0, 0, 100, 100, hwnd, (HMENU)IDC_MAIN_EDIT, GetModuleHandle(NULL), NULL);
    if(hEdit == NULL)
        MessageBox(hwnd, "Could not create edit box.", "Error", MB_OK | MB_ICONERROR);
Puedes ver que esta llamada a CreateWindowEx( ) especifica cierta cantidad de estilos y no es extraño tener alguno mas, especialmente para los controles comunes los cuales tienen una larga lista de opciones. Los primeros cuatro estilos WS_ deberian ser obvios, estamos creando el control como un hijo de nuestra ventana, queremos que sea visible y tenga barras de desplazamiento vertical y horizontal. Los tres estilos que son específicos de los controles EDIT (ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL) especifican que el control edit debe poseer múltiples lineas de texto y desplazarse automáticamente cuando tipeamos mas alla del límite inferior de la ventana y del limite derecho de la misma.

Los estilos regulares (WS_*) puedes encontrarlos en: listed here. y los estilos extendidos (WS_EX_*) son explicados en: CreateWindowEx() estas referencias son de MSDN donde también puedes encontrar links a los estilos específicos de cada control (ES_* en el caso del control EDIT).

Hemos especificado nuestro window handle como padre del control y le asignamos un ID de IDC_MAIN_EDIT, el cual usaremos luego para referirnos al control, de la misma manera que lo hariamos si el control hubiera sido creado en un diálogo. Los parámetros de posición y tamaño no importan mucho por el momento, debido a que cambiaremos el tamaño del control dinámicamente con el mensaje WM_SIZE para que éste siempre entre en nuestra ventana.

Cambio del tamaño de controles creados dinámicamente

Generalmente, si el tamaño de nuestra ventana puede ser cambiado, tendremos algún código para reposicionar o ajustar el tamaño de los controles que hemos creado dentro de ella, para que siempre sean mostrados apropiadamente.
    GetClientRect(hwnd, &rcClient);

    hEdit = GetDlgItem(hwnd, IDC_MAIN_EDIT);
    SetWindowPos(hEdit, NULL, 0, 0, rcClient.right, rcClient.bottom, SWP_NOZORDER);

Debido a que por ahora solo tenemos un control, la tarea es relativamente simple. Usamos GetClientRect( ) para obtener las dimensiones del Area Cliente de la ventana, la gran área vacía (por ahora) que no inlcluye los bordes, menú o título. Esto llenará nuestra estructura RECT con valores. Los valores left y top siempre serán 0, por lo tanto puedes ignorarlos. Los valores right and bottom indican el ancho y el alto del area cliente.

A Continuación, simplemente obtenemos el handle a nuestro control EDIT usando GetDlgItem( ), el cual funciona bien en las ventanas regulares como en los diálogos y la llamada SetWindowPos( ) para mover y ajustar el tamaño para llenar todo el área cliente. Por su puesto, puedes cambiar los valores pasados en SetWindowPos( ) para hacer algo como sólo llenar la mitad del alto de la ventana, dejando libre la parte inferior para ubicar otros controles.

Crear otros controles en tiempo de ejecución

No voy a dar ejemplos de como crear dinámicamente los otros controles, como listas, botones, etc... debido a que es básicamente lo mismo. Si visitas los links anteriores en MSDN o buscas en tu referencia de Win32 API, encotrarás toda la información necesaria para crear cualquiera de los otros controles estándar.

Veremos mas sobre esto con los controles comunes, en la siguientes secciones, donde obtendrás mas práctica.


Copyright © 1998-2003, Brook Miles (theForger). All rights reserved.

Versión en Español: Federico Pizarro - 2003