Introducción a la Programación en Windows
Por: Demian C. Panello demianpanello@yahoo.com.ar
Capítulo II
Indice rápido del capítulo 2:
Cuando se inicia una aplicación, uno de los mensajes que envía Windows es WM_PAINT el cual se encarga de dibujar la ventana. También se envía este mensaje cuando por ejemplo se coloca una ventana sobre otra y luego se descubre una región.
En este capítulo se verá un ejemplo que muestra un texto en la ventana. Para esto se necesitará crear una ventana y escribir en el mensaje WM_PAINT las sentencias necesarias para "dibujar" el texto "Hola Visual C++".
En Windows existe un concepto que es el de "Contexto de dispositivo", (DC). Este concepto nos permite direccionar nuestras "salidas" a diferentes "dispositivos", (una ventana, el escritorio de Windows, un impresora, un plotter, etc).
Nosotros dibujaremos sobre una ventana, entonces nuestro Contexto de dispositivo será esa ventana.
Para comenzar, debe crear un proyecto Win32, así que vaya al menú FILE - NEW, luego en PROJECTS elija la opción WIN32 Aplication y como Project Name escriba "win2", luego pulse OK y en la siguiente ventana FINISH, (verifique antes que esté marcada la opción An empty project).
Tendremos entones un proyecto en blanco, hay que agregar ahora un archivo .cpp para escribir el código. Nuevamente vaya a FILE NEW y en la solapa FILES seleccione C++ Source File y como File Name escriba "win2", (la extensión la pone sola el IDE), pulse OK.
Escriba las siguientes líneas en win2.cpp, (es muy similar al ejemplo del capítulo 1, con una función más. Las líneas con marcador amarillo son las agregadas para este ejemplo).
//Creación de una ventana sencilla en la cual
se
//dibuja un texto
//Autor: Demian Panello.
#include <windows.h>
#define NOMBRE_CLASE "Ventana1" //Nombre de la clase ventana a crear
#define TITULO "Primer Ventana" //El título que mostrará la ventana
//Prototipos de funciones.
static BOOL Inicializa(HINSTANCE hInstance, int nShowCmd);
long FAR PASCAL WindowProc(HWND hwnd, UINT message, WPARAM
wParam, LPARAM lParam);
void
MuestraTexto(HWND hwnd); (1)
HWND hwnd; //Variable HWND, (window handler), global que será
el manejador de la ventana.
//Función principal.
int PASCAL WinMain(HINSTANCE hInstance,HINSTANCE
hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
MSG msg; //Variable para los mensajes.
//Si no se puede crear la ventana retorno FALSE
if (!Inicializa(hInstance, nShowCmd))
return FALSE;
//Bucle de mensajes.
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
//Esta función se encarga de definir los atributos, (propiedades)
de la ventana y además la muestra
static BOOL Inicializa(HINSTANCE hInstance, int nShowCmd)
{
//Variable para registrar la ventana.
WNDCLASS wc;
//Propiedades de la ventana.
wc.style = CS_HREDRAW|CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.cbClsExtra =0;
wc.cbWndExtra =0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL,IDC_ARROW);
wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE+1);
wc.lpszMenuName = NULL;
wc.lpszClassName =NOMBRE_CLASE; //Nombre de la clase
RegisterClass(&wc);
//Se crea la ventana de clase "Ventana1"
hwnd=CreateWindowEx(WS_EX_APPWINDOW,NOMBRE_CLASE, TITULO,
WS_TILEDWINDOW,CW_USEDEFAULT,0,
CW_USEDEFAULT,0, NULL,NULL,hInstance,NULL);
if
(!hwnd) //Si no se pudo crear, retorno FALSE
return FALSE;
ShowWindow(hwnd,nShowCmd); //Muestro la ventana
UpdateWindow(hwnd);
//Se dibuja la ventana,(mensaje WM_PAINT)
return TRUE;
}
//Esta función es la encargada de procesar los mensajes que van
llegando.
long FAR PASCAL WindowProc(HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
//Verifico que mensaje llegó(estos son sólo algunos mensajes)
switch(message)
{
case WM_ACTIVATEAPP: //Se activó la aplicación
break;
case
WM_CREATE:
//Se creó la ventana
break;
case
WM_KEYDOWN: //Se pulsó una tecla
break;
case
WM_PAINT:
//Cuando es necesario dibujar la ventana
MuestraTexto(hwnd); (2)
break;
case
WM_DESTROY: //Al
destruirse la ventana invoco la salida
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd,message,wParam,lParam);
}
//Función encargada de mostrar el texto.
void MuestraTexto(HWND hwnd) (3)
{
HDC
miDC;
//Variable para capturar el Contexto de dispositivo.
PAINTSTRUCT ps; //Variable
para almacenar la región a re-dibujar.
RECT
miRect;
//Variable para guardar las dimensiones de la ventana.
LPCTSTR Texto; //Variable para texto.
GetClientRect(hwnd,&miRect);
//Se obtiene las dimensiones de la ventana
miDC=GetDC(hwnd); //Se obtiene el Contexto de Dispositivo
miDC=BeginPaint(hwnd,&ps);
//Se inicia la "sesión" para dibujar
Texto="Hola Visual C++";
SetTextColor(miDC,
RGB(255,0,0));
//Se establece un color para el texto
DrawText(miDC,Texto,-1,&miRect,DT_CENTER);
//Se muestra el texto
EndPaint(hwnd,&ps);
//Se finaliza la "sesión" para dibujar
}
Bueno, el ejemplo es muy similar al anterior, en cuanto que en este también se crea una ventana, pero la diferencia consiste en que ahora no nos interesan los mensajes para los botones del mouse, sino que escribimos código para WM_PAINT, la llamada a una función nuestra (2), MuestraTexto(HWND hwnd), cuyo prototipo se especificó en (1).
La función MuestraTexto() recibe como parámetro el manejador de la ventana que acabamos de crear, si presta atención se dará cuenta que no hace falta pasarle dicho parámetro a la función, pues es una variable declarada como global y la función tranquilamente "la ve". No obstante, para el mejor entendimiento de un programa se suelen permitir estas redundancias.
En la función primero se definen cuatro variables:
HDC miDC;
PAINTSTRUCT ps;
RECT miRect;
LPCTSTR Texto;
- La variable miDC es de tipo HDC y nos servirá para obtener el Contexto de dispositivo, que en este caso será hwnd, (nuestra ventana).
- El mensaje WM_PAINT gestiona el tema de re-dibujar las regiones de una ventana en caso de que éstas queden en algún momento ocultas por otra ventana. Por esto se necesitará un variable de tipo PAINTSTRUCT que entre otros campos hay uno que contiene las coordenadas de la región en particular. La definición de PAINTSTRUCT es:
typedef struct tagPAINTSTRUCT {
HDC hdc;
BOOL fErase;
RECT rcPaint;
BOOL fRestore;
BOOL fIncUpdate;
BYTE rgbReserved[32];
} PAINTSTRUCT;
Precisamente
el campo rcPaint es el que almacenará las coordenadas de la región. Para más
información sobre esta estructura ver la ayuda.
-
La función encargada de mostrar un texto necesita saber dónde mostrarlo, en que región,
es por esto que se declara una variable de tipo RECT que luego se completará con las
coordenadas de la ventana.
Con la función GetClientRect() se obtienen las dimensiones de la
ventana las cuales se guardan en la variable de tipo RECT miRect.
Con
GetDC() se especifica cual será el contexto de dispositivo, en este caso la ventana,
(hwnd), y su referencia será la variable miDC.
Se da inicio con BeginPaint() el proceso de dibujar una región. Los parámetros son el manejado de la ventana donde se encuentra la región a dibujar y la variable de tipo PAINTSTRUCT para que BeginPaint() la "rellene" con valores, uno de ellos las dimensiones de la región.
Después se especifica cual será el texto a mostrar y con SetColor() se le establece un color usando la función RGB().
Finalmente es la función DrawText() será la encargada de mostrar el texto:
DrawText(miDC,Texto,-1,&miRect,DT_CENTER);
Los parámetros son: la variable de tipo HDC, el texto, cantidad de caracteres del texto a dibujar, (este parámetro es -1 si el texto es un puntero a una cadena terminada en nulo, el tipo LPCTSTR define precisamente eso), una variable de tipo RECT con las coordenadas donde se situará el texto y una constante que indica la alineación del texto con respecto a la región dada por la variable de tipo RECT).
Se finaliza WM_PAINT con EndPaint(), cuyos parámetros son los mismos que BeginPaint().
Debería obtener la siguiente salida:

En el siguiente capítulo se verá como generar un botón. Auf wiedersehen!.