Apunte de Visual C++
Por: Demian Panello
[email protected]
Capítulo IX
Indice rápido del capítulo 9:
Gráficos en Visual C++.
Contexto de dispositivo.
La clase CDC.
Dibujar sobre el escritorio de Windows (uso de las funciones GetDesktopWindow() y GetWindowDC()).
Dibujar un píxel.
Función RGB().
El mensaje WM_DESTROY.
Liberar un contexto.
Dibujar sobre un diálogo.
La clase CClientDC.
GRÁFICOS EN VISUAL C++:
Existe en Windows un concepto denominado Contexto de dispositivo. Un contexto de dispositivo proporciona el medio
sobre el cual se dibujan todos los puntos, líneas, figuras, fuentes y todo lo que se ve. La palabra “dispositivo” se refiere al
lugar donde se dibujará, o sea, la pantalla, impresora, plotter o cualquier otro dispositivo de cualquier fabricante, sin
necesidad de tener un excesivo conocimiento del modelo del mismo.
Algo positivo que ha hecho Microsoft para la industria del software ha sido estandarizar el soporte para todos los
dispositivos en el sistema Windows.
TIPOS DE CONTEXTO DE DISPOSITIVOS:
Existe un contexto de dispositivo estándar global y además hay otros para ocasiones especiales y tareas concretas. Todos
son objetos GDI (interfaz de dispositivo gráfico). El GDI son funciones gráficas de la librería GDI32.DLL y proporcionan el
enlace con los controladores de dispositivos y el propio hardware.
La MFC (Microsoft Foundation Classes) proporciona clases que simplifican la interacción con los GDI. La clase del
contexto de dispositivo global es la CDC. Esta clase proporciona funciones de dibujo, de correspondencia entre coordenadas
y otras para implementar la visualización de gráficos.
Todas las demás clases de contexto de dispositivo, más especializadas, se basan en ésta y la extienden.
La clase CDC:
Para ejemplificar el uso de CDC vamos a crear una aplicación que “pinte” toda la pantalla, para esto entonces, cree un
proyecto MFC basado en diálogos, con el nombre “graf1”.
Reduzca las dimensiones del diálogo un poco y al botón por defecto “Cancelar” cámbiele el ID por IDC_DIBUJAR y
Caption= Dibujar.
Tiene que quedar un diálogo con sólo dos botones: Aceptar y Dibujar.
Pulse dos veces sobre el botón Dibujar para crear el manejador de mensajes OnDibujar() allí escriba:
void CGraf1Dlg::OnDibujar()
{
// TODO: Add your control notification handler code here
CDC* pDC; (1)
CWnd* pEscritorio; (2)
int x, y;
pEscritorio = GetDesktopWindow(); (3)
pDC= pEscritorio>GetWindowDC (); (4)
for(x=0; x<800; x++)
for(y=0; y<600; y++)
pDC>SetPixel (x, y, RGB(x*y,0,0)); (5)
pEscritorio>ReleaseDC (pDC); (6)
}
En la primer línea se declara una variable puntero, pDC, a CDC, por lo general siempre se declara el futuro objeto CDC
como un puntero porque el retorno de la función que los crea es un puntero.
Como se desea utilizar toda la pantalla y no sólo la región ocupada por nuestro diálogo deberemos relacionar el contexto de
dispositivo con el escritorio, cosa que en Windows equivale a toda la pantalla, entonces en la línea (2) se declara un puntero
a la clase CWnd y en (3) se toma el manejador, (puntero CWnd), del escritorio por medio de la función global
GetDesktopWindow().
Una vez que tengo el manejador, que sería la “salida” de mi contexto de dispositivo, creo el objeto CDC en la línea (4) por
medio de la función GetWindowDC() perteneciente a la clase CWnd, que en nuestro caso está apuntando a la “ventana” que
representa el escritorio.
Una vez que uno tiene referenciado el objeto CDC, en nuestro caso por medio del puntero pDC, se pueden acceder a todas
las funciones GDI disponibles haciendo pDC>función, (note que se utiliza el operados > y no el punto ya que la variable
es un puntero).
El dibujo que vamos a hacer será recorrer todo el escritorio dibujando de un color en particular cada píxel, por eso se usan
dos ciclos variar para el ancho y el alto, (mi resolución de video es de 800 x 600, en caso de tener una resolución diferente
hay que cambiar estos valores). En la línea (5) se usa la función GDI SetPixel() cuyos parámetros son los puntos x e y donde
se dibujará el píxel y el otro parámetro es el color del mismo. Para el color usamos la función RGB() donde los parámetros
representan el grado de rojo, verde y azul, entre 0 y 255. La intensidad de verde y azul la dejamos en 0 y el rojo será el
producto de las coordenadas x e y lo que da un efecto interesante llamado tramas moiré.
La última línea libera la referencia al objeto CDC del escritorio, esto es importante hacerlo ya que ocupa memoria.
Antes de ejecutar la aplicación, hay que hacer otra cosa importante, que es “limpiar” la pantalla cuando la aplicación
termine, porque sino todo el escritorio quedará dibujado de forma permanente hasta que se pulse F5 que se encarga en
Windows de redibujar. Entonces utilizaremos el evento, (mensaje), WM_DESTROY que se ejecuta cuando la aplicación
termina, para redibujar el escritorio y dejar todo como antes.
Hay que agregar el mensaje WM_DESTROY, para esto pulse CTRL.+ W para acceder a ClassWizard. Allí en Objects Ids
seleccione CGraf1Dlg y en messages WM_DESTROY, luego pulse Add Function y luego Edit Code, se editará el mensaje
OnDestroy(), allí escriba:
void CGraf1Dlg::OnDestroy()
{
CDialog::OnDestroy();
// TODO: Add your message handler code here
// redibujar todo lo anterior
CWnd* pEscritorio;
pEscritorio=GetDesktopWindow();
RDW_ERASE+RDW_INVALIDATE+RDW_ALLCHILDREN+RDW_ERASENOW);
pEscritorio>RedrawWindow(NULL,NULL,
}
Nuevamente se toma el manejador del escritorio con un puntero CWnd y luego se usa la función RedrawWindow(). Los dos
primer parámetros hacen referencia a la región a redibujar, como en nuestro caso pretendemos redibujar todo el escritorio
estos parámetros serán NULL y el tercer parámetro son combinaciones de constantes que indican como se redibujará,
RDW_ERASE va junto con RDW_INVALIDATE donde está última si el segundo parámetro es NULL, (nuestro caso),
indica que se redibujará todo incluyendo las aplicaciones descendientes tal como lo especifica RDW_ALLCHILDREN.
Pruebe escribiendo este código en el mensaje WM_MOUSEMOVE y obtendrá un prototipo de salva pantalla.
Ahora si ejecute la aplicación y pulse Dibujar, obtendrá el siguiente dibujo en toda la pantalla:
Para cerrar la aplicación tendrá que adivinar donde está el botón Aceptar detrás del dibujo.
En caso de querer usar como objeto de “salida” el diálogo lea el siguiente ejemplo de este capítulo.
Resumiendo:
Las funciones gráficas de Windows forman parte de una librería llamada GDI, a la cual se puede acceder desde
Visual C++ haciendo uso de la clase CDC que es la clase principal para el uso de contextos de dispositivos (pantalla,
impresora, casco de realidad virtual, etc).
Para usar toda la pantalla como lugar donde dibujar, (la pantalla en Windows equivale al escritorio), se debe declarar
un puntero a la clase CDC y otro a la clase CWnd. Entonces con la función GetDesktopWindow() uno puede
almacenar el manejador del escritorio en el puntero CWnd antes declarado y luego tomarlo como dispositivo de
contexto con la función GetWindowDC() del puntero CWnd declarado.
Despues puede hacer uso de muchas funciones de gráficos: SetPixel(), LineTo(), Ellipse(), etc.
Luego se debe liberar la memoria utilizada para el contexto usando la función ReleaseDC() del objeto CWnd
pasandole como parámetro el puntero CDC usado.
No hay que olvidarse de redibujar el escritorio por ejemplo en el evento WN_DESTROY para así tener todo lindo
como antes.
Descargar archivos fuentes del ejemplo: graf1.zip
Dibujar en un diálogo cliente:
En el ejemplo anterior dibujamos sobre el escritorio utilizando la clase principal para definir un contexto de dispositivo,
CDC. Usando esta misma clase también se puede establecer como contexto de dispositivo un diálogo, al cual se le llama
“cliente”. En este caso no haría falta obtener ningún manejador de ventana por medio de una función, pues el puntero a un
diálogo activo ya se encuentra referenciado con la palabra clave this, por lo que sólo haría falta definir el puntero CDC y
obtenerlo desde el cliente:
CDC* pDC;
pDC=this>GetWindowDC();
De esta forma puede uno, luego, usar la función SetPixel() o cualquier otra del puntero pDC y el efecto se producirá en toda
la ventana del diálogo, incluyendo la barra donde está el título de la ventana y los botones de cerrar, maximizar y minimizar,
(para que el dibujo se realice sólo dentro del diálogo; en lugar de GetWindowDC() habría que utilizar GetDC()).
Bien, VC++ nos da otra posibilidad más de hacer lo mismo usando una clase descendiente de CDC que se llama CClientDC
y se dedica pura y exclusivamente a definir como DC el diálogo cliente (sin incluir la barra de título).
Para probar esto con un ejemplo cree un proyecto MFC basado en diálogo con el nombre “graf2” y realice los cambios en el
diálogo de manera tal que quede exactamente igual que el del ejemplo anterior, o sea con un botón Aceptar y el otro Dibujar,
con ID=IDC_DIBUJAR.
Pulse dos veces el botón dibujar para generar el evento OnDibujar(), allí escriba:
void CGraf2Dlg::OnDibujar()
{
// TODO: Add your control notification handler code here
//Se construye un DC cliente a partir de la ventana de diálogo
CClientDC dlgDC(this); (1)
int x,y;
for (x=0; x<=200; x++)
for(y=0; y<=200; y++)
Comentarios de: Apunte de VC++ (0)
No hay comentarios