[ contenidos | #winprog ]

Aplicación Parte 3: Barras de Herramientas y Barras de Estado

Ejemplo: app_three

[images/app_three.gif]

Una Palabra IMPORTANTE en los Controles Comunes

Al igual que con todos los controles comunes, debemos llamar a InitCommonControl ANTES de intentar usarlos. Necesitaremos #include <commctrl.h> para poder usar esta función y para obtener la funciones y declaraciones necesarias para el uso de los controles comunes. También necesitaremos agregar comctl32.lib en la configuración de nuestro enlazador (linker), si no se encuentra configurado de esa manera. Observa que InitCommonControls( ) es una vieja API, para obtener mas control podemos usar InitCommonControlsEx( ) la cual es requerida por los más recientes controles comunes. Sin embargo, debido a que no voy a usar ninguna de las características avanzadas, InitCommonControls( ) será adecuado y mas simple.

Barras de Herramientas

Podemos crear una barra de herramientas usando CreateToolbarEx( ) pero no es la idea... Lo que necesitamos hacer es crear la barra de herramientas...

    hTool = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0,
        hwnd, (HMENU)IDC_MAIN_TOOL, GetModuleHandle(NULL), NULL);

Esto es bastante simple, TOOLBARCLASSNAME es una constante definida por los encabezados (headers) de los controles comunes. hwnd es la ventana padre, la ventana en la que aparecerá la barra de herramientas. IDC_MAIN_TOOL es un identificador que podemos usar posteriormente para obtener el HWND de la barra de herramientas por medio de GetDlgItem( ).

     // Send the TB_BUTTONSTRUCTSIZE message, which is required for
     // backward compatibility.
     SendMessage(hTool, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);

Este mensaje es necesario para permitirle al sistema darse cuenta que versión de la librería de controles comunes estamos usando. Debido a que nuevas versiones agregan código a la estructura, dando el tamaño de la misma el sistema puede darse cuenta que comportamiento estamos esperando.

Botones de la barra de Herramientas

Los botones con bitmaps para las barras de herramientas vienen en dos variedades, los botones estándar que son provistos por comctl32 y los botones definidos por el usuario, que son creados por él mismo. NOTA: Los botones y bitmaps son agregados a las barras de herramientas en forma separada... primero agregamos una lista de imágenes a usar y luego agregamos la lista de botones. Por último especificamos que imagen usar en cada botón.

Agregado de Botones Estándar

Ahora que hemos creado una barra de herramientas, necesitamos agregarle algunos botones. Los bitmaps mas comunes están disponibles dentro de la librería de los controles comunes, por lo tanto no necesitamos crearlos o agregarlos en cada archivo .exe que los usa.

Primero declaramos TBBUTTON y TBADDBITMAP

    TBBUTTON tbb[3];
    TBADDBITMAP tbab;
y luego agregamos los los bitmaps estándar a la barra de herramientas usando la lista de imágenes en la libreria de los controles comunes...
    tbab.hInst = HINST_COMMCTRL;
    tbab.nID = IDB_STD_SMALL_COLOR;
    SendMessage(hTool, TB_ADDBITMAP, 0, (LPARAM)&tbab);
Ahora que hemos cargado nuestras imágenes, podemos agregar algunos botones que las utilicen...
    ZeroMemory(tbb, sizeof(tbb));
    tbb[0].iBitmap = STD_FILENEW;
    tbb[0].fsState = TBSTATE_ENABLED;
    tbb[0].fsStyle = TBSTYLE_BUTTON;
    tbb[0].idCommand = ID_FILE_NEW;

    tbb[1].iBitmap = STD_FILEOPEN;
    tbb[1].fsState = TBSTATE_ENABLED;
    tbb[1].fsStyle = TBSTYLE_BUTTON;
    tbb[1].idCommand = ID_FILE_OPEN;

    tbb[2].iBitmap = STD_FILESAVE;
    tbb[2].fsState = TBSTATE_ENABLED;
    tbb[2].fsStyle = TBSTYLE_BUTTON;
    tbb[2].idCommand = ID_FILE_SAVEAS;

    SendMessage(hTool, TB_ADDBUTTONS, sizeof(tbb)/sizeof(TBBUTTON), (LPARAM)&tbb);
Aquí hemos agregado los botones New, Open y Save As usando las imágenes estándar, lo cual es una buena idea debido a que las personas suelen verlas y ya saben que significan.

