Haciendo botones en C++ con Winapi
En la lección anterior a la que puede acceder desde el enlace ubicado debajo de este artículo, ya estuvimos hablando de cómo crear una ventana en C++, para esto estamos utilizando la librería grafica Winapi por ser la más versátil que existe al ser la oficial de Windows y en la cual se basan muchas de las otras librerías.
En esta lección les mostrare como crear botones, asunto que por cierto es mucho más sencillo que crear la más sencilla de las ventanas en Winapi (por extraño que parezca), pero también estaremos modificando dichos botones con lo cual el código se irá haciendo cada vez más complejo, primero hagamos (nuevamente) una ventana básica para ya luego añadirle algún botón.
Código para la ventana básica en C++
#define _WIN32_WINNT 0x0500 // Es necesaria esta definición para esconder ventana de consola
#include <windows.h> // Librería que contiene las funciones de Winapi
/* Declaracion del procedimiento de windows */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
/* Declaramos una variable de tipo char para guardar el nombre de nuestra aplicación */
char NombreClase[] = "Estilos";
HWND ventana1; /* Manejador de la ventana*/
MSG mensajecomunica; /* Mensajes internos que se envían a la aplicación */
WNDCLASSEX estilo1; /* Nombre de la clase para los estilos de ventana */
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nCmdShow)
{
/* Creamos la estructura de la ventana indicando varias características */
estilo1.hInstance = hThisInstance;
estilo1.lpszClassName = NombreClase;
estilo1.lpfnWndProc = WindowProcedure;
estilo1.style = CS_DBLCLKS;
estilo1.cbSize = sizeof (WNDCLASSEX);
estilo1.hIcon = LoadIcon (NULL, IDI_QUESTION);
estilo1.hIconSm = LoadIcon (NULL, IDI_INFORMATION);
estilo1.hCursor = LoadCursor (NULL, IDC_ARROW);
estilo1.lpszMenuName = NULL; /* Sin Menu */
estilo1.cbClsExtra = 0;
estilo1.cbWndExtra = 0;
estilo1.hbrBackground = (HBRUSH) COLOR_WINDOW; /* Color del fondo de ventana */
/* Registramos la clase de la ventana */
if (!RegisterClassEx (&estilo1))
return 0;
/* Ahora creamos la ventana a partir de la clase anterior */
ventana1 = CreateWindowEx (
0,
NombreClase, /* Nombre de la clase */
("Ventana Codigazo"), /* Titulo de la ventana */
WS_OVERLAPPEDWINDOW|WS_BORDER, /* Ventana por defecto */
400, /* Posicion de la ventana en el eje X (de izquierda a derecha) */
70, /* Posicion de la ventana, eje Y (arriba abajo) */
644, /* Ancho de la ventana */
575, /* Alto de la ventana */
HWND_DESKTOP,
NULL, /* Sin menu */
hThisInstance,
NULL
);
/* Hacemos que la ventana sea visible */
ShowWindow (ventana1, nCmdShow);
ShowWindow(GetConsoleWindow(), SW_HIDE ); // Función para esconder la ventana de consola
/* Hacemos que la ventana se ejecute hasta que se obtenga resturn 0 */
while (GetMessage (&mensajecomunica, NULL, 0, 0))
{
/* Traduce mensajes virtual-key */
TranslateMessage(&mensajecomunica);
/* Envia mensajes a WindowProcedure */
DispatchMessage(&mensajecomunica);
}
return mensajecomunica.wParam;
}
LRESULT CALLBACK WindowProcedure (HWND ventana1, UINT mensajecomunica, WPARAM wParam, LPARAM lParam)
{
switch (mensajecomunica) /* Manejamos los mensajes */
{
case WM_CLOSE: /* Que hacer en caso de recibir el mensaje WM_CLOSE*/
DestroyWindow(ventana1); /* Destruir la ventana */
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default: /* Tratamiento por defecto para mensajes que no especificamos */
return DefWindowProc (ventana1, mensajecomunica, wParam, lParam);
}
return 0;
}
Recuerde que estos códigos no dependen de su IDE, pueden ser ejecutados en Dev-C++, Codeblocks, Visual studio y cualquier otro IDE para C++. Pasemos ahora a crear el primer botón, para cada botón necesitamos registrar una variable que viene a ser el identificador de nuestro botón, estas variables son de tipo HWND, y significa handler window.
HWND boton1; // Coloque esta variable debajo de la variable HWND ventana1.
También colocaremos un identificador para el menú al que pertenecerá nuestro botón, este identificador es necesario para detectar eventos dentro de nuestro botón, nada más tenemos que colocar debajo de "#include <windows.h>" el codigo "#define ID1 100" todo identificador se le añade un número, se recomienda que sea mayor a 100 para que no exista conflicto entre identificadores del sistema.
ahora vamos a crear debajo del "break;" del caso "WM_DESTROY:" ubicado dentro del mensajecomunica, un nuevo caso, este va a ser:
case WM_CREATE:
break;
Luego podemos crear el botón con ayuda de la funcion CreateWindowEx, colocando en el segundo parámetro "button", este botón va debajo de "WM_CREATE:" y antes del "break;" veamos un ejemplo.
boton1 = CreateWindowEx(0, "button", ("Texto"), WS_VISIBLE | WS_CHILD | 0x00000001, 10, 10, 80, 25, ventana1, (HMENU)ID1, GetModuleHandle(NULL), 0);
Le recomiendo que pruebe cambiando algunos de estos parámetros, principalmente con los números 110,40,80 y 25, de esta forma entenderá para que sirve cada uno de ellos, los otros parámetros no los cambie porque en su mayoría han de quedarse como están para funcionar.
Detectar clic en botón Winapi
Para manejar los clics que el usuario da sobre el botón se necesita crear otro case, quizá ya se va dando cuenta que todo tipo de actividad dentro de Winapi se maneja por cases, este case lo podemos crear debajo del anterior y se llamará:
case WM_COMMAND:
break;
El caso anterior lo que hace es detectar varios tipos de comandos que se envían a la ventana y los clics son precisamente un comando, este WM_COMMAND no pertenece al botón como en otros lenguajes, sino que pertenece y es manejado por la ventana, ahora tenemos que detectar en cual botón se ha realizado esta acción, esto con ayuda del identificador ID1, para eso lo habíamos creado, para probar botones es practico crear un MessageBox(esas ventanitas de alerta que tienen un botón de Aceptar, todo esto lo hacemos colocando dentro de WM_COMMAND lo que sigue a continuación.
if (LOWORD(wParam) == ID1){
MessageBox(NULL, "Este es un mensaje de prueba, modifíquelo.", "¡Alerta Codigazo!", MB_OKCANCEL | MB_DEFBUTTON2);
}
Hay mucho más que hacer con los botones, pero por ahora con esto es suficiente para que practiquen y así evitar que el código les parezca muy pesado o difícil.
Nota 1: Para cada botón nuevo tendrá que crear una nueva variable, y un nuevo identificador, luego crear el botón siempre debajo del caso "WM_CREATE:" este caso permite que se cree el botón en el momento que se está creando la ventana.
Nota 2: El botón se puede crear tambien con "CreateWindow" pero "CreateWindowEx" es la versión actualizada que incluye un par de opciones extra de hecho "Ex" pertenece a "Extendended" que significa extendido.