La rueda del ratón no funciona en DROPDOWNLIST

Post Reply
User avatar
Armando
Posts: 3249
Joined: Fri Oct 07, 2005 8:20 pm
Location: Toluca, México
Contact:

La rueda del ratón no funciona en DROPDOWNLIST

Post by Armando »

Foreros:

Resulta que la rueda del ratón (MouseWheel) no funciona en un ComboBox
con estilo DROPDOWNLIST, alguna idea?

Saludos
SOI, s.a. de c.v.
estbucarm@gmail.com
http://www.soisa.mex.tl/
http://sqlcmd.blogspot.com/
Tel. (722) 174 44 45
Carpe diem quam minimum credula postero
User avatar
Antonio Linares
Site Admin
Posts: 42268
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Re: La rueda del ratón no funciona en DROPDOWNLIST

Post by Antonio Linares »

Estimado Armando,

La cuestión que planteas aunque parece fácil es bastante complicada. Te explico el por qué:

1. Windows no proporciona un estilo de combobox que automaticamente procese el mensaje WM_MOUSEWHEEL en la lista desplegada del combobox.
2. Los mensajes WM_MOUSEWHEEL llegan a la lista desplegada y no al combobox por lo que no podemos usar oCombo:bMouseWheel
3. La única solución que parece posible es localizar el handle de ventana de la lista desplegable y "subclasear" su procedimiento para que procese WM_MOUSEWHEEL adecuadamente.

Para localizar el handle de la lista desplegada podemos hacer esto:

Code: Select all | Expand

METHOD HandleEvent( nMsg, nWParam, nLParam ) CLASS TComboBox

   local hWndComboList

   if nMsg == FM_CLOSEUP
      return ::CloseUp()
   endif

   if nMsg == FM_DROPDOWN
      return ::DropDown()
   endif

   if ::hWndComboList == nil .and. IsWindow( hWndComboList := hWndComboList( ::hWnd ) )
      ::hWndComboList = hWndComboList 
      // SetWindowProc( hWndComboList, { || nil } )   // probando la nueva función SetWindowProc()
   endif   

return ::Super:HandleEvent( nMsg, nWParam, nLParam )
 
Ahora en ::hWndComboList tenemos el handle de ventana de la lista desplegada y tenemos que implementar una nueva función SetWindowProc() para "subclasearla" y asi poder implementar el comportamiento para los mensajes WM_MOUSEWHEEL.

El código de la nueva función SetWindowProc() es un tanto complicado pero debera funcionar correctamente implementado asi:

Code: Select all | Expand

#include <windows.h>
#include <hbapi.h>
#include <hbapiitm.h>
#include <hbvm.h>

#if ( defined( _MSC_VER )  && ( _MSC_VER < 1500 ) ) // VC98
   #define GWLP_USERDATA    -21 
   #define GWLP_WNDPROC      -4
   LONG_PTR GetWindowLongPtr( HWND hWnd, int nIndex );
   LONG_PTR SetWindowLongPtr( HWND hWnd, int nIndex, LONG_PTR dwNewLong );
#endif

typedef struct
{
   PHB_ITEM pBlock;
   WNDPROC  pOldProc;
} HB_SUBCLASSED, * PHB_SUBCLASSED;

static LRESULT CALLBACK HB_SubclassedProc( HWND hWnd, UINT message,
                                           WPARAM wParam, LPARAM lParam )
{
   PHB_SUBCLASSED pSubclassed = ( PHB_SUBCLASSED ) GetWindowLongPtr( hWnd, GWLP_USERDATA );

   if( pSubclassed && pSubclassed->pBlock )
   {
      PHB_ITEM pReturn;
      #ifndef _WIN64
         PHB_ITEM phWnd = hb_itemPutNL( NULL, ( long ) hWnd );
         PHB_ITEM pMessage = hb_itemPutNL( NULL, ( long ) message );
         PHB_ITEM pwParam = hb_itemPutNL( NULL, ( long ) wParam );
         PHB_ITEM plParam = hb_itemPutNL( NULL, ( long ) lParam );      
      #else   
         PHB_ITEM phWnd = hb_itemPutNLL( NULL, ( HB_LONGLONG ) hWnd );
         PHB_ITEM pMessage = hb_itemPutNLL( NULL, ( HB_LONGLONG ) message );
         PHB_ITEM pwParam = hb_itemPutNLL( NULL, ( HB_LONGLONG ) wParam );
         PHB_ITEM plParam = hb_itemPutNLL( NULL, ( HB_LONGLONG ) lParam );      
      #endif   
      hb_evalBlock( pSubclassed->pBlock, phWnd, pMessage, pwParam, plParam, NULL );
      hb_itemRelease( phWnd );
      hb_itemRelease( pMessage );
      hb_itemRelease( pwParam );
      hb_itemRelease( plParam );
      pReturn = hb_param( -1, HB_IT_ANY );
      if( HB_IS_NUMERIC( pReturn ) )
         return hb_itemGetNL( pReturn );
   }

   return pSubclassed && pSubclassed->pOldProc ? 
          CallWindowProc( pSubclassed->pOldProc, hWnd, message, wParam, lParam ) :
          DefWindowProc( hWnd, message, wParam, lParam );
}

