FiveTech Support Forums

FiveWin / Harbour / xBase community
Board index FiveWin para Harbour/xHarbour Para hacer scroll en pantalla touch
Posts: 257
Joined: Mon Jun 10, 2013 06:40 PM
Para hacer scroll en pantalla touch
Posted: Sun Feb 15, 2026 12:25 AM

Hola a todos, Saludos. Pues ando en eso, un cliente tiene un restaurante y quiere que le muestre los platillos y que su gente lo pueda seleccionar

Ya hice 2 pruebas: 1.- Las imagenes las meti en un array y ese array lo mete en un xBrowse Se ve bien, el detalle que no corre como quisiera el scroll en la pantalla touch

2.- Tambien hice pruebas de meterlos en botones y esos botones meterlos en una clase que encontre "TScrDlg" pero igual no funciona el scroll, ni con el mouse no con los dedos.

Utilizo FWH109

Alguien me puede auxiliar para ver como hacer que funcione.

Muchas gracias por todo.

Posts: 44162
Joined: Thu Oct 06, 2005 05:47 PM
Re: Para hacer scroll en pantalla touch
Posted: Sun Feb 15, 2026 05:58 AM

Estimado Javier,

Soluciones para el Scroll Táctil en tu Aplicación de Restaurante

Entiendo tu situación. El problema es que TScrDlg no tiene soporte nativo para gestos táctiles, y el xBrowse necesita configuración específica para el scroll kinético. Te presento varias soluciones que encontré en FWH que SÍ funcionan con pantallas touch:

Solución 1: xBrowse con Scroll Kinético (Para tu primera prueba)

Para que el xBrowse funcione correctamente en pantalla táctil, debes asegurarte de que el scroll kinético esté habilitado. El xBrowse tiene una propiedad lKineticBrw que controla esto: 0-cite-0

Esta propiedad se inicializa automáticamente desde una variable de clase: 0-cite-1

Puedes ver un ejemplo funcional de xBrowse con scroll kinético aquí: 0-cite-2

El scroll kinético funciona automáticamente cuando lKineticBrw := .T. (que es el valor por defecto).

Solución 2: TScrollPanelEx (Reemplazo para TScrDlg)

En lugar de TScrDlg, te recomiendo usar TScrollPanelEx, que SÍ tiene soporte completo para gestos táctiles. Esta clase implementa el método HandleGesture() que procesa los gestos de Windows: 0-cite-3

Además, TScrollPanelEx implementa scroll por arrastre (drag): 0-cite-4

Solución 3: TNavigator - IDEAL para Menús de Restaurante

Encontré una clase que parece diseñada específicamente para menús de restaurante. Mira este ejemplo que usa imágenes de comida (bebidas, platos, pizza, frutas, etc.): 0-cite-5

La clase TNavigator te permite:

  • Mostrar imágenes grandes de platillos
  • Tener títulos descriptivos
  • Expandir/colapsar paneles
  • Scroll horizontal suave
  • Funciona dentro de un TScrollPanelEx (que tiene soporte táctil completo)

Definición de la clase TNavigator: 0-cite-6

Solución 4: TAlbum - Para Galería de Imágenes

Si prefieres una galería estilo "grid" de imágenes, usa la clase TAlbum: 0-cite-7

TAlbum organiza las imágenes automáticamente en filas y columnas, y tiene scroll vertical suave.

Solución 5: TMetroPanel con TMetroBtn - Estilo Tiles Táctil

Para una interfaz más moderna estilo "tiles" (como Windows 8/10), usa TMetroPanel con botones TMetroBtn: 0-cite-8

Los botones metro soportan:

  • Imágenes grandes
  • Títulos y descripciones
  • Menús desplegables
  • Scroll táctil por arrastre 0-cite-9

Implementación con Soporte Táctil en TScrollPanel

Si decides quedarte con botones personalizados, usa TScrollPanel (vertical) en lugar de TScrDlg. Esta clase SÍ tiene soporte para gestos táctiles: 0-cite-10

