VS2008: Cambiar cursor de botón deshabilitado
-
lundi 6 février 2012 10:29Hola,alguien sabe cómo se puede cambiar el tipo de cursor default a otro tipo (en mi caso quiero el Cursors::No) cuando un botón está deshabilitado?Cambiándolo con el botón habilitado no hay problema, pero al estar deshabilitado el cursor queda igual al pasar por encima.Lo hago con this->button1->cursor=Cursors::No;Estoy programando en C++ (Visual Studio 2008)Alguna idea? gracias adelantadas!
Toutes les réponses
-
lundi 6 février 2012 12:07
Void Form1_MouseMove(Object^ sender, MouseEventArgs^ e) { this->Cursor = button1->Bounds.Contains(this->PointToClient(Cursor->Position)) ? Cursors::No : Cursors::Default; }
Dentro del evento MouseMove del form. Si el botón está inhabilitado el form lo recibe. -
lundi 6 février 2012 12:34
Gracias Walter!
Lo que hace es comprobar si la posicion del cursor está sobre el botón, entonces cambia al cursor correspondiente lo que es el cursor como tal y no el cursor del botón (es decir, la propiedad del botón cursor), no?
voy a probarlo :) y te cuento.
Sara- Modifié Sara23SQL lundi 6 février 2012 12:40
-
lundi 6 février 2012 20:30
Vale, funciona pero a medias, jeje.
Le he añadido
this->MouseMove += gcnew MouseEventHandler(this, &form1::form1_MouseMove);
para que funcione, y he cambiado un poco la función para comprobar que hace algo:
void form1_MouseMove(Object^ sender, System::Windows::Forms::MouseEventArgs^ e) { this->Cursor = button1->Bounds.Contains(this->PointToClient(Cursor->Position)) ? Cursors::No : Cursors::Cross; }
Pero al pasar por dicho botón, el cursor es el mismo, una cruz (lo he puesto así para ver si entra, quitando el default) y no cambia, porque puede ser? Gracias de nuevo!
Sara -
mardi 7 février 2012 02:57
No pude reproducir el efecto que mencionas.
Cuando el botón está inhabilitado y el hot spot del cursor dentro de sus límites, el evento lo recibe el form1 que cambia su cursor a No. Si está fuera de los límites, es una cruz.
-
mardi 7 février 2012 08:41Así es, en parte, lo que no hace es cambiar el cursor a tipo No, pero si a tipo Cross cuando esta en el resto del formulario. Lo has probado y si te funciona? Es decir, al pasar el ratón por el botón cambia a No (aún estando deshabilitado) y sino es una cruz? Voy a volver a revisar, por si acaso. Gracias por tu ayuda! Voy probando y te sigo contando.
Sara
-
mercredi 8 février 2012 01:50
y porque no mejor en lugar de usar la posicion del cursor usas las coordenadas en el MouseEventArgs?
ejemplo:
private: System::Void Form1_MouseMove(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) { this->Cursor = this->button1->Bounds.Contains(Point(e->X, e->Y)) ? Cursors::No : Cursors::Default; }
es igual, pero asi no necesitas usar PointToClient()
Salu2,
Marvin E. Pineda
ComboBoxMultiColumns
-
mercredi 8 février 2012 12:08
Si. Cambia.
Si agrego otro botón habilitado, su cursor cambia al default para esa clase de ventana (la flecha): el form obviamente ya no recibe el mouse move.
Creo que si no funciona es que debo estar pasando por alto alguna cosa. Digo, cuando el ratón se mueve el control recibe un wm_setcursor (luego de un wm_nchittest, que suele condicionar el cursor a mostrar), y el defwindowproc() pinta el cursor por defecto que levanta del wndclass. En este caso el control que recibe el mensaje es la ventana del form.
-
mercredi 8 février 2012 20:23
y porque no mejor en lugar de usar la posicion del cursor usas las coordenadas en el MouseEventArgs?
ejemplo:
private: System::Void Form1_MouseMove(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) { this->Cursor = this->button1->Bounds.Contains(Point(e->X, e->Y)) ? Cursors::No : Cursors::Default; }
es igual, pero asi no necesitas usar PointToClient()
Salu2,
Marvin E. Pineda
ComboBoxMultiColumns
No me funciona :( no se que hago mal (en lugar del default, he puesto el tipo cross para comprobar que entra en el procedimiento)
Continuaré probando. Gracias!
Sara
-
mercredi 8 février 2012 21:40
que raro!!!!... pero bien
prueba de esta otra manera:
private: System::Void Form1_MouseMove(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) { Control^ ctl = this->GetChildAtPoint(Point(e->X, e->Y)); if (ctl) { this->Cursor = Cursors::No; } else { this->Cursor = Cursors::Default; } }si así no te funciona, pon un punto de interrupción para que depures el evento.
Salu2,
Marvin E. Pineda
ComboBoxMultiColumns
- Marqué comme réponse Sara23SQL dimanche 12 février 2012 19:22
-
jeudi 9 février 2012 09:27Modérateur
Lo mismo digo una chorrada, porque leo y debería funcionar como lo hacéis, pero ¿por qué no usáis los enventos Enter y Leave del control del que quieres cambiar el cursor?
Bueno, edito porque no funciona. Al estar deshabilitado el botón, no recibe mensajes de ningún tipo, por lo que hay que hacerlo a nivel de form con el mousemove.
Una pregunta: ¿cambiáis el cursor del botón o del form? Porque si es el del botón, no hará nada puesto que está a todos los efectos "muerto".
MVP Visual C++ - Visita mi blog sobre desarrollo: http://geeks.ms/blogs/rfog/
- Modifié RFOGMVP, Moderator jeudi 9 février 2012 09:36 añadir información
-
jeudi 9 février 2012 09:47Modérateur
Bueno, finalmente lo encontré y es una tontería como una casa.
El código a aplicar es:
private: System::Void Form1_MouseMove(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) { Control^ ctl = this->GetChildAtPoint(Point(e->X, e->Y)); if(ctl && ctl->Name=="button1") Cursor=Cursors::No; else Cursor=Cursors::Default; }Pero hay que hacerlo un poco más complicado.
Deberías crear una variable de estado y asignar el código sólo una vez, porque si no estarás asignando el cursor de forma continua cada vez que se mueva por dentro del form.
MVP Visual C++ - Visita mi blog sobre desarrollo: http://geeks.ms/blogs/rfog/
-
vendredi 10 février 2012 09:41
Void Form1_MouseMove(Object^ sender, MouseEventArgs^ e)
{ this->Cursor = button1->Bounds.Contains(this->PointToClient(Cursor->Position)) ? Cursors::No : Cursors::Default; }
Dentro del evento MouseMove del form. Si el botón está inhabilitado el form lo recibe.He vuelto a probar esto de nuevo, con un proyecto sencillo: u form con 3 botones, 2 de ellos deshabilitados. El caso es que si, solo hay dos botones, con uno de ellos deshabilitado funciona bien! per al poner otro, como decia al principio, solo funciona unos de ellos (el segundo) con:
this->MouseMove += gcnew MouseEventHandler(this, &Form1::Form1_MouseMove); private: System::Void Form1_MouseMove(Object^ sender, MouseEventArgs^ e){ this->Cursor = button2->Bounds.Contains(this->PointToClient(Cursor->Position)) ? Cursors::No : Cursors::Default; this->Cursor = button3->Bounds.Contains(this->PointToClient(Cursor->Position)) ? Cursors::Help : Cursors::Default; }Esta vez, lo he probado con VS2005, en WXP, mientras que cuando lo hago en VS2008, es en W7. La cosa es que solo funciona con uno, o debería haber un evento por botón?
Gracias por vuestras respuestas!
Sara
-
vendredi 10 février 2012 09:45
y porque no mejor en lugar de usar la posicion del cursor usas las coordenadas en el MouseEventArgs?
ejemplo:
private: System::Void Form1_MouseMove(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) { this->Cursor = this->button1->Bounds.Contains(Point(e->X, e->Y)) ? Cursors::No : Cursors::Default; }
es igual, pero asi no necesitas usar PointToClient()
Salu2,
Marvin E. Pineda
ComboBoxMultiColumns
No me funciona :( no se que hago mal (en lugar del default, he puesto el tipo cross para comprobar que entra en el procedimiento)
Continuaré probando. Gracias!
Sara
Al igual que con la otra respuesta, lo he probado en VS2005 y funciona pero a medias, con uno de los botones no hace nada:
private: System::Void Form1_MouseMove(Object^ sender, MouseEventArgs^ e){ this->Cursor = button2->Bounds.Contains(Point(e->X, e->Y)) ? Cursors::No : Cursors::Default; this->Cursor = button3->Bounds.Contains(Point(e->X, e->Y)) ? Cursors::Help : Cursors::Default; }
Sara
-
vendredi 10 février 2012 09:49
Perfecto! Es justo el efecto que quiero! Aunque no se indique el botón, si éste está deshabilitado cambia el cursor. Tengo dos de ellos deshabilitados y cambia el cursor en ambos. Lo he probado por el momento en VS2005, lo tengo que probar en 2008 y os comento, espero que funcione también! Muchas gracias :)que raro!!!!... pero bien
prueba de esta otra manera:
private: System::Void Form1_MouseMove(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) { Control^ ctl = this->GetChildAtPoint(Point(e->X, e->Y)); if (ctl) { this->Cursor = Cursors::No; } else { this->Cursor = Cursors::Default; } }si así no te funciona, pon un punto de interrupción para que depures el evento.
Salu2,
Marvin E. Pineda
ComboBoxMultiColumns
Sara
-
vendredi 10 février 2012 09:53
Funciona también pero en el caso de usar un solo botónBueno, finalmente lo encontré y es una tontería como una casa.
El código a aplicar es:
private: System::Void Form1_MouseMove(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) { Control^ ctl = this->GetChildAtPoint(Point(e->X, e->Y)); if(ctl && ctl->Name=="button1") Cursor=Cursors::No; else Cursor=Cursors::Default; }Pero hay que hacerlo un poco más complicado.
Deberías crear una variable de estado y asignar el código sólo una vez, porque si no estarás asignando el cursor de forma continua cada vez que se mueva por dentro del form.
MVP Visual C++ - Visita mi blog sobre desarrollo: http://geeks.ms/blogs/rfog/
Sara
-
vendredi 10 février 2012 13:47Modérateur
Te funciona uno solo porque efectivamente sólo comprueba el último. La secuencia es:
Si estoy dentro del primero, quito el cursor. Si estoy fuera lo pongo.
Si estoy dentro del segundo, quito el cursor. Si estoy fuera lo pongo.
Por lo tanto, cuando termina de ejecutar el código, o bien estás dentro del segundo o bien fuera.
El código debería ser algo así (escrto al vuelo, podría tener errores):
this->MouseMove += gcnew MouseEventHandler(this, &Form1::Form1_MouseMove); private: System::Void Form1_MouseMove(Object^ sender, MouseEventArgs^ e){ this->Cursor = (button2->Bounds.Contains(this->PointToClient(Cursor->Position)) || this->Cursor = button3->Bounds.Contains(this->PointToClient(Cursor->Position)))? Cursors::No : Cursors::Default; }
Por cierto, haz lo que digo de asignarlo una sola vez mientras estés dentro y cuando salgas.
MVP Visual C++ - Visita mi blog sobre desarrollo: http://geeks.ms/blogs/rfog/
-
vendredi 10 février 2012 15:29
if (button1->Bounds.Contains(this->PointToClient(Cursor->Position)) || button2->Bounds.Contains(this->PointToClient(Cursor->Position))) { this->Cursor = Cursors::No; } else this->Cursor = Cursors::Cross;Incluso podrías testear la colección completa de controles sin discriminarlos.
Fijate que Cursor es una propiedad de ambiente. O sea, cualquier control habilitado mostrará la cruz salvo que establezcas otra cosa en la propiedad Cursor del control. Ok, ya sé que pusiste Cross en vez de Default para hacer pruebas...#include <Windows.h>
protected: virtual void WndProc(Message% m) override { switch(m.Msg) { case WM_NCHITTEST: { this->DefWndProc(m); if (m.Result == (IntPtr)HTCLIENT) { Point p; p.X = (int)m.LParam & 0x0000FFFF; p.Y = ((int)m.LParam & 0xFFFF0000) >> 16; if (GetChildAtPoint(this->PointToClient(p)) != nullptr) { this->Cursor = Cursors::No; } else this->Cursor = Cursors::Cross; } break; } default: Form::WndProc(m); } }
- Modifié Walter MDV vendredi 10 février 2012 17:26
- Modifié Walter MDV vendredi 10 février 2012 18:32
-
dimanche 12 février 2012 19:21
Muchas gracias por la ayuda! Lo he probado en VS2008 y va bien :) Echaré también un vistazo a las soluciones alternativas que me habeis propuesto, parfa aprender algo más.
Saludos!
Sara
-
lundi 13 février 2012 16:45Modérateur
La solución (al menos la primera parte del código) es idéntica a la mia, pero con más codificación (y más clara de ver). Yo simplemente añadí el código necesario al tuyo.
El segundo bloque de código es completamente ineficiente, ya que añade una nueva subclasificación virtual a la lista que ya pueda tener de por sí el .NET (unas cuantas, seguro), con lo que se añade un nuevo puntero a la vtable y un salto doblemente indirecto.
MVP Visual C++ - Visita mi blog sobre desarrollo: http://geeks.ms/blogs/rfog/

