Mensajes de notificación

La clase Button dispone de muchos mensajes de notificación, pero la mayor parte de ellos se mantienen sólo por compatibilidad con versiones de Windows de 16 bits, y no deben usarse en aplicaciones de 32 bits, por lo que no los veremos con detalle.

Nota: Los mensajes de notificación obsoletos son: BN_DBLCLK, BN_DISABLE, BN_DOUBLECLICKED, BN_HILITE, BN_PAINT, BN_PUSHED, BN_UNHILITE y BN_UNPUSHED. En lugar de usar estos mensajes, las aplicaciones de 32 bits deben usar un control botón con un estilo owner-draw, y la estructura DRAWITEMSTRUCT.

Nos limitaremos a explicar, por lo tanto, sólo tres mensajes de notificación.

Como en todos los casos, los mensajes de notificación se envían a la ventana padre mediante un mensaje WM_COMMAND.

Selección

Cada vez que el usuario hace clic sobre un botón, se envía un mensaje de notificación BN_CLICKED a la ventana propietaria del botón.

Doble clic

Cuando el usuario hace un doble clic sobre un botón se envía un mensaje de notificación BN_DBLCLK. El botón debe tener el estilo BS_OWNERDRAW o BS_RADIOBUTTON.

Pérdida y recuperación de foco

Cuando un control pierde el foco del teclado, se envía un mensaje de notificación BN_KILLFOCUS a la ventana propietaria. Análogamente, cuando un control botón recupera el foco del teclado, se envía un mensaje BN_SETFOCUS a la ventana propietaria.

Inhibir mensajes de notificación

Si definimos un botón sin el estilo BS_NOTIFY, los mensajes BN_DISABLE, BN_PUSHED, BN_KILLFOCUS, BN_PAINT, BN_SETFOCUS y BN_UNPUSHED no se enviarán a la ventana padre del control.

Esto significa que deberemos ser cuidadosos cuando procesemos los mensajes WM_COMMAND procedentes de un botón con el estilo BS_NOTIFY, ya que no todos los mensajes WM_COMMAND que recivamos serán pulsaciones de botón, y por lo tanto no nos servirá el método usado en el capítulo 9, en el que no se verificaba el valor del parámetro wParam.

Por contra, un botón pulsable sin el estilo BS_NOTIFY sólo puede enviar mensajes de notificación BN_CLICKED, de modo que no tiene sentido verificar el valor de la palabra de mayor peso del parámetro wParam.

Tanto si se usa el estilo BS_NOTIFY, como si no, los mensajes BN_CLICKED y BN_DBLCLK siempre se envían.

Estilos de cada tipo de botón

Ya hemos mencionado que los botones pulsables, los check boxes, los radio buttons y las cajas de grupos no son más que controles botón con diferentes estilos. Veamos ahora qué estilos puede tener cada uno de los controles:

Botones pulsables

Botón pulsable

Estos botones se pueden definir usando los estilos BS_PUSHBUTTOM y BS_DEFPUSHBUTTON. En el segundo caso, el botón será el botón por defecto, y se activará cuando el usuario pulse la tecla de ENTER.

Check boxes

Check boxes

Los estilos BS_CHECKBOX, BS_AUTOCHECKBOX, BS_3STATE y BS_AUTO3STATE defiene botónes check box de dos estados (los dos primeros) o de tres estados (los dos últimos). Los estilos AUTO, además, se procesarán automáticamente por el sistema.

Añadir que el estilo BS_PUSHLIKE permite definir un check box con la misma apariencia que un botón pulsable.

Radio buttons

Radio buttons

Para definir este tipo de botones disponemos de los estilos BS_RADIOBUTTON y BS_AUTORADIOBUTTON. El segundo define radio buttons automáticos.

En este caso, el estilo BS_PUSHLIKE también permite definir un radio buttons con la misma apariencia que un botón pulsable.

Cajas de grupo

Botón de grupo

El estilo BS_GROUPBOX permite definir cajas de grupo.