HB_FUNC( SETWINDOWPROC )
{
   #ifndef _WIN64 
      HWND hWnd = ( HWND ) hb_parnl( 1 );
   #else   
      HWND hWnd = ( HWND ) hb_parnll( 1 );
   #endif   
   PHB_ITEM pBlock = hb_param( 2, HB_IT_BLOCK );

   if( hWnd && pBlock )
   {
      PHB_SUBCLASSED pSubclassed = ( PHB_SUBCLASSED ) GetWindowLongPtr( hWnd, GWLP_USERDATA );

      if( ! pSubclassed )
      {
         pSubclassed = ( PHB_SUBCLASSED ) hb_xgrab( sizeof( HB_SUBCLASSED ) );
         SetWindowLongPtr( hWnd, GWLP_USERDATA, ( LONG_PTR ) pSubclassed );
      }
      else
         hb_itemRelease( pSubclassed->pBlock );

      pSubclassed->pBlock = hb_itemNew( pBlock );
      pSubclassed->pOldProc = ( WNDPROC ) SetWindowLongPtr( hWnd, GWLP_WNDPROC,
                                                            ( LONG_PTR ) HB_SubclassedProc );

      hb_retnl( ( LONG_PTR ) pSubclassed->pOldProc );
   }
   else
      hb_retnl( 0 );
}

HB_FUNC( REMOVEWINDOWPROC )
{
   #ifndef _WIN64 
      HWND hWnd = ( HWND ) hb_parnl( 1 );
   #else   
      HWND hWnd = ( HWND ) hb_parnll( 1 );
   #endif   

   if( hWnd )
   {
      PHB_SUBCLASSED pSubclassed = ( PHB_SUBCLASSED ) GetWindowLongPtr( hWnd, GWLP_USERDATA );

      if( pSubclassed )
      {
         SetWindowLongPtr( hWnd, GWLP_WNDPROC, ( LONG_PTR ) pSubclassed->pOldProc );
         hb_itemRelease( pSubclassed->pBlock );
         SetWindowLongPtr( hWnd, GWLP_USERDATA, 0 );
         hb_xfree( pSubclassed );
      }
   }
}
En principio todo parece estar bien y ya podriamos continuar implementando el soporte para WM_MOUSEWHEEL. El problema es que al intentar usar SetWindowProc() obtenemos un GPF que nos deja fuera de juego. Estamos buscando la razón de ese GPF.
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
Posts: 42268
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Re: La rueda del ratón no funciona en DROPDOWNLIST

Post by Antonio Linares »

Estábamos equivocados :-)

Sin ningún cambio en FWH, la rueda de mouse SI funciona con listas de combobox cuando la lista es más grande que el área de la lista.

Cuando la lista es grande, vemos una barra de desplazamiento y luego tanto la barra de desplazamiento como la rueda de mouse funcionan.

Cuando la lista es pequeña, no hay necesidad y ni siquiera tiene sentido que la rueda de mouse funcione.

Gracias a Rao por sabiamente observar esto!

Image
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Armando
Posts: 3249
Joined: Fri Oct 07, 2005 8:20 pm
Location: Toluca, México
Contact:

Re: La rueda del ratón no funciona en DROPDOWNLIST

Post by Armando »

Maestro Antonio y Mr. Rao:

Tienen la boca llena de razón, tengo dos PRG que usan el control, ahora que lo mencionaste
comparé uno con otro y efectivamente, uno funciona y en el otro no.

Revisé el control y en el que no funcionaba tenia yo el WINDOWS-STYLE Vert Scrollbar a NO.

Me disculpo fue mi error.

Saludos
SOI, s.a. de c.v.
estbucarm@gmail.com
http://www.soisa.mex.tl/
http://sqlcmd.blogspot.com/
Tel. (722) 174 44 45
Carpe diem quam minimum credula postero
Post Reply