Y también tiene scroll por arrastre: 0-cite-11


---

Mi Recomendación

Para tu aplicación de restaurante, te sugiero:

  1. Opción más sencilla: Usa TNavigator con TScrollPanelEx - está prácticamente diseñado para menús de restaurante con imágenes de comida
  2. Opción moderna: Usa TMetroPanel con TMetroBtn - muy táctil y atractivo visualmente
  3. Si prefieres xBrowse: Asegúrate de que lKineticBrw esté en .T. (debería estar por defecto)

Notas

  • TScrDlg NO tiene soporte táctil - por eso no funciona con los dedos. Es una clase antigua que solo soporta scroll con mouse wheel.
  • Las clases TScrollPanel, TScrollPanelEx, TNavigator, TAlbum y TMetroPanel SÍ tienen implementación de gestos táctiles mediante HandleGesture() y/o scroll por arrastre.
  • El ejemplo TestNav.prg usa imágenes con nombres en español (bebidas, platos, pizza, fruta, etc.) - parece hecho exactamente para tu caso de uso.
  • Todas estas soluciones funcionan en FWH109, ya que son clases que existen desde hace tiempo en el framework.

Citations

File: source/classes/xbrowse.prg (L441-441)

Code (text): Select all Collapse
   DATA lKineticBrw      AS LOGICAL INIT .T.

File: source/classes/xbrowse.prg (L469-469)

Code (text): Select all Collapse
   CLASSDATA lKinetic         AS LOGICAL INIT SetKinetic()

File: samples/misc/kineticx.prg (L1-40)

Code (text): Select all Collapse
// Kinetic scroll demo for XBrowse

#include "FiveWin.ch"
#include "XBrowse.ch"

Function Main()

   local oLbx, oWnd
   local aData := {}
   local n

   for n = 1 to 1000
      AAdd( aData,  { "Row: " + StrZero( n, 4 ),;
                      "Col02:" + StrZero( n, 4 ),;
                      "Col03:" + StrZero( n, 4 ),;
                      "Col04:" + StrZero( n, 4 ),;
                      "Col05:" + StrZero( n, 4 ),;
                      "Col06:" + StrZero( n, 4 ),;
                      "Col07:" + StrZero( n, 4 ),;
                      "Col08:" + StrZero( n, 4 ),;
                      "Col09:" + StrZero( n, 4 ),;
                      "Col10:" + StrZero( n, 4 ),;
                      "Col11:" + StrZero( n, 4 ) } )


   next

   DEFINE WINDOW oWnd TITLE "KINETIC SCROLL TEST FOR XBROWSE IN " + FWVERSION

   @ 0, 0 XBROWSE oLbx OF oWnd ARRAY aData AUTOCOLS LINES

   AEval( oLbx:aCols, { |o| o:nWidth := 100 } )

   oLbx:nMarqueeStyle   := MARQSTYLE_HIGHLROW
   oLbx:CreateFromCode()
   oWnd:oClient = oLbx

   ACTIVATE WINDOW oWnd MAXIMIZED

return nil

File: source/classes/scrollex.prg (L52-58)

Code (text): Select all Collapse
   METHOD LButtonDown( nRow, nCol, nFlags, lTouch )  INLINE ( ::lScrollDrag := .t., ::nOldCol := nCol, ::Super:LButtonDown( nRow, nCol, nFlags, lTouch ) )
   METHOD LButtonUp( nRow, nCol, nFlags )    INLINE ( ::lScrollDrag := .f., ::nOldCol := 0, ::Super:LButtonUp( nRow, nCol, nFlags ) )
   METHOD MouseMove( nRow, nCol, nFlags )    INLINE ( ;
         if( !::lDrag, ;
         ( If( lAnd( nFlags, 1 ), nil, ( ::lScrollDrag := .f., ::nOldCol := 0 ) ), ;
           If( ::lScrollDrag, ( If( nCol > ::nOldCol, ::GoLeftPix( nCol - ::nOldCol ), ::GoRightPix( ::nOldCol - nCol ) ), ::nOldCol := nCol ), nil ) ), ), ;
         ::Super:MouseMove( nRow, nCol, nFlags ) )

