Using vscode + Copilot Agent and the techniques that we are going to review in the webinar, here you have a modified FWH Class TScrollPanel that supports horizontal scrolling:
/*
*
* ScrlPanl.prg
* Author: GNRao,India + enhancements by Copilot Agent
* 08-07-2009 08:48 PM
*
*/
#include "FiveWin.Ch"
#define GWL_STYLE -16
#define GWL_EXSTYLE -20
#define CS_DBLCLKS 8
#define MK_MBUTTON 0x0010
#define MK_SHIFT 0x0004
static lVScrolled := .f.
static lHScrolled := .f.
//------------------------------------------------------------------//
CLASS TScrollPanel FROM TPanel
CLASSDATA lRegistered AS LOGICAL
DATA aPages INIT Array( 0 )
DATA vStep INIT 20
DATA hStep INIT 20
DATA oCtrlTop
DATA oCtrlBot
DATA nCtrlTopTop
DATA nCtrlBotTop
// Horizontal scroll support
DATA oCtrlLeft
DATA oCtrlRight
DATA nCtrlLeftLeft
DATA nCtrlRightLeft
// Margins to be left from right & bottom of Parent window when resized
DATA nRightMargin INIT 0
DATA nBottomMargin INIT 0
DATA nScrollRange
DATA nHScrollRange
DATA aSays INIT Array( 0 )
// Scroll By Drag DATA
DATA lScrollDrag INIT .f.
DATA nOldRow INIT 0
DATA nOldCol INIT 0
//
METHOD New( nTop, nLeft, nBottom, nRight, oWnd, lNoBorder ) CONSTRUCTOR
METHOD Resize( nSizeType, nWidth, nHeight )
METHOD CheckResize()
ACCESS nCtrlHt INLINE ( ::oCtrlBot:nTop + ::oCtrlBot:nHeight - ::oCtrlTop:nTop )
ACCESS nCtrlWd INLINE ( ::oCtrlRight:nLeft + ::oCtrlRight:nWidth - ::oCtrlLeft:nLeft )
ACCESS nPos INLINE Max(1, ( ::nCtrlTopTop - ::oCtrlTop:nTop ) )
ACCESS nHPos INLINE Max(1, ( ::nCtrlLeftLeft - ::oCtrlLeft:nLeft ) )
METHOD vScroll( nWParam, nLParam )
METHOD hScroll( nWParam, nLParam )
METHOD vSetPos()
METHOD hSetPos()
METHOD MouseWheel( nKeys, nDelta, nXPos, nYPos )
METHOD GoTop() INLINE ( ::ScrollBy( ::nCtrlTopTop - ::oCtrlTop:nTop, 0 ), ::oVScroll:SetPos( 1 ) )
METHOD GoBottom() INLINE ( ::ScrollBy( -::oCtrlBot:nTop, 0 ), ::oVScroll:SetPos( ::oVScroll:GetRange()[ 2 ] ) )
METHOD GoLeft() INLINE ( ::ScrollBy( 0, ::nCtrlLeftLeft - ::oCtrlLeft:nLeft ), ::oHScroll:SetPos( 1 ) )
METHOD GoRight() INLINE ( ::ScrollBy( 0, -::oCtrlRight:nLeft ), ::oHScroll:SetPos( ::oHScroll:GetRange()[ 2 ] ) )
METHOD GoUp( nPix )
METHOD GoDown( nPix )
METHOD GoLeftPix( nPix )
METHOD GoRightPix( nPix )
METHOD GoToPos( nPos )
METHOD GoToHPos( nPos )
METHOD PageUp() INLINE ::GoUp( 2 * ::vStep )
METHOD PageDown() INLINE ::GoDown( 2 * ::vStep )
METHOD PageLeft() INLINE ::GoLeftPix( 2 * ::hStep )
METHOD PageRight() INLINE ::GoRightPix( 2 * ::hStep )
METHOD ControlIntoView( oControl )
METHOD SetRange()
METHOD ScrollBy( nPixV, nPixH )
METHOD SetPage( cPage, nRow ) INLINE AAdd( ::aPages, { Upper( AllTrim( cPage ) ), nRow } )
METHOD GoToPage( cPage )
METHOD NcMouseMove( nHitTestCode, nRow, nCol )
METHOD Display() INLINE ( ::BeginPaint(), ::Paint(), ::EndPaint(), 0 )
METHOD Paint()
METHOD PaintText( nItem )
METHOD AddText( nRow, nCol, nWidth, nHeight, cbText, cPicture, oFont, ;
lTransparent, nClrText, nClrBack, nAlign )
// METHOD GotFocus( hCtlLost )
// METHOD GoNextCtrl( hCtrl )
// METHOD GoPrevCtrl( hCtrl )
// Scroll By Drag METHODS
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 ) )
METHOD HandleGesture( nGesture, nLParam )
//
METHOD cGenPrg( lDlgUnits )
ENDCLASS
//------------------------------------------------------------------//
METHOD New( nTop, nLeft, nBottom, nRight, oWnd, lNoBorder ) CLASS TScrollPanel
// ::oWnd:bMouseWheel := { | nKeys, nDelta, nXPos, nYPos | ::MouseWheel( nKeys, nDelta, nXPos, nYPos ) }
DEFAULT nTop := 0, nLeft := 0, nBottom := 100, nRight := 100,;
oWnd := GetWndDefault(), lNoBorder := .f.
::lUnicode = FW_SetUnicode()
::nTop = nTop
::nLeft = nLeft
::nBottom = nBottom
::nRight = nRight
::oWnd = oWnd
::nStyle = nOr( WS_CHILD, WS_VSCROLL, WS_HSCROLL,;
WS_VISIBLE, WS_TABSTOP, WS_CLIPCHILDREN )
::lDrag = .F.
::nClrPane = CLR_WHITE //GetSysColor( COLOR_BTNFACE )
if ! lNoBorder
::nStyle := nOr( ::nStyle, WS_BORDER )
endif
::Register( nOr( CS_VREDRAW, CS_HREDRAW, CS_DBLCLKS ) )
if ! Empty( ::oWnd:hWnd )
::Create()
::oWnd:AddControl( Self )
if ::oWnd:oBrush != nil
::SetBrush( ::oWnd:oBrush )
endif
else
::oWnd:DefControl( Self )
endif
DEFINE SCROLLBAR ::oVScroll VERTICAL OF Self RANGE 1,2
DEFINE SCROLLBAR ::oHScroll HORIZONTAL OF Self RANGE 1,2
::oWnd:OnResize := { || ::CheckResize() }
RETURN Self
//------------------------------------------------------------------//
METHOD ReSize( nSizeType, nWidth, nHeight ) CLASS TScrollPanel
if !::lDrag
::vSetPos() // nHeight )
endif
return ::Super:ReSize( nSizeType, nWidth, nHeight )
//------------------------------------------------------------------//
METHOD CheckResize() CLASS TScrollPanel
local aRect := GetClientRect( ::oWnd:hWnd )
local nHeight, nWidth
if ::nBottomMargin > 0 .or. ::nRightMargin > 0
if ::oWnd:oBottom != nil
aRect[ 3 ] -= ::oWnd:oBottom:nHeight
elseif ::oWnd:oMsgBar != nil
aRect[ 3 ] -= ::oWnd:oMsgBar:nHeight
endif
nHeight := aRect[ 3 ] - aRect[ 1 ] - ::nTop - ::nBottomMargin //- 28
nWidth := aRect[ 4 ] - aRect[ 2 ] - ::nLeft - ::nRightMargin
if nHeight != ::nHeight .or. nWidth != ::nWidth
if ::nBottomMargin > 0
::nHeight := nHeight
endif
if ::nRightMargin > 0
::nWidth := nWidth
endif
endif
endif
return nil
//----------------------------------------------------------------------------//
METHOD SetRange() CLASS TScrollPanel
local oTop, oBot, oLeft, oRight, oCtrl, nTop, nBot, nLeft, nRight
if Len( ::aControls ) > 0
oTop := oBot := oLeft := oRight := ::aControls[ 1 ]
nTop := oTop:nTop
nBot := oBot:nTop + oBot:nHeight
nLeft := oLeft:nLeft
nRight := oRight:nLeft + oRight:nWidth
for each oCtrl in ::aControls
if oCtrl:nTop < nTop
oTop := oCtrl
nTop := oTop:nTop
endif
if oCtrl:nTop + oCtrl:nHeight > nBot
oBot := oCtrl
nBot := oBot:nTop + oBot:nHeight
endif
if oCtrl:nLeft < nLeft
oLeft := oCtrl
nLeft := oLeft:nLeft
endif
if oCtrl:nLeft + oCtrl:nWidth > nRight
oRight := oCtrl
nRight := oRight:nLeft + oRight:nWidth
endif
if lAnd( GetWindowLong( oCtrl:hWnd, GWL_STYLE ), WS_TABSTOP ) .and. ;
! oCtrl:IsKindOf( "TCOMBOBOX" )
oCtrl:bGotFocus := { |o| If( lVScrolled,,::ControlIntoView( o )), lVScrolled := .f. }
endif
next
::oCtrlTop := oTop
::oCtrlBot := oBot
::oCtrlLeft := oLeft
::oCtrlRight := oRight
::nCtrlTopTop := ::oCtrlTop:nTop
::nCtrlBotTop := ::oCtrlBot:nTop
::nCtrlLeftLeft := ::oCtrlLeft:nLeft
::nCtrlRightLeft := ::oCtrlRight:nLeft
::nScrollRange := ::nCtrlBotTop
::nHScrollRange := ::nCtrlRightLeft
::oVScroll:SetRange( 1, ::nScrollRange )
::oHScroll:SetRange( 1, ::nHScrollRange )
::vSetPos()
::hSetPos()
endif
return Self
//----------------------------------------------------------------------------//
METHOD vSetPos() CLASS TScrollPanel
::oVScroll:SetPos( Max( 1, ::nCtrlTopTop - ::oCtrlTop:nTop ) )
return Self
//----------------------------------------------------------------------------//
METHOD hSetPos() CLASS TScrollPanel
::oHScroll:SetPos( Max( 1, ::nCtrlLeftLeft - ::oCtrlLeft:nLeft ) )
return Self
//------------------------------------------------------------------//
METHOD ScrollBy( nPixV, nPixH ) CLASS TScrollPanel
DEFAULT nPixV := 0, nPixH := 0
if ! Empty( nPixV ) .or. ! Empty( nPixH )
if ! Empty( ::aSays )
if ! Empty( nPixV )
AEval( ::aSays, { |a| a[ 1 ][ 1 ] += nPixV, a[ 1 ][ 3 ] += nPixV } )
endif
if ! Empty( nPixH )
AEval( ::aSays, { |a| a[ 1 ][ 2 ] += nPixH, a[ 1 ][ 4 ] += nPixH } )
endif
::Refresh()
endif
ScrollWindow( ::hWnd, nPixH, nPixV, 0, GetClientRect( ::hWnd ) )
endif
return nil
//----------------------------------------------------------------------------//
METHOD GoUp( nPix ) CLASS TScrollPanel
DEFAULT nPix := ::vStep
nPix := Min( nPix, ::nCtrlTopTop - ::oCtrlTop:nTop )
if nPix > 0
::ScrollBy( nPix, 0 )
::oVScroll:SetPos( ::nPos )
endif
return Self
//------------------------------------------------------------------//
METHOD GoDown( nPix ) CLASS TScrollPanel
DEFAULT nPix := ::vStep
nPix := Min( nPix, ::oCtrlBot:nTop )
if nPix > 0
::ScrollBy( -nPix, 0 )
::oVScroll:SetPos( ::nPos )
endif
return Self
//------------------------------------------------------------------//
METHOD GoLeftPix( nPix ) CLASS TScrollPanel
DEFAULT nPix := ::hStep
nPix := Min( nPix, ::nCtrlLeftLeft - ::oCtrlLeft:nLeft )
if nPix > 0
::ScrollBy( 0, nPix )
::oHScroll:SetPos( ::nHPos )
endif
return Self
//------------------------------------------------------------------//
METHOD GoRightPix( nPix ) CLASS TScrollPanel
DEFAULT nPix := ::hStep
nPix := Min( nPix, ::oCtrlRight:nLeft )
if nPix > 0
::ScrollBy( 0, -nPix )
::oHScroll:SetPos( ::nHPos )
endif
return Self
//------------------------------------------------------------------//
METHOD GoToPos( nPos ) CLASS TScrollPanel
local nPix
nPix := ::nCtrlTopTop - nPos - ::oCtrlTop:nTop
if nPix != 0
::ScrollBy( nPix, 0 )
::oVScroll:SetPos( ::nPos )
endif
return Self
//------------------------------------------------------------------//
METHOD GoToHPos( nPos ) CLASS TScrollPanel
local nPix
nPix := ::nCtrlLeftLeft - nPos - ::oCtrlLeft:nLeft
if nPix != 0
::ScrollBy( 0, nPix )
::oHScroll:SetPos( ::nHPos )
endif
return Self
//------------------------------------------------------------------//
METHOD VScroll( nWParam, nLParam ) CLASS TScrollPanel
local nScrHandle := nLParam
local nScrollCode := nLoWord( nWParam )
local nPos := nHiWord( nWParam )
lVScrolled := .t.
if GetFocus() != ::hWnd
SetFocus( ::hWnd )
endif
if nScrHandle == 0 .and. ::oVScroll != nil
do case
case nScrollCode == SB_LINEUP
::GoUp()
case nScrollCode == SB_LINEDOWN
::GoDown()
case nScrollCode == SB_PAGEUP
::PageUp()
case nScrollCode == SB_PAGEDOWN
::PageDown()
case nScrollCode == SB_TOP
::GoTop()
case nScrollCode == SB_BOTTOM
::GoBottom()
case nScrollCode == SB_THUMBPOSITION .or. ;
nScrollCode == SB_THUMBTRACK
do case
case nPos == 1
::GoTop()
case nPos == ::oVScroll:GetRange()[ 2 ]
::GoBottom()
otherwise
::GoToPos( nPos )
endcase
otherwise
return nil
endcase
lVScrolled := .t.
endif
return 0
//----------------------------------------------------------------------------//
METHOD HScroll( nWParam, nLParam ) CLASS TScrollPanel
local nScrHandle := nLParam
local nScrollCode := nLoWord( nWParam )
local nPos := nHiWord( nWParam )
lHScrolled := .t.
if GetFocus() != ::hWnd
SetFocus( ::hWnd )
endif
if nScrHandle == 0 .and. ::oHScroll != nil
do case
case nScrollCode == SB_LINELEFT
::GoLeftPix()
case nScrollCode == SB_LINERIGHT
::GoRightPix()
case nScrollCode == SB_PAGELEFT
::PageLeft()
case nScrollCode == SB_PAGERIGHT
::PageRight()
case nScrollCode == SB_LEFT
::GoLeft()
case nScrollCode == SB_RIGHT
::GoRight()
case nScrollCode == SB_THUMBPOSITION .or. ;
nScrollCode == SB_THUMBTRACK
do case
case nPos == 1
::GoLeft()
case nPos == ::oHScroll:GetRange()[ 2 ]
::GoRight()
otherwise
::GoToHPos( nPos )
endcase
otherwise
return nil
endcase
lHScrolled := .t.
endif
return 0
//----------------------------------------------------------------------------//
METHOD MouseWheel( nKeys, nDelta, nXPos, nYPos ) CLASS TScrollPanel
local aPoint := { nYPos, nXPos }
if !::lDrag
ScreenToClient( ::hWnd, aPoint )
if IsOverWnd( ::hWnd, aPoint[ 1 ], aPoint[ 2 ] )
if lAnd( nKeys, MK_MBUTTON )
if nDelta > 0
::PageUp()
else
::PageDown()
endif
elseif lAnd( nKeys, MK_SHIFT ) // Shift + Mouse wheel para scroll horizontal
if nDelta > 0
::GoLeftPix( WheelScroll() * ::hStep )
else
::GoRightPix( WheelScroll() * ::hStep )
endif
else
if nDelta > 0
::GoUp( WheelScroll() * ::vStep )
else
::GoDown( WheelScroll() * ::vStep )
endif
endif
endif
endif
Return nil
//----------------------------------------------------------------------------//
METHOD NcMouseMove( nHitTestCode, nRow, nCol ) CLASS TScrollPanel
TWindow():NcMouseMove( nHitTestCode, nRow, nCol )
return nil
//----------------------------------------------------------------------------//
METHOD GoToPage( cPage ) CLASS TScrollPanel
local lSuccess := .f.
local nAt
cPage := Upper( AllTrim( cPage ) )
nAt := AScan( ::aPages, { |a| a[ 1 ] == cPage } )
if nAt > 0
::GoToPos( ::aPages[ nAt ][ 2 ] )
lSuccess := .t.
endif
return lSuccess
//----------------------------------------------------------------------------//
METHOD ControlIntoView( oControl ) CLASS TScrollPanel
local nCtrlBottom, nPanelBottom, nCtrlRight, nPanelRight
local lMoved := .f.
// Verificar scroll vertical
if oControl:nTop < 0
::GoUp( -oControl:nTop )
lMoved := .t.
else
nPanelBottom := GetClientRect( ::hWnd )[ 3 ]
nCtrlBottom := oControl:nTop + oControl:nHeight
if nCtrlBottom > nPanelBottom
::GoDown( nCtrlBottom - nPanelBottom )
lMoved := .t.
endif
endif
// Verificar scroll horizontal
if oControl:nLeft < 0
::GoLeftPix( -oControl:nLeft )
lMoved := .t.
else
nPanelRight := GetClientRect( ::hWnd )[ 4 ]
nCtrlRight := oControl:nLeft + oControl:nWidth
if nCtrlRight > nPanelRight
::GoRightPix( nCtrlRight - nPanelRight )
lMoved := .t.
endif
endif
return lMoved
//----------------------------------------------------------------------------//
METHOD Paint() CLASS TScrollPanel
local aInfo, aRect
aInfo := ::DispBegin()
// ::CheckResize()
if ::lTransparent .or. ::nOpacity < 255
aRect := GetClientRect( ::hWnd )
SetBrushOrgEx( ::hDC, -::nLeft, -::nTop )
FillRect( ::hDC, aRect, ::oWnd:oBrush:hBrush )
if ! ::lTransparent
FillRectEx( ::hDC, aRect, nARGB( ::nOpacity, ::nClrPane ) )
endif
else
::PaintBack( ::hDC )
endif
::PaintText()
if ValType( ::bPainted ) == "B"
Eval( ::bPainted, ::hDC, ::cPS, Self )
endif
::DispEnd( aInfo )
return nil
//----------------------------------------------------------------------------//
METHOD AddText( nRow, nCol, nWidth, nHeight, cbText, cPicture, oFont, ;
lTransparent, nClrText, nClrBack, nAlign ) CLASS TScrollPanel
DEFAULT lTransparent := .t., nAlign := 0
AAdd( ::aSays, { { nRow, nCol, nRow + nHeight, nCol + nWidth }, ;
cbText, cPicture, oFont, lTransparent, nClrText, nClrBack, nAlign } )
return Len( ::aSays )
//----------------------------------------------------------------------------//
METHOD PaintText( nItem ) CLASS TScrollPanel
local n, nLen
local oFont, nColor, cText
local aSay
if nItem == nil
nLen := Len( ::aSays )
for n := 1 to nLen
::PaintText( n )
next n
return nil
endif
aSay := ::aSays[ nItem ]
if aSay[ 1 ][ 3 ] < 0 .or. aSay[ 1 ][ 1 ] > ::nHeight
return nil
endif
cText := If( ValType( aSay[ 2 ] ) == 'B', Eval( aSay[ 2 ] ), aSay[ 2 ] )
cText := If( Empty( aSay[ 3 ] ), cValToChar( cText ), Transform( cText, aSay[ 3 ] ) )
oFont := If( Empty( aSay[ 4 ] ), ::oFont, aSay[ 4 ] )
nColor := If( Empty( aSay[ 6 ] ), ::nClrText, aSay[ 6 ] )
oFont:Activate( ::hDC )
SetTextColor( ::hDC, nColor )
n := SetBkMode( ::hDC, 1 ) // TRANSPARENT
DrawTextEx( ::hDC, cText, aSay[ 1 ], aSay[ 8 ] )
SetBkMode( ::hDC, n ) // restore bkmode
oFont:DeActivate( ::hDC )
return nil
//----------------------------------------------------------------------------//
/*
METHOD GotFocus( hCtlLost ) CLASS TScrollPanel
::Super:GotFocus( hCtlLost )
if ! Empty( ::hCtlFocus )
SetFocus( ::hCtlFocus )
else
::hCtlFocus = NextDlgTab( ::hWnd ) // ,::aControls[ 1 ]:hWnd
SetFocus( ::hCtlFocus )
endif
return nil
//----------------------------------------------------------------------------//
METHOD GoNextCtrl( hCtrl ) CLASS TScrollPanel
local nAt, hNext
local nNext := 0
nAt := AScan( ::aControls, { | o | o:hWnd == hCtrl } )
if nAt > 0
hNext := NextDlgTab( ::hWnd, hCtrl )
nNext := AScan( ::aControls, { |o| o:hWnd == hNext } )
::hCtlFocus := hCtrl
if nNext < nAt .and. Len( ::oWnd:aControls ) > 1
::oWnd:GoNextCtrl( ::hWnd )
else
SetFocus( hNext )
endif
endif
return nil
//----------------------------------------------------------------------------//
METHOD GoPrevCtrl( hCtrl ) CLASS TScrollPanel
local nAt, hPrev
local nPrev := 0
nAt := AScan( ::aControls, { | o | o:hWnd == hCtrl } )
if nAt > 0
hPrev := NextDlgTab( ::hWnd, hCtrl, .t. )
nPrev := AScan( ::aControls, { |o| o:hWnd == hPrev } )
::hCtlFocus := hCtrl
if ( nPrev == 0 .or. nPrev > nAt ) .and. Len( ::oWnd:aControls ) > 1
::oWnd:GoPrevCtrl( ::hWnd )
else
SetFocus( hPrev )
endif
endif
return nil
//----------------------------------------------------------------------------//
*/
/*
METHOD GoPrevCtrl( hCtrl ) CLASS TScrollPanel
local hCtlPrev := NextDlgTab( ::hWnd, hCtrl, .t. )
local oNext, n, cFoldName, nAt
nAt = AScan( ::aControls, { | o | o:hWnd == hCtrl } )
if nAt != 0
nAt := If( nAt > 1, nAt - 1, Len( ::aControls ) )
do while !( oNext := ::aControls[ nAt ] ):WinStyle( WS_TABSTOP ) .or. !oNext:lWhen()
nAt := If( nAt > 1, nAt - 1, Len( ::aControls ) )
enddo
SetFocus( ::aControls[ nAt ]:hWnd )
return nil
endif
return nil
//----------------------------------------------------------------------------//
*/
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 )
//----------------------------------------------------------------------------//
METHOD cGenPrg( lDlgUnits ) CLASS TScrollPanel
local cSource := ""
local nFactorX, nFactorY
DEFAULT lDlgUnits := .T.
if ::oWnd:IsKindOf( "TDIALOG" )
lDlgUnits := .T.
endif
nFactorX = If( lDlgUnits, 4 / nLoWord( GetDlgBaseUnits() ), 1 )
nFactorY = If( lDlgUnits, 8 / nHiWord( GetDlgBaseUnits() ), 1 )
::CoorsUpdate()
cSource += CRLF + " " + ::cVarName + " := " + ;
"TScrollPanel():New( " + ;
AllTrim( Str( ::nTop * nFactorX ) ) + ", " + ;
AllTrim( Str( ::nLeft * nFactorY ) ) + ", " + ;
AllTrim( Str( ::nBottom * nFactorX ) ) + ", " + ;
AllTrim( Str( ::nRight * nFactorY ) ) + ", " + ;
::oWnd:cVarName + ", .F. ) " + CRLF
cSource += " " + ::cVarName + ":SetRange()" + CRLF + CRLF
if ! Empty( ::aControls )
AEval( ::aControls, { | oCtrl | cSource += oCtrl:cGenPRG( lDlgUnits ) } )
endif
return cSource
//----------------------------------------------------------------------------//
#include "Fivewin.ch"
#include "TGraph.ch"
FUNCTION MAIN()
LOCAL oDlg, oGraph, oScrPanel
DEFINE WINDOW oDlg;
SIZE 800, 600;
TITLE "Ejemplo Gráfico de Barras con Scroll Horizontal"
// Crear panel scrolleable usando TScrollPanel
oScrPanel := TScrollPanel():New( 10, 10, 550, 780, oDlg, .F. )
// Gráfico más ancho para acomodar todas las barras
@ 10, 10 GRAPH oGraph OF oScrPanel;
SIZE 1400, 350;
TYPE GRAPH_TYPE_BAR;
YVALUES XGRID YGRID XVALUES LEGENDS
// Configuración de series
oGraph:aSeries = { { "Ventas 2022-2024", CLR_BLUE, GRAPH_TYPE_BAR, .T. } }
// Etiquetas del eje Y (meses y trimestres de varios años)
oGraph:aYVals = { "Ene 2022", "Feb 2022", "Mar 2022", "Abr 2022", "May 2022", "Jun 2022",;
"Jul 2022", "Ago 2022", "Sep 2022", "Oct 2022", "Nov 2022", "Dic 2022",;
"Ene 2023", "Feb 2023", "Mar 2023", "Abr 2023", "May 2023", "Jun 2023",;
"Jul 2023", "Ago 2023", "Sep 2023", "Oct 2023", "Nov 2023", "Dic 2023",;
"Ene 2024", "Feb 2024", "Mar 2024", "Abr 2024", "May 2024", "Jun 2024",;
"Jul 2024", "Ago 2024", "Sep 2024", "Oct 2024", "Nov 2024", "Dic 2024" }
// Datos del gráfico (valores de ventas de 3 años - 36 barras)
oGraph:aData = { { 15000, 18500, 22000, 19500, 25000, 28000,;
24000, 26500, 23000, 21000, 19500, 32000,;
16000, 19000, 24000, 21500, 27000, 31000,;
26000, 28500, 25000, 23000, 21500, 35000,;
18000, 21000, 26000, 23500, 29000, 33000,;
28000, 30500, 27000, 25000, 23500, 38000 } }
// Configuración adicional
oGraph:nClrX = CLR_BLACK // Color del eje X
oGraph:nClrY = CLR_BLACK // Color del eje Y
oGraph:l3D = .T. // Activar vista 3D
oGraph:lViewSRLegend = .T. // Mostrar leyenda
// Tooltip personalizado
oGraph:cToolTip = {|oGph,nSerie,nPos,nVal| ;
oGph:aSeries[nSerie][1] + CRLF + ;
oGraph:aYVals[nPos] + ": $" + Transform(nVal, "999,999")}
// IMPORTANTE: Configurar el rango del scroll panel después de crear todos los controles
oScrPanel:SetRange()
ACTIVATE WINDOW oDlg;
CENTER
RETURN NIL