VS2008: Cambiar cursor de botón deshabilitado

Answered VS2008: Cambiar cursor de botón deshabilitado

  • lundi 6 février 2012 10:29
     
     
    Hola, 
    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
     
      A du code
    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
     
      A du code

    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:41
     
     
    Así 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
     
      A du code

    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

     NetBarControl

      TextEditor

  • 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
     
      A du code

    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

     NetBarControl

      TextEditor

    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
     
     Traitée A du code

    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

     NetBarControl

      TextEditor

    • Marqué comme réponse Sara23SQL dimanche 12 février 2012 19:22
    •  
  • jeudi 9 février 2012 09:27
    Modé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/


  • jeudi 9 février 2012 09:47
    Modérateur
     
      A du code

    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
     
      A du code

    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
     
      A du code

    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

     NetBarControl

      TextEditor

    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
     
      A du code

    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

     NetBarControl

      TextEditor

    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 :)

    Sara

  • vendredi 10 février 2012 09:53
     
      A du code

    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/

    Funciona también pero en el caso de usar un solo botón

    Sara

  • vendredi 10 février 2012 13:47
    Modérateur
     
      A du code

    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
     
      A du code

     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.

    #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); } }

    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...

    • 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:45
    Modé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/