Apunte de Visual C++
Por: Demian Panello demianpanello@yahoo.com.ar
Capítulo VII
Indice rápido del capítulo 7:
Seguramente necesitará en alguna ocasión saber cuándo se ha pulsado o soltado un botón del mouse y dónde se ha pulsado.
Windows maneja tres botones del mouse: los botones izquierdo, central y derecho. Para cada botón el programa recibirá dos sucesos: uno para el momento en que el usuario pulsa el botón y otro para el momento en que suelta el botón.
Cree un proyecto MCF basado en diálogos con el nombre EventosMouse .

El objetivo del programa será ir mostrando en la barra de título del diálogo las coordenadas x e y relativas el puntero del mouse, a medida que uno lo mueve. Además si justamente se pulsa el botón izquierdo del mouse cuando las coordenadas x e y son iguales, se mostrará un mensaje y se realizará un pequeño circulo con centro en esas cooredenadas.
Son dos los mensajes del mouse que deberemos codificar. Uno es el que ocurre con el solo hecho de moverlo y el otro cuando pulsamos el botón izquierdo.
Aparecerá la definición del mensaje OnMouseMove(), allí escriba:
void CEventosMouseDlg::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CString strPos; (1)
strPos.Format ("Puntero en: x=%d, y=%d", point.x , point.y); (2)
SetWindowText(strPos); (3)
CDialog::OnMouseMove(nFlags, point);
}
En principio verá que la función recibe dos parámetros el primero un entero sin signo nFlags indica que otros botones del teclado se han mantenido pulsados, (este parámetro por ahora no nos interesa), y el otro de tipo CPoint son las coordenadas donde anda el puntero, es la estructura point y da a lugar a point.x , point.y.
En (1) se declara un string donde se almacenará la cadena a mostrar en la barra de título, la misma que en (2) formateo a través de su función Format() y como parámetros los valores x e y.
Con SetWindowText() en (3) se establece como título del diálogo el texto recién formateado.
Con esto ya logramos que a medida que movemos el mouse se van mostrando las coordenadas de la posición del puntero en la barra de título.
Ahora presione Ctrl + W para acceder a ClassWizard; marque en Object ID’s CeventosMouseDlg y en Messages selecciones WM_LBUTTONDOWN (este es el suceso para capturar cuando se presionó el botón izquierdo del mouse), pulse Add Function y luego Edit Code.
Escriba:
void CEventosMouseDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CDC* pDC; (1)
pDC = GetDC(); (2)
if (point.x == point.y ) (3)
{
MessageBox("Perfecto!", "Acertó",MB_ICONEXCLAMATION);
pDC->Ellipse (point.x -5 , point.y -5 , point.x + 5, point.y +5); (4)
}
else
MessageBox("Intentelo nuevamente", "Falló", MB_ICONERROR);
CDialog::OnLButtonDown(nFlags, point);
}
Lo que se quiere lograr es que si al presionar el botón izquierdo del mouse sobre el diálogo coinciden el valor de la coordenada x con el de y, se muestre un mensaje y se dibuje un circulo pequeño con centro en x, y.
Como hay que dibujar sobre el diálogo habrá que hacer uso de un Contexto de dipositios, por eso en (1) se declara un puntero a la clase CDC (más adelante se detallará el tema de Contextos de Dispositivos).
En (2) se obtiene el dispositivo por defecto (el diálogo) y en (3) me fijo si los parámetros x e y son iguales. En caso de ser iguales se muestra el mensaje "¡Perfecto!" y en (4) se dibuja el círculo por medio de la función Ellipse() de la clase CDC, cuyos parámetros son los puntos del rectángulo en el cual está inscripta la elipse. En este caso para que point.x, point.y sea el centro, se restó 5 para obtener el puntos superior izquierdo del rectángulo y se sumó 5 para el punto inferior izquierdo.
Resumiendo:
Lo referente a el Contexto de Dispositivo (clase CDC) se verá más adelante.
Descargar archivos fuentes del ejemplo: emouse.zip
Quienes programan en Visual Basic habrán usado alguna vez el control Timer. Este control permite estipular un intervalo de tiempo para el cual ejecutar una determinada porción de código. Digamos por ejemplo que quiero mostrar el mensaje "Hola" cada 5 segundos; bueno, en VB bastaba con agregar un control Timer en el formulario, especificar la propiedad Interval en 5000 (milésimas de segundos) y escribir el código del mensaje en el evento Timer del Timer.
Bien, nada de esto hay en VC++.
Mirando la barra de herramientas no encontramos ningún control Timer o Temporizador, pero esto no implica que no exista el concepto de temporizador en VC++.
Hay un mensaje para la clase CDialog llamado WM_TIMER, este mensaje es el encargado de ejecutar periódicamente el código que queramos. No funciona solo, sino que primero hay que hacer una llamada a la función SetTimer() pasándole como parámetro el intervalo en milésimas de segundos, (esta función, se podría decir, activa el Timer), después hay que usar la función KillTimer() para desactivarlo, (hay que recordar que un Timer activo ocupa recursos del sistema).
Bien, vamos a realizar una aplicación que incremente en 1 una variable pública y en 2 otra, cada un segundo. El programa utilizará el mensaje WM_TIMER y se activará cuando se pulse un botón y desactivará pulsando otro.
La pantalla debería quedar así:

