Capítulo 9 Control básico Button

Los controles button simulan el comportamiento de un pulsador o un interruptor. Pero sólo cuando se comportan como un pulsador los llamaremos botones, cuando emulen interruptores nos referiremos a ellos como checkbox o radiobutton.

Los botones se usan para que el usuario pueda ejecutar ciertas acciones o para dar órdenes a una aplicación. En muchos aspectos, funcionan igual que los menús, y de hecho, ambos generan mensajes de tipo WM_COMMAND.

Se componen normalmente de una pequeña área rectangular con un texto en su interior que identifica la acción que tienen asociada.

En realidad ya hemos usado controles button en todos los ejemplos anteriores, pero los explicaremos ahora con algo más de detalle.

Ficheros de recursos

Empezaremos definiendo el control button en el fichero de recursos, y lo añadiremos a nuestro dialogo de prueba:

#include <windows.h>
#include "win008.h"

Menu MENU
BEGIN
 POPUP "&Principal"
 BEGIN
  MENUITEM "&Diálogo", CM_DIALOGO
 END
END

DialogoPrueba DIALOG 0, 0, 130, 70
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION
CAPTION "Diálogo de prueba"
FONT 8, "Helv"
BEGIN
 CONTROL "Botones:", -1, "static", 
    SS_LEFT | WS_CHILD | WS_VISIBLE, 
    8, 9, 28, 8
 CONTROL "Nuestro botón", ID_BOTON, "BUTTON", 
    BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 
    9, 19, 104, 25
 CONTROL "Aceptar", IDOK, "BUTTON", 
    BS_DEFPUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 
    8, 50, 45, 14
 CONTROL "Cancelar", IDCANCEL, "BUTTON", 
    BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 
    61, 50, 45, 14
END

Hemos añadido un nuevo control button a continuación del control static. Para más detalles acerca de los controles button ver controles button.

Ahora veamos cómo hemos definido nuestro control button, y también los otros dos que hemos usado hasta ahora.:

 CONTROL "Nuestro botón", ID_BOTON, "BUTTON", 
    BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 
    9, 19, 104, 25
 CONTROL "Aceptar", IDOK, "BUTTON", 
    BS_DEFPUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 
    8, 50, 45, 14
  • CONTROL es la palabra clave que indica que vamos a definir un control.
  • A continuación, en el parámetro text, en el caso de los button se trata del texto que aparecerá en su interior.
  • id es el identificador del control. Los controles button necesitan un identificador para que la aplicación pueda acceder a ellos y para usarlos como parámetro en los mensajes WM_COMMAND. Usaremos un identificador definido en win008.h.
  • class es la clase de control, en nuestro caso "BUTTON".
  • style es el estilo de control que queremos. En nuestro caso es una combinación de un estilo button y varios de ventana:
    • BS_PUSHBUTTON: Crea un botón corriente que envía un mensaje WM_COMMAND a su ventana padre cuando el usuario pulsa el botón.
    • BS_DEFPUSHBUTTON: Crea un botón normal que se comporta como uno del estilo BS_PUSHBUTTON, pero también tiene un borde negro y grueso. Si el botón está en un cuadro de diálogo, el usuario puede pulsar este botón usando la tecla ENTER, aún cuando el botón no tenga el foco de entrada. Este estilo es corriente para permitir al usuario seleccionar rápidamente la opción más frecuente, la opción por defecto. Lo usaremos frecuentemente con el botón "Aceptar".
    • BS_CENTER: Centra el texto horizontalmente en el área del botón.
    • WS_CHILD: crea el control como una ventana hija.
    • WS_VISIBLE: crea una ventana inicialmente visible.
    • WS_TABSTOP: define un control que puede recibir el foco del teclado cuando el usuario pulsa la tecla TAB. Presionando la tecla TAB, el usuario mueve el foco del teclado al siguiente control con el estilo WS_TABSTOP.
  • coordenada x del control.
  • coordenada y del control.
  • width: anchura del control.
  • height: altura del control.

Iniciar controles button

Los controles button no se usan para editar o seleccionar información, sólo para que el usuario pueda dar órdenes o indicaciones a la aplicación, así que no requieren inicialización. Lo más que haremos en algunos casos es situar el foco en uno de ellos.

Eso se hace durante el proceso del mensaje WM_INITDIALOG dentro del procedimiento de diálogo.

        case WM_INITDIALOG:
           SetFocus(GetDlgItem(hDlg, ID_BOTON));
           return FALSE;

Tratamiento de acciones de los controles button

Nuestro cuadro de diálogo tiene tres botones. Los de "Aceptar" y "Cancelar" tienen una misión clara: validar o ignorar los datos y cerrar el cuadro de diálogo. En el caso de nuestro botón, queremos que se realice otra operación diferente, por ejemplo, mostrar un mensaje.

        case WM_COMMAND:
           switch(LOWORD(wParam)) {
              case ID_BOTON:
                 MessageBox(hDlg, "Se pulsó 'Nuestro botón'", "Acción", MB_ICONINFORMATION|MB_OK);
                 break;
              case IDOK: 
                 EndDialog(hDlg, FALSE);
                 break;
              case IDCANCEL:
                 EndDialog(hDlg, FALSE);
                 break;
           }
           return TRUE;

Ejemplo 8


  Nombre Fichero Fecha Tamaño Contador Descarga
D Ejemplo 8 win008.zip 2004-01-18 2922 bytes 1201

Comentarios de los usuarios (4)

Martín Villagra
2010-12-15 02:41:38

Dentro del procedimiento de dialogo, creo que sería mejor poner (en el switch del wParam) un caso por default que especifique cerrar el diálogo y quitar los casos IDOK e IDCANCEL.

Quedaría:

case WM_COMMAND:

switch(LOWORD(wParam)) {
     case ID_BOTON:
          MessageBox(hDlg, \"Se pulsó \'Nuestro botón\'\", \"Acción\", MB_ICONINFORMATION|MB_OK);
          break;

     default:
          EndDialog(hDlg, FALSE);
}
Salvador Pozo
2010-12-15 10:42:35

Ten en cuenta que se trata de un ejemplo para demostrar cómo se tratan los mensajes procedentes de pulsaciones de botones.

Generalmente, a cada botón le corresponde una tarea diferente, (normalmente no usaremos botones distintos para hacer lo mismo), de modo que muy raramente encontrarás un default dentro de un tratamiento de WM_COMMAND.

De todos modos, si en este caso quieres minimizar el código, sería preferible usar un if...else, en lugar de un switch.

Una optimización que sí se usa a menudo es esta:

...
    case IDOK:
        // tareas cuando se valida el diálogo
    case IDCANCEL:
        EndDialog(hDlg, FALSE);
        break;
...

Es decir, se omite el break en el caso del botón de aceptar.

david tadeo
2011-03-08 01:38:30

De hecho creo que si haces eso de default, te podrias equivocar por que cualquier otro mensaje que sea pasado por WM_COMMAND cerraria el dialogo inesperadamente, por ejemplo en un listbox si seleccionases una cadena generaria un mensaje WM_COMMAND y se cerraria

david tadeo
2011-03-08 01:39:35

para martin villagra es este comentario