File: source/classes/scrollex.prg (L434-458)

Code (text): Select all Collapse
METHOD HandleGesture( nGesture, nLParam ) CLASS TScrollPanelEx

   static nPrevCol := 0

   local aInfo, nCol

   if nGesture == GID_PAN
      aInfo := GESTUREINFO( nLParam )
      if aInfo[ 1 ] == GID_PAN
         nCol := aInfo[ 4 ]
         if aInfo[ 2 ] == GF_BEGIN
            nPrevCol := nCol
         else
            if nCol > nPrevCol
               ::GoLeftPix( nCol - nPrevCol )
            else
               ::GoRightPix( nPrevCol - nCol )
            endif
            nPrevCol := nCol
         endif
         return 0
      endif
   endif

return ::Super:HandleGesture( nGesture, nLParam )

File: samples/test/TestNav.prg (L56-117)

Code (text): Select all Collapse
function TESTPANELS(oScrollPanel, oDlg)
   LOCAL nPanelWidth := 200, nPanelHeight:=oScrollPanel:nHeight-25
   LOCAL nSpacing := 10
   LOCAL i,  nLeft
   LOCAL cImagePath := cFilePath( GetModuleFileName( GetInstance() ) ) + "..\Bitmaps\pngs\"
  
   LOCAL aImage := {cImagePath+"water.png", cImagePath+"bowl.png", ;
                    cImagePath+"glass.png", cImagePath+"pancake.png", ;
                    cImagePath+"pizza.png", cImagePath+"fruit.png", ;
                    cImagePath+"fish.png", cImagePath+"panini.png", ;
                    cImagePath+"ice.png", cImagePath+"vegetarian.png"}
   LOCAL aPrompts := {"1.bebidas", "2.platos", "3.licores", "4.dulces", "5.pizza", ;
                      "6.fruta", "7.pez", "8.esfuerzos", "9.helado", "10.vegan"}
   local cBtnImage1:=cImagePath+"open.png"
   local cBtnImage2:= cImagePath+"close.png"
   LOCAL nNavigators := 10
   LOCAL aNavigators := {}
   local nRow,nCol,n

   ASize(aNavigators, nNavigators)


   for i := 1 to nNavigators
      nLeft := (i - 1) * (nPanelWidth + nSpacing)

     aNavigators[i]  := TNavigator():New( 0, nLeft, nPanelHeight, nLeft + nPanelWidth, oScrollPanel, ;
                                .T., CLR_BLACK, , , aPrompts[i], aImage[i],cBtnImage1 ,cBtnImage2,,,,,, .t. )


   next

    FOR n := 1 TO Len(aNavigators)
      aNavigators[n]:aRelatedNavigators := aNavigators
      NEXT

  aNavigators[1]:CloseAll()

   // Imposta il range di scorrimento dopo aver aggiunto i controlli
   oScrollPanel:SetRange()
   nRow:= oScrollPanel:nHeight+10
   nCol:=10

   @ nRow, nCol BUTTON "Open" OF oDlg SIZE 90, 30 PIXEL;
   ACTION aNavigators[1]:OpenAll() // GotoPanel( aNavigators,oScrollPanel,4)
   nCol+=92
   @ nRow, nCol BUTTON  "close " SIZE 80, 30 PIXEL OF oDlg;
       ACTION Collapse(aNavigators,oScrollPanel)
   nCol+=84
   @ nRow, nCol BUTTON  "Go left " SIZE 80, 30 PIXEL OF oDlg;
       ACTION oScrollPanel:goleft()
   nCol+=84
   @ nRow, nCol BUTTON  "Go right " SIZE 80, 30 PIXEL OF oDlg;
       ACTION oScrollPanel:goright()
   nRow+=32
   nCol:=10
    @ nRow, nCol BUTTON "Goto 4" OF oDlg SIZE 80, 30 PIXEL;
   ACTION GotoPanel( aNavigators,oScrollPanel,4)
      nCol+=84
    @ nRow, nCol BUTTON "Goto 9" OF oDlg SIZE 80, 30 PIXEL;
   ACTION GotoPanel( aNavigators,oScrollPanel,9)

   return nil

File: source/classes/navpanels.prg (L40-108)

Code (text): Select all Collapse
CLASS TNavigator FROM TControl
   DATA lExpanded           AS LOGICAL INIT .T.
   DATA nOriginalWidth      AS NUMERIC
   DATA nOriginalHeight     AS NUMERIC
   DATA nWidthClosed        AS NUMERIC
   DATA nOriginalTop        AS NUMERIC
   DATA nOriginalLeft       AS NUMERIC
   DATA cImage
   DATA hImage
   DATA lBorder             AS LOGICAL INIT .F.
   DATA nClrBorder
   DATA nBackColor          HIDDEN
   DATA oFont
   DATA oBold
   DATA oBoldVertical
   DATA cTitle
   DATA nTitleHeight        AS NUMERIC INIT 40
   DATA nClrTextSpecial     INIT CLR_WHITE
   DATA nClrHover           INIT RGB(255,69,0)
   DATA lOverTitle          INIT .F.
   DATA lOverPanel          INIT .F.
   DATA hRegion
   DATA nRound              INIT 6
   DATA lTransparent        AS LOGICAL INIT .F.
   DATA nOpacity            AS NUMERIC INIT 255
   DATA nTopColor           AS NUMERIC INIT RGB(153,204,255)
   DATA nBottomColor        AS NUMERIC INIT RGB(0,100,255)
   DATA nImageWidth         AS NUMERIC INIT 32
   DATA nImageHeight        AS NUMERIC INIT 32
   DATA nZeroZeroClr        AS NUMERIC
   DATA lGradient           AS LOGICAL INIT .T.
   DATA oBtnToggle
   DATA cBtnImage1
   DATA cBtnImage2
   DATA lBtnBitmap1         AS LOGICAL INIT .F.
   DATA lBtnBitmap2         AS LOGICAL INIT .F.
   DATA nTextAlign          HIDDEN
   DATA aRelatedNavigators
   DATA nBetWeenSpace       AS NUMERIC INIT 2
   DATA bToggled
   CLASSDATA lRegistered    AS LOGICAL

   METHOD New( nTop, nLeft, nBottom, nRight, oWnd, lBorder, nClrBorder,;
            nBackColor, nWidthClosed, cTitle, cImage, cBtnImage1, cBtnImage2,;
            nClrTextSpecial,nClrHover,nTitleHeight,nBetWeenSpace,lDesign, lPixels ) CONSTRUCTOR
    METHOD ReDefine(  nId, oWnd, lBorder, nClrBorder,;
            nBackColor, nWidthClosed, cTitle, cImage, cBtnImage1, cBtnImage2,;
            nClrTextSpecial,nClrHover,nTitleHeight,nBetWeenSpace,lDesign ) CONSTRUCTOR
   METHOD CloseAll()
   METHOD OpenAll()
   METHOD ToggleSize()
   METHOD Display()         INLINE ::BeginPaint(), ::Paint(), ::EndPaint(), 0
   METHOD Resize()
   METHOD Paint()
   METHOD PaintTitle( hDCMem)
   METHOD PaintBorder( hDCMem)
   METHOD PaintButton( hDCMem)
   METHOD PaintBackImage(hDCMem)
   METHOD MouseMove( nRow, nCol, nKeyFlags )
   METHOD MouseLeave( nRow, nCol, nFlags )
   //METHOD KeyDown( nKey, nFlags )
   METHOD LButtonUp( nRow, nCol, nFlags )
   METHOD EraseBkGnd( hDC ) INLINE ( ( hDC ), 1 )
   METHOD ChangeWidth( nWidth, nHeight )
   METHOD Move( nLeft, nTop, nWidth, nHeight, lRepaint )
   METHOD Adjust()
   METHOD CoorsUpdate()
   METHOD Destroy()