Ahora vamos a asociarles variables a los cuadro de edición:
Creamos ahora la variable pública contador.
CTempoDlg::CTempoDlg(CWnd* pParent /*=NULL*/)
: CDialog(CTempoDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CTempoDlg)
m_eVeces = 0;
m_eVeces2 = 0;
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
m_nVeces=0; //Esta es la inicialización de la variable pública
}
Ya que tenemos todo preparado, es hora de agregar el mensaje WM_TIMER al diálogo:
void CTempoDlg::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
m_eVeces= m_nVeces; (1)
m_eVeces2=m_nVeces*2; (2)
UpdateData(FALSE); (3)
m_nVeces++; (4)
CDialog::OnTimer(nIDEvent);
}
Simplemente aquí se igualan las variables asociadas a los cuadros de edición con la variable pública contador, en (1) para que se vaya mostrando de saltos de a 1 y (2) se lo multiplica por 2 al contenido, entonces va pasando de a 2. En (3) transfiero los datos desde las variables a los contadores por medio de la función UpdateData(FALSE), para que se muestren por pantalla; y (4) incremento la variable pública.
Ahora hay que escribir el código, en el botón "Poner Timer", que llame a función SetTimer(), que es precisamente la que activa el Temporizador.
Entonces haga doble click sobre el botón, se creará automáticamente la función OnPonerTimer(), allí escriba:
void CTempoDlg::OnPonerTimer()
{
// TODO: Add your control notification handler code here
SetTimer(1,1000, NULL); (1)
}
A la función SetTimer() se le pasa como parámetros, primero un valor distinto de 0 que identificará a ese Timer en particular, en segundo lugar el intervalo de tiempo en milésimas de segundos, (en este caso 1000 equivale a 1 segundo, o sea que cada un segundo se ejecutará el código del evento OnTimer()) y por último se pasa un valor que significa a que objeto pertenece el temporizador, NULL porque se trata del diálogo actual;(por lo general va siempre NULL aquí).
Falta el código para terminar el Timer, escriba para el botón "Teminar Timer" lo siguiente:
void CTempoDlg::OnTerminarTimer()
{
CRect recDlg;
CString strH, strW;
// TODO: Add your control notification handler code here
KillTimer(1); (1)
}
Para terminar el temporizador simplemente hay que llamar a la función KillTimer() pasándole como parámetro el mismo valor distinto de 0 que representa el Timer.
Resumiendo: