Bueno, hoy he estado haciendo pruebas sobre como crear un control estático donde maneje a mi antojo lo que dibuje en el con MFC para windows, y entre otras cosas se me ha ocurrido meterle un icono como dibujo y que cuando el ratón pase por una zona del control se cambie el cursor (el puntero).
Para el primero he tenido varios problemas puesto que no esta muy depurada la API de windows para manejar cursores y dejarlos en 16×16 pixeles, haciendo cosas raras, menos mal que dentro del oceano de Internet uno puede ir recopilando informaciones cuando no se encuentra todo en un documento para saber como hacerlo. Tan sencillo como esto:
1 2 3 4 5 6 7 |
HICON icono=(HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_SEMAFOROVERDE), IMAGE_ICON, 16,16, LR_DEFAULTCOLOR); DrawIconEx(fondo.GetSafeHdc(),10,10,icono,16,16,0,NULL,DI_NORMAL); DestroyIcon(icono); |
Primero cargo el icono con la función LoadImage, donde le paso como parámetros la instancia de la aplicación donde se encuentra el icono (la misma aplicación donde se ejecuta), el identificador del recurso del icono pasado a cadena con la macro MAKEINTRESOURCE, el tipo de imagen que es (un icono), la anchura y la altura del mismo y finalmente que lo coja con los colores por defecto.
Segundo dibujo el icono en el dispositivo de contexto que nos ofrece windows para dibujar en el control CStatic, no uso la función DrawIcon del objeto de dispositivo contexto por que no consigue adaptar bién el icono a 16×16 pixeles, por lo que uso la función win32 DrawIconEx que si me lo permite, pasandole como parámetros el manejeador del dispositivo de contexto, la posición x e y donde quiero dibujar el icono, el icono, su achura y altura, ningúna brocha (no es necesario) y le digo que es una imagen con transparencias (DI_NORMAL indica todo eso).
Tercero lo destruyo porque en esto de la programación en C es bueno la «limpieza».
Para el segundo caso, siendo aún más sencillo me he partido más los cuernos, simplemente porque el evento que se debe usar para cambiar el cursor no tiene mucha lógica con lo que uno quiere hacer. Mi idea es que cuando moviese el ratón por una zona del CStatic, se cambiase el cursor, sin embargo usando el evento OnMouseMove no funciona para nada la función SetCursor. He de decir que cuando digo CStatic, en realidad es una clase que he derivado de esa para poder interceptar los eventos. Por lo visto para que funcione lo que queremos hacer debemos usar el vento OnSetCursor, que funciona a semejanza del OnMouseMove, pero que no te da las coordenadas dentro del control donde se encuentre el puntero del ratón, sino que se activa cuando se pasa el ratón por el control. Esto no funcionaría si no tuviesemos activado la opción «notify» de los estilos del control. Aquí dejo mi solución de como lo he conseguido al final:
1 2 3 4 5 6 7 8 9 10 11 |
POINT point; GetCursorPos(&point); ScreenToClient(&point); if(point.y>=10 && point.y<66) { ::SetCursor(LoadCursor(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDC_CURSOR))); return TRUE; } return CStatic::OnSetCursor(pWnd, nHitTest, message); |
Primero declaro una variable POINT, luego pregunto con GetCursorPos que me diga la posición relativa a pantalla donde se encuentra el ratón, y a continuación lo transformo a coordenadas del control gracias a la función ScreenToClient. Con todo esto logramos saber en que posición de nuestro control esta el cursor ya que el OnSetCursor no nos la da como parámetro como lo hicera el OnMouseMove.
Segundo comparo si el cursor esta dentro de un rango en el eje de la altura y si es así ya uso la función SetCursor (de la api de win32 no del objeto), pasandole como parámetro el cursor que me devuelve la función LoadCursor, a la cual se le pasan como parámetros la instancia donde se encuentra el cursor (la nuestra en este caso) y el identificador del cursor pasado a cadena con la macro explicada antes. Después salimos de la función delvolviendo un valor TRUE indicando que no hay que hacer nada más.
Tercero, si llega hasta aquí significa que no ha pasado por el if y que llama al manejador por defecto devolviendo el valor que a su vez este devuelve, esta linea la incorpora automáticamente el Editor de Visual C++ cuando añadimos el evento OnSetFocus.
Como veis la programación de Windows es apasionante, pero muchas veces me encuentro con cosas que no funcionan como deben o se manejan de forma ilógica, pero bueno, menos mal que ya hay mucho escrito sobre eso. Por cierto, sigo pendiente de aprender programar linux, estoy por el capítulo de programación avanzada de ficheros y en siguiente ya son los demonios, y aún así me queda mucho libro por leer 🙂