Todos estos controles, menos los group boxes, envián mensajes WM_COMMAND cuando son pulsados, y mensajes de notificación BN_CLICKED.

Botones owner-draw

Existe un quinto tipo de botón, el owner-draw, que se define con el estilo BS_OWNERDRAW. El comportamiento de estos botones depende de nosotros, ya que estaremos obligados a diseñarlos y pintarlos dependiendo de su estado.

Estados de un botón

Un botón puede tener tres niveles de estado diferentes.

Por una parte, puede tener o no el foco del teclado. Esto se indica, generalmente, mediante un rectángulo de líneas punteadas alrededor del texto.

Puede estar o no resaltado. El resaltado se produce cuando el usuario coloca el ratón sobre el botón y pulsa, y mantiene, el botón izquiedo del ratón. O también si el control tiene le foco y se pulsa la tecla [Espacio].

Por último, en el caso de check boxes y radio buttons, el botón puede o no estar marcado (checked).

Selección de un botón

En los botones que usaremos normalmente, tanto el estado del control como su aspecto gráfico se actualizarán de forma automática por el sistema. Esto se aplica a botones pulsables, que cambiarán de aspecto cuando se pulsen y se suelten y también a los check boxes y radio buttons automáticos, que mostrarán el estado de marcado de forma automática.

En los radio buttons y check boxes no automáticos, el estado de marcado dependerá de nuestra aplicación. Esto nos permite crear condiciones más elaboradas para el cambio de estado que las simples pulsaciones.

Por último, en los botones owner draw, tanto el cambio de estado como la actualización de la representación dependerán de nuestra aplicación. Esto nos dará mucho más trabajo, pero a cambio proporciona una total libertad en cuanto al comportamiento y aspecto de los botones.

Cambios de estado

Para determinar el estado de un botón se usan los mensajes BM_GETCHECK y BM_GETSTATE.

El mensaje BM_GETCHECK puede devolver los valores BST_CHECKED, BST_INDETERMINATE o BST_UNCHECKED, de modo que podemos determinar el estado de marcado de un botón check box o radio button. El valor BST_INDETERMINATE sólo es válido para botones con el estilo BS_3STATE o BS_AUTO3STATE.

El mensaje BM_GETSTATE es algo más completo, ya que puede devolver los valores BST_FOCUS y BST_PUSHED, además de los tres que devuelve BM_GETCHECK.

Podemos usar la máscara 0x0003, o mejor aún, la suma de los valores BST_CHECKED y BST_INDETERMINATE, para extraer sólo los valores de la marca de chequeo. Aunque esto es redundante, ya que podemos usar en su lugar el mensaje BM_GETCHECK.

El valor BST_FOCUS indica si el botón tiene el foco del teclado, y el valor BST_PUSHED si el botón está pulsado.

   if(SendDlgItemMessage(hwnd, ID_BOTON2, BM_GETSTATE, 0, 0) == BST_CHECKED)
      MessageBox(hwnd, "Botón 2 marcado", "Marca", MB_OK);
   else
      MessageBox(hwnd, "Botón 2 no marcado", "Marca", MB_OK);

De forma simétrica, podemos usar los mensaje BM_SETCHECK o BM_SETSTATE para modificar el estado de un botón.

BM_SETCHECK nos permite modificar el estado de marcado de un botón del tipo Check Box o Radio Button, usando uno de los valores BST_CHECKED, BST_INDETERMINATE o BST_UNCHECKED, en el parámetro wParam.

El mensaje BM_SETSTATE permite modificar el estado del resaltado de un botón. Para ello se usa el parámetro wParam. Un valor TRUE resalta el botón, y un valor FALSE elimina el resalte. Estos estados no afectan más que a la apariencia del botón. El estado resaltado corresponde a cuando el usuario pulsa y maniene pulsado un botón.

   SendDlgItemMessage(hwnd, ID_BOTON2, BM_SETSTATE, TRUE, 0);
   SendDlgItemMessage(hwnd, ID_BOTON2, BM_SETCHECK, BST_UNCHECKED, 0);