Los índices de las lista de imágenes están definidos en los encabezados de los controles comunes y también son listados en MSDN.

Hemos asignado a cada botón un ID (ID_FILE_NEW, etc...) lo cual es idéntico a los IDs de los items equivalentes en el Menú. Estos botones generarán mensajes WM_COMMAND identicos a los del Menú, por lo tanto no se requiere algún procesamiento extra! Si fueramos a agregar un botón para un comando que no aparece en el Menú, simplemente definimos un nuevo ID y agregamos un manejador a WM_COMMAND.

Si te estás preguntando por qué he pasado wParam a TB_ADDBUTTONS, bueno, está realizando un cálculo del número de botones en el arreglo tbb para que no necesitemos especificar un valor. Si en lugar de esto, lo que hacemos es poner un 3, bien, estaría correcto pero que sucede si queremos agregar otros botones... deberíamos cambiar este numero por 4 y en programación eso no es muy bueno... queremos que los cambios provoquen la menor cantidad de cambios. Por ejemplo, si el tamaño de TBBUTON tiene 16 bits, debido a que tenemos 3 botones el tamaño del tbb debería ser de 16*3 = 48. Del mismo modo, 48/16 da el número de botones, 3 en este caso.

Barras de Estado

Algo que se suele encontrar a menudo en las aplicaciones son las barras de estado, la pequeña barra en la parte inferior de la ventana que muestra información. Son muy fácil de usar, solo hay que crearlas...
    hStatus = CreateWindowEx(0, STATUSCLASSNAME, NULL,
        WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP, 0, 0, 0, 0,
        hwnd, (HMENU)IDC_MAIN_STATUS, GetModuleHandle(NULL), NULL);
Y luego (opcionalmente) especificamos el numero de secciones que deseamos. Si no especificamos ninguna, simplemente tendrá una que usa el ancho entero de la barra. Podemos especificar o recuperar el texto usando SetWindowText( ) como con lo hacíamos con muchos de los otros controles. Si especificamos más de una sección, necesitamos especificar el ancho de cada una y luego usar SB_SETTEXT para especificar el texto de cada sección.

Para definir los anchos declaramos un arreglo de enteros donde cada valor es el ancho en pixeles de una sección. Si queremos que una sección use el espacio restante fijamos como valor -1.

El wParam nuevamente es para calcular cuantos elementos hay en el arreglo. Una vez que hemos terminado de agregar secciones, fijamos el primer valor (de índice 0) para verla en acción.

Tamaño Apropiado

A diferencia de los Menúes, las barras de estado y de herramientas son controles separados que viven dentro del área cliente de la ventana padre. Por lo tanto si solo dejamos nuestro código WM_SIZE anterior, se van a solapar con el control edit que hemos agregado en los ejemplos anteriores. En WM_SIZE, ponemos las barras de estado y de herramientas en posición y luego restamos el alto del area cliente para que podamos mover nuestro control edit para rellenar el espacio restante...
    HWND hTool;
    RECT rcTool;
    int iToolHeight;

    HWND hStatus;
    RECT rcStatus;
    int iStatusHeight;

    HWND hEdit;
    int iEditHeight;
    RECT rcClient;

    // Size toolbar and get height

    hTool = GetDlgItem(hwnd, IDC_MAIN_TOOL);
    SendMessage(hTool, TB_AUTOSIZE, 0, 0);

    GetWindowRect(hTool, &rcTool);
    iToolHeight = rcTool.bottom - rcTool.top;

    // Size status bar and get height

    hStatus = GetDlgItem(hwnd, IDC_MAIN_STATUS);
    SendMessage(hStatus, WM_SIZE, 0, 0);

    GetWindowRect(hStatus, &rcStatus);
    iStatusHeight = rcStatus.bottom - rcStatus.top;

    // Calculate remaining height and size edit

    GetClientRect(hwnd, &rcClient);

    iEditHeight = rcClient.bottom - iToolHeight - iStatusHeight;

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

Desafortunadamente esta es una porción de código bastante larga, pero es simple... las barras de herramiemntas se autoposicionarán cuando envíemos el mensaje TB_AUTOSIZE y las barras de estado harán lo mismo cuando enviemos WM_SIZE (las librerías de los controles comunes no entienden nada a cerca de consistencia).


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

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