La rueda del ratón no funciona en DROPDOWNLIST

La rueda del ratón no funciona en DROPDOWNLIST

Postby Armando » Fri Jul 19, 2024 7:56 pm

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
Armando
 
Posts: 3242
Joined: Fri Oct 07, 2005 8:20 pm
Location: Toluca, México

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

Postby Antonio Linares » Mon Jul 22, 2024 6:18 am

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 view  RUN
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 view  RUN
#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: 42203
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

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

Postby Antonio Linares » Mon Jul 22, 2024 8:39 am

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
Antonio Linares
Site Admin
 
Posts: 42203
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

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

Postby Armando » Mon Jul 22, 2024 4:59 pm

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
User avatar
Armando
 
Posts: 3242
Joined: Fri Oct 07, 2005 8:20 pm
Location: Toluca, México


Return to FiveWin para Harbour/xHarbour

Who is online

Users browsing this forum: No registered users and 20 guests