Funciones para controles botón

Como en el resto de los controles, los mensajes se pueden envíar mediante dos funciones distintas.

Por una parte, el la función SendMessage nos permite enviar un mensaje a una ventana o control, disponiendo de su manipulador de ventana:

   SendMessage(hctrl, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0));

Si no disponemos de tal manipulador existen otras opciones. Por ejemplo, podemos obtener un manipulador de ventana o control, a partir del identificador, mediante la función GetDlgItem. Combinando estas dos funciones, podemos enviar un mensaje a un control, aunque no dispongamos de un manipulador de ventana:

   SendMessage(GetDlgItem(hwnd, ID_BOTON1), WM_SETFONT, 
      (WPARAM)hfont, MAKELPARAM(TRUE, 0));

Sin embargo, existe una función que combina las acciones de estas dos, se trata de SendDlgItemMessage:

   SendDlgItemMessage(hwnd, ID_BOTON1, WM_SETFONT, 
      (WPARAM)hfont, MAKELPARAM(TRUE, 0));

A pesar de que aparezca la abreviatura "Dlg" como parte de estas dos últimas funciones, ambas funcionan tanto en cuadros de diálogo como en ventanas normales. Es decir, podemos usar estas dos funciones para enviar mensajes a controles insertados en ventanas corrientes.

Funciones propias de controles botón

Otras funciones, que ya vimos previamente en los capítulos 14 y 15, son específicas para controles botón de los tipos check box y radio button.

Aunque estas funciones tienen sus equivalentes en mensajes, a menudo nos serán útiles en nuestros programas.

La función CheckDlgButton, nos permite cambiar el estado de marcado de un control botón del tipo check box o radio button, en realidad equivale a enviar un mensaje BM_SETCHECK.

La función CheckRadioButton es más útil, ya que trabaja con grupos de radio buttons. Dentro de un grupo de radio buttons sólo uno de ellos puede estar marcado en un momento dado. Usar esta función nos permite marcar uno de los controles, y eliminar la marca del que la tenía previamente, en una única operación.

La función IsDlgButtonChecked nos permite conocer el estado de marcado de un control botón. Es equivalente a enviar un mensaje BM_GETCHECK al control.

Modificar el estilo de un botón

Es posible modificar el estilo de un botón durante la ejecución. Para ello se usa el mensaje BM_SETSTYLE, indicando en el parámetro wParam el nuevo estilo del botón y en lParam si se debe o no redibujar el control, un valor TRUE en la palabra de menor peso indica que se debe redibujar, un valor FALSE, que no:

   SendDlgItemMessage(hwnd, ID_BOTON, BM_SETSTYLE, 
      BS_PUSHBUTTON | BS_LEFTTEXT | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 
      MAKELPARAM(TRUE,0));

Botones owner-draw

Ya lo hemos mencionado antes: los controles botón también disponen de un estilo owner-draw.

Un control botón con el estilo owner-draw, BS_OWNERDRAW no tiene un comportamiento definido, ni un aspecto gráfico concreto. Será el procedimiento de ventana o diálogo de la ventana propietaria del control el encargado de actualizar el aspecto en pantalla y también de definir las respuestas a cada evento de teclado o ratón.

De modo que un botón owner-draw puede ser un botón pulsable, un radio button, un check box o cualquier otra cosa que inventemos.

Lo primero es crear el control con el estilo BS_OWNERDRAW:

   HWND hctrl;
...
   hctrl = CreateWindowEx(
      0,
      "BUTTON",        /* Nombre de la clase */
      "Botón 2",       /* Texto del título */
      BS_OWNERDRAW | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, /* Estilo */
      9, 49,           /* 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 */

Cuando existen botones con el estilo owner-draw, la ventana padre del control recibirá un mensaje WM_DRAWITEM cada vez que el control deba ser redibujado. Este mensaje se recibe para todos los controles owner-draw existentes, de modo que deberemos distinguir a qué control en concreto se refiere el mensaje. Esta es la parte sencilla, ya que en el parámetro wParam de este mensaje recibiremos el identificador del control.

Por otra parte, en el parámetro lParam, recibiremos un puntero a una estructura DRAWITEMSTRUCT, que nos proporciona información sobre todos los detalles necesarios para decidir el modo en que debemos dibujar el control.

Por una parte, el campo CtlType contendrá el valor ODT_BUTTON, indicando que el control es un botón. El campo CtlID contiene el identificador del control. El campo itemID no tiene ninguna información en el caso de un control botón. El campo itemAction contiene un valor que especifica el tipo de acción de dibujo requerido. Puede ser ODA_DRAWENTIRE, si se necesita actualizar el control completo, ODA_FOCUS si el único cambio es la pérdida o recuperación del foco o ODA_SELECT, si ha cambiado el estado de selección.

El campo itemState especifica el estado del control. En el caso de los botones, el valor de este campo puede ser una combinación de: ODS_DISABLED, si el control está deshabilitado, ODS_FOCUS, si el control tiene el foco o ODS_SELECTED, si el control está seleccionado.

El campo hwndItem contiene el manipulador de ventana, hDC contiene el manipulador de contexto de dispositivo del control. El campo rcItem contiene el rectángulo que define los límites de la zona a dibujar. E itemData no contiene nada válido en el caso de los controles botón.

Este ejemplo visualiza un control botón con forma elíptica, y cambia el color del fondo a naranja cuando está pulsado. Si se deshabilita, se muestra una cruz:

   LPDRAWITEMSTRUCT lpdis;
   HBRUSH pincel, pincel2;
...
   case WM_DRAWITEM:
      lpdis = (LPDRAWITEMSTRUCT)lParam;
      GetClientRect(lpdis->hwndItem, &re);
      SetBkMode(lpdis->hDC, TRANSPARENT);
      pincel = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
      pincel2 = CreateSolidBrush(RGB(240,120,0));
      FillRect(lpdis->hDC, &re, pincel);
      if(wParam == ID_BOTON2) {
         if(lpdis->itemState & ODS_SELECTED) {
            SelectObject(lpdis->hDC, (HBRUSH)GetStockObject(GRAY_BRUSH));
            SelectObject(lpdis->hDC, (HPEN)GetStockObject(WHITE_PEN));
            Ellipse(lpdis->hDC, re.left, re.top, re.right, re.bottom);
            TextOut(lpdis->hDC, re.left+14, re.top+4, "Botón 2", 7);
         } else if(lpdis->itemState & ODS_DISABLED) {
            MoveToEx(lpdis->hDC, 0, 0, NULL);
            LineTo(lpdis->hDC, re.right, re.bottom);
            MoveToEx(lpdis->hDC, 0, re.bottom, NULL);
            LineTo(lpdis->hDC, re.right, 0);
         } else {
            SelectObject(lpdis->hDC, pincel2);
            SelectObject(lpdis->hDC, (HPEN)GetStockObject(WHITE_PEN));
            Ellipse(lpdis->hDC, re.left, re.top, re.right, re.bottom);
            TextOut(lpdis->hDC, re.left+12, re.top+2, "Botón 2", 7);
         }
      }
      DeleteObject(pincel);
      DeleteObject(pincel2);
      return 0;

Ejemplo 69


  Nombre Fichero Fecha Tamaño Contador Descarga
D Ejemplo 69 win069.zip 2007-03-15 9132 bytes 280