Recapitulando
É TUDO EXEMPLO, não é pra usar exatamente igual.
Uma rotina principal do aplicativo
MEMVAR cnSQL
FUNCTION Main()
PUBLIC cnSQL := ConexaoMySQL()
Set( _SET_CODEPAGE, "PTISO" )
Set( _SET_EVENTMASK, INKEY_ALL + HB_INKEY_GTEVENT - INKEY_MOVE )
SET DATE BRITISH
SetMode(40,100)
SetColor( "W/B","N/W",,,"W/B" )
CLS
cnSQL:Open()
RotinaBrowse()
cnSQL:Close()
RETURN Nil
O módulo do aplicativo que vai usar o browse genérico.
FUNCTION RotinaBrowse()
LOCAL oRs, aCamposList
DO WHILE .T.
oRs := ADOExecute( cnSQL, "SELECT * FROM Any" )
aCamposList := { ;
{ "DATA", { || oRs:ToDate( "DATA" ) } }, ;
{ "HORA", { || oRs:ToString( "HORA", 8 ) } }, ;
{ "COMIDA", { || oRs:ToString( "COMIDA", 30 ) }, { | x | If( At( "TOTAL ", Upper( x ) ) > 0, { 5, 5 }, { 1, 2 } ) } }, ;
{ "QUANTIDADE", { || oRs:ToString( "QUANTIDADE", 20 ) } }, ;
{ "PONTOS", { || oRs:ToStr( "PONTOS", 6 ) } }, ;
{ "ID", { || oRs:ToStr( "ID", 6 ) } } }
BrowseADO( oRs, aCamposList, { | oBrowse, nKey | RotinaUsuario( oRs, oBrowse, nkey ) } )
* IF Alert( "Fechar?", { " Não ", " Sim " }, "W+/N" ) == 2
oRs:Close()
EXIT
* ENDIF
ENDDO
RETURN Nil
STATIC FUNCTION RotinaUsuario( oRs, oBrowse, nKey )
IF nKey == K_F5
Alert( "Foi teclado F5" )
Alert( oRs:ToString( "COMIDA" ) )
oBrowse:RefreshAll()
ENDIF
RETURN 1
A rotina de browse genérica.
#pragma -w3
#pragma -es2
#include "tbrowse.ch"
#include "inkey.ch"
#include "box.ch"
FUNCTION BrowseADO( oRs, aCamposList, bExecutaRotinaUsuario )
LOCAL oBrowse, nKey, oTela
IF oRs == Nil
hb_Alert( "Sem informações para exibição" )
RETURN Nil
ENDIF
SAVE SCREEN TO oTela
oBrowse := CriaBrowse( oRs, aCamposList )
DispBox( oBrowse:nTop - 1, oBrowse:nLeft - 1, oBrowse:nBottom + 3, oBrowse:nRight + 1, B_SINGLE )
DO WHILE .T.
oBrowse:refreshCurrent()
DO WHILE ! oBrowse:Stable()
oBrowse:Stabilize()
ENDDO
// Paint TBrowse current line...
//oBrowse:ColorRect( { oBrowse:RowPos, oBrowse:LeftVisible, oBrowse:RowPos, oBrowse:RightVisible }, { 2, 1 } )
@ MaxRow() - 1, 3 SAY Padr( " Registro " + Ltrim( Str( oRs:AbsolutePosition ) ) + " de " + Ltrim( Str( oRs:recordCount ) ) + " ", 20 ) COLOR "N/W"
nKey := Inkey(0)
IF oBrowse:applyKey( nKey ) == TBR_EXIT
EXIT
ENDIF
IF bExecutaRotinaUsuario != NIL
DO WHILE ! oBrowse:Stable
oBrowse:Stabilize()
ENDDO
Eval( bExecutaRotinaUsuario, oBrowse, nKey )
oBrowse:RefreshAll()
ENDIF
ENDDO
RESTORE SCREEN FROM oTela
RETURN Nil
STATIC FUNCTION CriaBrowse( oRs, aCamposList )
LOCAL oBrowse, oColumn, aItem, nLen, nCont
oBrowse := TBrowse():new( 02, 3, MaxRow() - 3, MaxCol() - 3 )
oBrowse:headSep := Chr(196) + Chr(194) + Chr(196)
oBrowse:colSep := " " + Chr(179) + " "
oBrowse:footSep := Chr(196) + Chr(193) + Chr(196)
oBrowse:goTopBlock := { || oRs:moveFirst() }
oBrowse:goBottomBlock := { || oRs:moveLast() }
oBrowse:skipBlock := { |n| ADORecordSetSkipper( oRs,n ) }
oBrowse:colorSpec := "W/B,W+/N,N/W*,W+/R,R+/B,R/W*"
IF aCamposList == Nil
nLen := oRs:fields():count() - 1
FOR nCont := 0 TO nLen
oColumn := TBColumnNew( oRs:fields( nCont ):name(), ADORecordSetFieldBlock( oRs, nCont ) )
oColumn:width := Max( Min( oRs:Fields( nCont ):definedSize,50), Len( oRs:fields( nCont ):name ) ) + 5
oBrowse:addColumn( oColumn )
NEXT
ELSE
FOR EACH aItem IN aCamposList
oColumn := TBColumnNew( aItem[1], aItem[2] )
IF Len( aItem ) > 2
oColumn:ColorBlock := aItem[3]
ENDIF
oBrowse:AddColumn( oColumn )
NEXT
ENDIF
RETURN oBrowse
STATIC FUNCTION ADORecordSetFieldBlock( oRs, i, xVal )
LOCAL bRet
IF xVal == NIL
IF oRs:Eof()
bRet := { || Space( Max( oRs:Fields( i ):DefinedSize , Len( oRs:Fields( i ):name ) ) ) }
ELSE
bRet := { || oRs:Fields( i ):value }
ENDIF
ELSE
bRet := { |xVal| oRs:Fields( i ):Value := xVal }
ENDIF
RETURN bRet
STATIC FUNCTION ADORecordSetSkipper(oRecordSet,nSkip)
LOCAL nRec := oRecordSet:AbsolutePosition
IF ! ( oRecordSet:eof )
oRecordSet:Move( nSkip )
IF oRecordSet:eof
oRecordSet:moveLast()
ENDIF
IF oRecordSet:bof
oRecordSet:moveFirst()
ENDIF
ENDIF
RETURN (oRecordSet:AbsolutePosition - nRec)
Rotinas pra facilitar o ADO
FUNCTION SuperADO( oRs )
__ObjAddMethod( oRs, "TOSTRING", @ADOToString() )
__ObjAddMethod( oRs, "TONUMBER", @ADOToNumber() )
__ObjAddMethod( oRs, "TODATE", @ADOToDate() )
__ObjAddMethod( oRs, "TOSTR", @ADOToStr() )
RETURN Nil
STATIC FUNCTION ADOToDate( cField )
LOCAL x, Self := QSelf()
x := ::Fields( cField ):Value
IF ValType( x ) != "D"
x := Ctod("")
ENDIF
RETURN x
STATIC FUNCTION ADOToString( cField, nLen )
LOCAL x, Self := QSelf()
x := ::Fields( cField ):Value
IF ValType( x ) != "C"
x := ""
ENDIF
IF nLen != Nil
x := Pad( x, nLen )
ENDIF
RETURN x
STATIC FUNCTION ADOToNumber( cField )
LOCAL x, Self := QSelf()
x := ::Fields( cField ):Value
IF ValType( x ) != "N"
x := 0
ENDIF
RETURN x
STATIC FUNCTION ADOToStr( cField, nLen, nDec )
LOCAL x, Self := QSelf()
x := ::Fields( cField ):Value
IF ValType( x ) != "N"
x := 0
ENDIF
IF nLen == Nil
x := Str( x )
ELSEIF nDec == Nil
x := Str( x, nLen )
ELSE
x := Str( x, nLen, nDec )
ENDIF
RETURN x
FUNCTION ConexaoMySQL()
LOCAL cServer := "mysql.xxx.com.br"
LOCAL cDatabase := "xxx"
LOCAL cUser := "xxx"
LOCAL cPassword := "xxx"
LOCAL cnSQL := win_OleCreateObject("ADODB.Connection")
cnSQL:ConnectionString := "DRIVER={MariaDB ODBC 3.0 Driver};TCPIP=1;SERVER=" + ;
cServer + ";Database=" + cDatabase + ";UID=" + cUser + ";PWD=" + cPassword + ";PORT=3306"
cnSQL:CursorLocation := 3
RETURN cnSQL
FUNCTION ADOExecute( cnSQL, cSQL )
LOCAL oRs
oRs := cnSQL:Execute( cSQL )
SuperADO( oRs )
RETURN oRs
Cada uma trata de "seu assunto".
Temos uma genérica pra browse, e uma genérica pra ADO.
As outras, são exemplos de rotinas comuns do aplicativo.
Se não quiser usar as rotinas pra facilitar o ADO, ou quiser usar outras, é só trocar.
Se quiser fazer o principal de outro jeito, é só fazer
Se quiser fazer o módulo de outro jeito, é só fazer.
Se quiser alterar o browse genérico para, por exemplo, poder escolher uma determinada posição na tela, é só alterar.
Mas separando "por assunto", é mexer só na parte que interessa mexer.
Deixando tudo junto, fica parecendo que é tudo uma coisa só, e acaba programando tudo dependente um do outro, ou só servindo pra uma rotina.