ENDCLASS

File: samples/misc/album.prg (L36-94)

Code (text): Select all Collapse
CLASS TAlbum

   DATA aPhotos
   DATA oWnd

   DATA nWndWidth  INIT 800
   DATA nWndHeight INIT 800
   DATA nImgWidth  INIT 210
   DATA nGutter    INIT 30
   DATA nImgCols PROTECTED
   DATA nOffset    INIT 0 PROTECTED
   DATA nHeight

   ACCESS oVScroll INLINE ::oWnd:oVScroll

   METHOD New( aPhotos ) CONSTRUCTOR
   METHOD Activate()

PROTECTED:
   METHOD CreateWindow()
   METHOD CreateControls()
   METHOD SetVScroll()
   METHOD GoUp()
   METHOD GoDown()
   METHOD ThumbPos( nPos )
   METHOD MouseWheel()
   METHOD VSetPos() INLINE ::oWnd:oVScroll:SetPos( -::nOffSet )
   METHOD GoTop()
   METHOD GoBottom()
   METHOD KeyDown( nKey )
   METHOD ScrollWnd( nPixels )
   METHOD Resize( nType, nWidth, nHeight )

ENDCLASS

//----------------------------------------------------------------------------//

METHOD New( aPhotos ) CLASS TAlbum

   ::aPhotos := aPhotos

return Self

//----------------------------------------------------------------------------//

METHOD Activate() CLASS TAlbum

   ::CreateWindow()
   ::CreateControls()
   ::SetVScroll()
   ::oWnd:bResized := { |t,w,h| ::Resize( t, w, h ) }

   if ::oWnd:IsKindOf( "MDICHILD" )
      ACTIVATE WINDOW ::oWnd
   else
      ACTIVATE WINDOW ::oWnd CENTERED
   endif

return Self

File: source/classes/metropnl.prg (L22-80)

Code (text): Select all Collapse
CLASS TMetroPanel FROM TPanel

   CLASSDATA lRegistered AS LOGICAL
   CLASSDATA oActive  // for internal use

   //
   CLASSDATA nBtnSize, nMetroRows, nMetroTop, nMetroMargin, nSliderTop
   //
   DATA  bOnMoveBtn
   //
   DATA  nOffset        INIT 0
   DATA  nScrollRange   INIT 0
   DATA  nScrollRatio   INIT 1
   DATA  oFont, oFontB
   DATA  oBtnFont, oTextFont
   DATA  nGroups        INIT 1
   DATA  aButtons       INIT Array(0)
   DATA  lArranged      INIT .f.
   DATA  lDesignMode    INIT .f.
   DATA  nClrScroll
   DATA  nClrThumb
   DATA  nMetroWidth, nThumbSize, nThumbWidth
   DATA  nThumbPos      INIT 60
   DATA  hPen

   DATA  cTitle
   DATA  nRow, nCol
   DATA  oParent

   // lDrag, nDragRow, nOldCol used for metro sliding by dragging on screen or scrollbar
   DATA  lDrag INIT .F.
   DATA  nDragRow
   DATA  nOldCol INIT 0

   DATA  nScrollBarTop

   METHOD New( oWnd, cTitle, nClrText, nClrPane, bLClicked, nBtnSize, ;
               nClrThumb, nClrScroll ) CONSTRUCTOR

   METHOD Paint()
   METHOD AddButton( lLarge, nGroup, cCaption, bAction, nClrText, nClrPane, cImgName, oFont, ;
                     nAlign, nBmpAlign, nBmpWidth, nBmpHeight, cText, nTextAlign, ;
                     oTextFont, oSubMetro, cBackImage, cAction, cSub )
   METHOD Show() INLINE ( ::Arrange(), ::oBrush:ReSize( Self ), ::Super:Show(), ::lVisible := .t. )
   METHOD Hide() INLINE ( ::Super:Hide(), ::lVisible := .f. )
   METHOD Arrange( lReArrange )

   METHOD LButtonDown( nRow, nCol, nFlags, lTouch )
   METHOD LButtonUp( nRow, nCol, nFlags )
   METHOD MouseMove( nRow, nCol, nFlags )

   METHOD MoveBtn( oBtnDrag, oBtnOver )
   METHOD SwitchTo( oNext )
   METHOD MouseWheel( nKey, nDelta, nXPos, nYPos )
   METHOD Slide( nPixels )
   METHOD ProgramCode( lShow )
   METHOD Destroy()

