Capítulo 41 Control Button avanzado

En nuestra primera aproximación a los controles button los dividimos en cuatro categorías: botones de pulsar (push buttons), botones de grupo, check boxes y radio buttons.

En este capítulo veremos algunos detalles que no vimos en esos capítulos, pero esta vez agrupando todas estas categorías en una sola, ya que todas ellas son en realidad botones de diferentes estilos.

Insertar botones durante la ejecución

Al igual que vimos con los controles edit y list box, también es posible insertar controles button durante la ejecución. En el caso del control button tendremos que insertar una ventana de la clase "BUTTON". Para insertar el control también usaremos las funciones CreateWindow y CreateWindowEx.

   HWND hctrl;
...
   hctrl = CreateWindowEx(
      0,
      "BUTTON",        /* Nombre de la clase */
      "Botón 1",       /* Texto del título */
      BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, /* Estilo */
      9, 19,           /* Posición */
      95, 24,          /* Tamaño */
      hwnd,            /* Ventana padre */
      (HMENU)ID_BOTON, /* Identificador del control */
      hInstance,       /* Instancia */
      NULL);           /* Sin datos de creación de ventana */ 
   SetFocus(hctrl);

A diferencia de los controles que hemos visto antes, en el caso de los botones el texto del título sí tiene uso, ya que será ese texto el que aparezca en el botón, radio button, check box o group box.

El identificador del control se suministra a través del parámetro hMenu, por lo que será necesario hacer un casting de ese valor a HMENU.

Ahora será nuestro procedimiento de ventana, si el control fue insertado en una ventana, o el procedimiento de diálogo, si se trata de un diálogo, el encargado de procesar los mensajes procedentes del control.

Cambiar fuente

También es posible modificar la fuente de un control button enviando un mensaje WM_SETFONT. El lugar apropiado es, por supuesto, al procesar el mensaje WM_INITDIALOG al iniciiar un cuadro de diálogo, o al procesar el mensaje WM_CREATE, al iniciar una ventana.

En el parámetro wParam pasamos un manipulador de fuente, y usaremos la macro MAKELPARAM para crear un valor LPARAM, en el que especificaremos la opción de repintar el control, que se almacena en la palabra de menor peso de LPARAM.

Esto nos permite modificar la fuente durante la ejecución, reflejando los cambios en pantalla.

   static HFONT hfont;
...
   hfont = (HFONT)GetStockObject( DEFAULT_GUI_FONT );
   SendMessage(hctrl, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0));

Cambiar colores

Análogamente a lo que hemos visto con otros controles, también existe un mensaje que nos permite modificar el color de los controles de tipo botón.

Se trata del mensaje WM_CTLCOLORBTN, que se envía a la ventana propietaria del control cuando debe ser dibujado.

En el parámetro wParam recibiremos un manipulador de contexto de dispositivo del control, y en el parámetro lParam el manipulador ventana del control. Podemos cambiar el color de fondo y el del texto, y cuando se procese este mensaje, y deberemos retornar un manipulador de pincel, que se usará para pintar el fondo:

   static HBRUSH pincel;
...
      case WM_CREATE:
        pincel = CreateSolidBrush(RGB(0,255,0));
        ...
      case WM_CTLCOLORBTN:
        SetTextColor((HDC)wParam, RGB(0,0,255));
        SetBkColor((HDC)wParam, RGB(0,255,0));
        return (LRESULT)pincel;
      case WM_DESTROY:
        DeleteObject(pincel);
        ...

Lo que pasa es que, en la mayor parte de los controles botón, los colores están predefinidos por el sistema, y nuestros cambios al procesar este mensaje no influyen en el aspecto final de los controles.

La excepción son los controles botón del estilo owner-draw, sólo en este tipo de botones puede ser útil procesar este mensaje.

Modificar el bucle de mensajes

Al insertar controles botón en la ventana principal, en lugar de hacerlo en un cuadro de diálogo, hay determinadas funcionalidades, relacionadas con el teclado, que no funcionan de forma similar.

Por ejemplo, para hacer que funcione la tecla de tabulación de modo que cambie el foco entre los distintos controles o para que las teclas como el espacio o el ENTER activen los botones, y para que funcionen las teclas del cursor, hay que modificar el bucle de mensajes de modo que ciertos mensajes, aquellos propios de los cuadros de diálogo, se procesen de forma diferente.

Esto se hace añadiendo la función IsDialogMessage. Esta función averigua si un mensaje es de diálogo, y en ese caso lo procesa. Estos mensaje no deben ser procesados por el bucle habitual:

    /* Bucle de mensajes, se ejecuta hasta que haya error o GetMessage devuelva FALSE 
       Modificado para procesar ciertas teclas de forma automática. */
    while(TRUE == GetMessage(&mensaje, NULL, 0, 0)) {
       if(!IsDialogMessage(hwnd, &mensaje) ) {
        /* Traducir mensajes de teclas virtuales a mensajes de caracteres */
        TranslateMessage(&mensaje);
        /* Enviar mensaje al procedimiento de ventana */
        DispatchMessage(&mensaje);
        }
    }