Olá!
Alexandre Santos escreveu:
// O code block abaixo define a cor das colunas 3 (comida) e 5 (pontos).
//
// Um code block, em xBase, é um tipo de dados como outro qualquer
// da linguagem. Assim como o tipo date armazena datas, o numeric
// números, etc..., o code block armazena uma peça de código executável.
// Esta peça de código pode ser uma chamada simples a uma função ou
// até mesmo o conteúdo completo de um arquivo .PRG. Code blocks são
// semelhantes a expressões macro (&) mas muito mais rápidos pois são
// resolvidos em tempo de compilação, ao passo que macros são compiladas
// em tempo de execução.
// Code blocks sozinhos não fazem nada, alem de armazenar o conteúdo.
// Para executar o código que armazenam, dependem de funções que manipulam
// code blocks (AEval(), AScan(), ASort(), DbEval(), Eval(), HEval()).
//
// No caso do code block abaixo, "x" é uma vaiável LOCAL criada e visÃvel
// apenas dentro do code block, durante sua execução. Ela serve para
// receber um parâmetro, como em uma função qualquer. Ex: f(x).
// "x" é apenas o nome da variável (parâmetro) e poderia ser qualquer
// outro nome válido para variáveis em Harbour como, por exemplo,
// ? Eval( { |celula| QOut( celula ) } ) -> exibirá na tela o conteúdo passado
// para o parâmetro "celula".
// ? Eval( { |x,y| QOut( x + y ) } ) -> exibirá na tela a soma de x e y.
//
// Um TBrowse exibe, em formato tabular, os dados da fonte de dados a ele
// associada e possui um objeto TBColumn para cada coluna a ser exibida.
// A interseção de uma linha e uma coluna é chamada de célula.
// Entre outras informações, os objetos TBColumn opcionalmente armazenam
// as cores e formatos (pictures) a serem aplicados a cada célula, além
// do bloco de recuperação de dados da coluna.
// O code block abaixo será o "color block" das colunas 3 e 5 do TBrowse.
// Durante o processo de estabilização do TBrowse, as linhas de dados
// são lidas da fonte de dados (pode ser DBF, Array, ADO), é feito o
// cálculo de quantas linhas caberão na janela definida para o TBrowse,
// conforme a posição do registro atual da fonte de dados. Definidos
// os registros que serão exibidos na tela, inicia-se o processo de
// pintura dos dados, linha a linha e coluna a coluna. Durante este
// processo, para cada célula é avaliado o code block de recuperação de
// dados da coluna Eval( oColumn:block ). O resultado desta operação
// traz o conteúdo da célula, que é então passado para outros métodos
// existentes no objeto TBColumn. O code block abaixo, está armazenado
// na variável colorBlock de cada objeto TBColumn do browse. No momento
// da pintura das células, este valor (conteúdo da célula) é passado para
// o code block abaixo e é recebido pelo mesmo como o parâmetro "x".
bColor := ;
{ |x| If( At( "TOTAL ", Upper( Eval( oBrowse:getColumn( 3 ):block ) ) ) > 0, { 5, 5 }, { 1, 2 } ) }
/*
Exibição das linhas de um Record set ADO usando TBrowseDB()
Alexandre Santos
Compilar: Hbmk2 tbado hbwin.hbc
*/
#pragma -w3
#pragma -es2
#include "tbrowse.ch"
#include "inkey.ch"
#include "setcurs.ch"
#include "hbgtinfo.ch"
#include "box.ch"
#include "set.ch"
#include "hbclass.ch"
#include "ado.ch"
REQUEST HB_CODEPAGE_PTISO
FUNCTION Tbrowseado(cSql)
LOCAL oRs, aCamposList
LOCAL oCN :=ConexaoMySQL( "xxx.com.br", "xxx", "xxx", "xxx" )
LOCAL tela :=savescreen(0,0,maxrow(),maxcol())
LOCAL oBrowse, bColor, bUserFunction
// coloquei aqui o meu SQL para teste...
cSQL := If( cSQL == NIL, "SELECT * FROM tbDieta;", cSQL )
Set( _SET_CODEPAGE, "PTISO" )
Set( _SET_EVENTMASK, INKEY_ALL + HB_INKEY_GTEVENT - INKEY_MOVE )
SET DATE BRITISH
SetMode( 35, 90 )
* hb_gtInfo( HB_GTI_WINTITLE , "TBrowse colorBlock() com Acesso ao MySQL via ADO" )
* hb_gtInfo( HB_GTI_FONTNAME , "Lucida Console" )
SetColor( "W/B","N/W",,,"W/B" )
CLS
// O code block abaixo define a cor das colunas 3 (comida) e 5 (pontos).
//
// Um code block, em xBase, é um tipo de dados como outro qualquer
// da linguagem. Assim como o tipo date armazena datas, o numeric
// números, etc..., o code block armazena uma peça de código executável.
// Esta peça de código pode ser uma chamada simples a uma função ou
// até mesmo o conteúdo completo de um arquivo .PRG. Code blocks são
// semelhantes a expressões macro (&) mas muito mais rápidos pois são
// resolvidos em tempo de compilação, ao passo que macros são compiladas
// em tempo de execução.
// Code blocks sozinhos não fazem nada, alem de armazenar o conteúdo.
// Para executar o código que armazenam, dependem de funções que manipulam
// code blocks (AEval(), AScan(), ASort(), DbEval(), Eval(), HEval()).
//
// No caso do code block abaixo, "x" é uma vaiável LOCAL criada e visÃvel
// apenas dentro do code block, durante sua execução. Ela serve para
// receber um parâmetro, como em uma função qualquer. Ex: f(x).
// "x" é apenas o nome da variável (parâmetro) e poderia ser qualquer
// outro nome válido para variáveis em Harbour como, por exemplo,
// ? Eval( { |celula| QOut( celula ) } ) -> exibirá na tela o conteúdo passado
// para o parâmetro "celula".
// ? Eval( { |x,y| QOut( x + y ) } ) -> exibirá na tela a soma de x e y.
//
// Um TBrowse exibe, em formato tabular, os dados da fonte de dados a ele
// associada e possui um objeto TBColumn para cada coluna a ser exibida.
// A interseção de uma linha e uma coluna é chamada de célula.
// Entre outras informações, os objetos TBColumn opcionalmente armazenam
// as cores e formatos (pictures) a serem aplicados a cada célula, além
// do bloco de recuperação de dados da coluna.
// O code block abaixo será o "color block" das colunas 3 e 5 do TBrowse.
// Durante o processo de estabilização do TBrowse, as linhas de dados
// são lidas da fonte de dados (pode ser DBF, Array, ADO), é feito o
// cálculo de quantas linhas caberão na janela definida para o TBrowse,
// conforme a posição do registro atual da fonte de dados. Definidos
// os registros que serão exibidos na tela, inicia-se o processo de
// pintura dos dados, linha a linha e coluna a coluna. Durante este
// processo, para cada célula é avaliado o code block de recuperação de
// dados da coluna Eval( oColumn:block ). O resultado desta operação
// traz o conteúdo da célula, que é então passado para outros métodos
// existentes no objeto TBColumn. O code block abaixo, está armazenado
// na variável colorBlock de cada objeto TBColumn do browse. No momento
// da pintura das células, este valor (conteúdo da célula) é passado para
// o code block abaixo e é recebido pelo mesmo como o parâmetro "x".
bColor := ;
{ |x| If( At( "TOTAL ", Upper( Eval( oBrowse:getColumn( 3 ):block ) ) ) > 0, { 5, 5 }, { 1, 2 } ) }
aCamposList := { ;
{ "DATA", { || oRs:ToDate( "DATA" ) } }, ;
{ "HORA", { || oRs:ToString( "HORA", 8 ) } }, ;
{ "COMIDA", { || oRs:ToString( "COMIDA", 30 ) }, bColor }, ;
{ "QUANTIDADE", { || oRs:ToString( "QUANTIDADE", 20 ) } }, ;
{ "PONTOS", { || oRs:ToStr( "PONTOS", 6 ) }, bColor }, ;
{ "ID", { || oRs:ToStr( "ID", 6 ) } } }
//@ 4, MaxRow() SAY Padr( "Obtendo informa‡?es...", 22 ) COLOR "W+/W"
@ 4, MaxCol() SAY Padr( "Obtendo informa‡?es...", 22 ) COLOR "W+/W"
oCn:open()
oRs := oCn:Execute( cSql )
IF oRs == NIL .OR. oRs:Eof()
Hb_Alert( "N?o foi poss¡vel obter dados para exibi‡?o",, "W+/B" )
RETURN NIL
ENDIF
SuperADO( oRs )
oBrowse := CriaBrowse( 2, 2, MaxRow() - 5, MaxCol() - 2, oRs, aCamposList )
bUserFunction := { |oBrowse, aCamposList, nKey| RotinaUsuario( oBrowse, aCamposList, nKey ) }
TBrowseADO2( oBrowse, oRs, aCamposList, bUserFunction )
If oRs != NIL .And. oRs:state() = adStateOpen
oRs:close()
Endif
If oCn != NIL .And. oCn:state = adStateOpen
oCn:close()
Endif
oCn := NIL
oRs := NIL
rest scre from tela
RETURN Nil
FUNCTION TBrowseADO2( oBrowse, oRs, aCamposList, bRotinaUsuario )
//LOCAL oBrowse, nKey
LOCAL nKey, nRetCode
//oBrowse := CriaBrowse( oRs, aCamposList )
DispBox( oBrowse:nTop - 1, oBrowse:nLeft - 1, oBrowse:nBottom, 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 } )
// ... and current cell in different colors
If ( oBrowse:colPos == 3 .Or. oBrowse:colPos == 5 ) .And. At( "TOTAL ", Upper( Eval( oBrowse:getColumn( 3 ):block ) ) ) > 0
oBrowse:ColorRect( { oBrowse:rowPos, oBrowse:colPos, oBrowse:rowPos, oBrowse:colPos }, { 7, 7 } )
Else
oBrowse:ColorRect( { oBrowse:rowPos, oBrowse:colPos, oBrowse:rowPos, oBrowse:colPos }, { 3, 2 } )
Endif
@ oBrowse:nBottom + 2, 3 SAY Padr( " Registro " + Ltrim( Str( oRs:AbsolutePosition ) ) + " de " + Ltrim( Str( oRs:recordCount ) ) + " ", 20 ) COLOR "N/W"
nKey := Inkey(0)
IF ( nRetCode := oBrowse:applyKey( nKey ) ) == TBR_EXIT
EXIT
ELSEIF nRetCode == TBR_EXCEPTION
IF Valtype( bRotinaUsuario ) == "B"
DO WHILE ! oBrowse:Stable
oBrowse:Stabilize()
ENDDO
// Note que um code block se comporta como um objeto...
// invoca o m‚todo Eval() do code block
bRotinaUsuario:eval( oBrowse, oRs, nKey )
oBrowse:RefreshAll()
ENDIF
ENDIF
ENDDO
RETURN Nil
STATIC FUNCTION CriaBrowse( nTop, nLeft, nBottom, nRight, oRs, aCamposList )
LOCAL oBrowse, oColumn, aItem, nLen, nCont
// TODO: colocar valores default em nTop, nLeft, nBottom, nRight
//oBrowse := TBrowse():new( 02, 3, MaxRow() - 3, MaxCol() - 3 )
oBrowse := TBrowse():new( nTop, nLeft, nBottom, nRight )
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,N/GR*,N/W*,W+/R,R+/B,R/W*,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)
STATIC FUNCTION ConexaoMySQL( cServer, cDatabase, cUser, cPassword )
LOCAL oCn := win_OleCreateObject("ADODB.Connection")
oCn:ConnectionString := "DRIVER={MariaDB ODBC 3.1 Driver};TCPIP=1;SERVER=" + ;
cServer + ";Database=" + cDatabase + ";UID=" + cUser + ";PWD=" + cPassword + ";PORT=3306"
oCn:CursorLocation := 3
RETURN oCn
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
STATIC FUNCTION RotinaUsuario( oBrowse, oRs, nKey )
IF nKey == K_F5
Alert( "Foi teclado F5;;Coluna 'COMIDA' = " + oRs:ToString( "COMIDA" ) )
ENDIF
RETURN 1