ENDCLASS

File: source/classes/scrlpanl.prg (L107-115)

Code (text): Select all Collapse
   METHOD LButtonDown( nRow, nCol, nFlags, lTouch )  INLINE ( ::lScrollDrag := .t., ::nOldRow := nRow, ::nOldCol := nCol, ::Super:LButtonDown( nRow, nCol, nFlags, lTouch ) )
   METHOD LButtonUp( nRow, nCol, nFlags )    INLINE ( ::lScrollDrag := .f., ::nOldRow := 0, ::nOldCol := 0, ::Super:LButtonUp( nRow, nCol, nFlags ) )
   METHOD MouseMove( nRow, nCol, nFlags )    INLINE ( ;
         if( !::lDrag, ;
         ( If( lAnd( nFlags, 1 ), nil, ( ::lScrollDrag := .f., ::nOldRow := 0, ::nOldCol := 0 ) ), ;
           If( ::lScrollDrag, ( If( nRow > ::nOldRow, ::GoUp( nRow - ::nOldRow ), ::GoDown( ::nOldRow - nRow ) ), ;
                               If( nCol > ::nOldCol, ::GoLeftPix( nCol - ::nOldCol ), ::GoRightPix( ::nOldCol - nCol ) ), ;
                               ::nOldRow := nRow, ::nOldCol := nCol ), nil ) ), ), ;
         ::Super:MouseMove( nRow, nCol, nFlags ) )

File: source/classes/scrlpanl.prg (L746-771)

Code (text): Select all Collapse
METHOD HandleGesture( nGesture, nLParam ) CLASS TScrollPanel

   static nPrevRow   := 0

   local aInfo, nRow


   if nGesture == GID_PAN
      aInfo     := GESTUREINFO( nLParam )
      if aInfo[ 1 ] == GID_PAN
         nRow  := aInfo[ 3 ]
         if aInfo[ 2 ] == GF_BEGIN
            nPrevRow    := nRow
         else
            if nRow > nPrevRow
               ::GoUp( nRow - nPrevRow )
            else
               ::GoDown( nPrevRow - nRow )
            endif
            nPrevRow    := nRow
         endif
         return 0
      endif
   endif

return ::Super:HandleGesture( nGesture, nLParam )
regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 257
Joined: Mon Jun 10, 2013 06:40 PM
Re: Para hacer scroll en pantalla touch
Posted: Wed Feb 18, 2026 04:59 PM

Antonio, buen dia Cambie de Version de FWH (2407) de un curso que nos diste.

Lo trabaje con TScrollPanel y funciono muy bien.

Saludos.

Posts: 537
Joined: Mon Jan 16, 2006 03:42 PM
Re: Para hacer scroll en pantalla touch
Posted: Fri Feb 27, 2026 01:54 PM

Lo puede hacer igual asi:

saludos

Posts: 257
Joined: Mon Jun 10, 2013 06:40 PM
Re: Para hacer scroll en pantalla touch
Posted: Sat Feb 28, 2026 02:50 AM

puse el TPanelscroll

Saludos.

Continue the discussion