Clipper On Line • Ver Tópico - Browse com ADO
Página 1 de 8

Browse com ADO

MensagemEnviado: 26 Nov 2019 13:07
por JoséQuintas
A origem é deste post, do Alexandre Santos (AlxSts)

http://www.pctoledo.com.br/forum/viewtopic.php?f=45&t=15328&hilit=sql+server

Como está na resposta de outra coisa, talvez fique difícil de ser localizado o browse para ADO.
Aqui fiz algumas mudanças.
É um browse simples, sem qualquer tipo de filtro ou opção especial.
Só usar um browse de DBFs como referência, e adicionar recursos.

Para o recordset, usei o nome de oTemporario, fica claro pra quem não usa ADO, o que ele representa.

#include "tbrowse.ch"

PROCEDURE Main

LOCAL oConexao, oTemporario, oTBrowse

oConexao := ConexaoMySql()
oConexao:Open()
oTemporario := oConexao:Execute( "SELECT CODIGO, NOME, ENDERECO FROM CLIENTES ORDER BY NOME" )
oTBrowse := { ;
   { "CODIGO", { || Pad( oTemporario:Fields( "CODIGO" ):Value, 10 ) } }, ;
   { "NOME",  { || Pad( oTemporario:Fields( "NOME" ):Value, 30 ) } }, ;
   { "ENDERECO", { || Pad( oTemporario:Fields( "ENDERECO" ):Value, 30 ) } } }
BrowseADO( oTemporario, oTBrowse )

oTemporario:Close()
oConexao:Close()
RETURN

FUNCTION BrowseADO( oTemporario, oTBrowse )

LOCAL oBrowse, nKey, oElement

oBrowse := TBrowseDB():new( 04, 3, MaxRow() - 7, MaxCol() - 3 )

oBrowse:goTopBlock  := { || oTemporario:moveFirst() }
oBrowse:goBottomBlock := { || oTemporario:moveLast() }
oBrowse:skipBlock  := { | n | ADOSkipper( oTemporario, n ) }

FOR EACH oElement IN oTBrowse
   oBrowse:AddColumn( TBColumnNew( oElement[ 1 ], oElement[ 2 ] ) )
NEXT

DO WHILE .T.
   oBrowse:forceStable()
   oBrowse:ColorRect( { oBrowse:RowPos, oBrowse:LeftVisible, oBrowse:RowPos, oBrowse:RightVisible }, { 2, 1 } )
   oBrowse:ColorRect( { oBrowse:RowPos, oBrowse:ColPos, oBrowse:RowPos, oBrowse:ColPos }, { 3, 2 } )
   oBrowse:refreshCurrent()
   nKey := Inkey(0)
   DO CASE
   CASE oBrowse:ApplyKey( nKey ) == TBR_EXIT
    EXIT
   ENDCASE
ENDDO

RETURN NIL

STATIC FUNCTION ADOSkipper( oTemporario, nSkip )

LOCAL nRec := oTemporario:AbsolutePosition

IF ! ( oTemporario:Eof )
   oTemporario:Move( nSkip )
   IF oTemporario:Eof
    oTemporario:moveLast()
   ENDIF
   IF oTemporario:Bof
    oTemporario:moveFirst()
   ENDIF
ENDIF

RETURN oTemporario:AbsolutePosition - nRec

FUNCTION ConexaoMySql()

LOCAL oConexao := win_OleCreateObject( "ADODB.Connection" )

oConexao:ConnectionString := "colocar_a_string"
oConexao:CursorLocation := 3 // adUseClient
oConexao:CommandTimeOut := 600
oConexao:ConnectionTimeOut := 600
RETURN oConexao


Provavelmente vão querer adicionar opções de:
codeblock a executar, filtrar colunas, cores no tbrowse, navegação por mouse, filtro enquanto digita, etc, mas de um modo geral isso pode ser encontrado em qualquer browse de DBF.

Browse com ADO

MensagemEnviado: 26 Nov 2019 13:13
por JoséQuintas
Pra que serve esse browse:

pode ser planilha Excel, Access, MySQL, SQL Server, Firebird, Oracle, e qualquer coisa que possua ODBC disponível.

Browse com ADO

MensagemEnviado: 26 Nov 2019 19:46
por JoséQuintas
Tem uma coisa interessante nesse browse:

CASE oBrowse:ApplyKey( nKey ) == TBR_EXIT


Substitui tudo isto, ou pelo menos a parte padrão.

      CASE nkey == K_CTRL_PGDN ;  oBrowse:GoBottom() ; LOOP
      CASE nkey == K_CTRL_PGUP ;  oBrowse:GoTop() ;    LOOP
      CASE nkey == K_DOWN ;       oBrowse:Down()    ;  LOOP
      CASE nkey == K_HOME ;       oBrowse:GoTop() ;    LOOP
      CASE nkey == K_END ;        oBrowse:GoBottom() ; LOOP
      CASE nkey == K_LEFT ;       oBrowse:Left() ;     LOOP
      CASE nkey == K_RIGHT ;      oBrowse:Right() ;    LOOP
      CASE nkey == K_PGDN ;       oBrowse:PageDown() ; LOOP
      CASE nkey == K_PGUP ;       oBrowse:PageUp() ;   LOOP
      CASE nkey == K_UP ;         oBrowse:Up() ;       LOOP
      CASE nKey == K_ESC;   EXIT


Acaba deixando a rotina de browse mais enxuta.
Não sei se alguém reparou nisso.
É o que digo sempre: todo fonte pode ter dicas interessantes, é sempre bom olhar com atenção.

Browse com ADO

MensagemEnviado: 27 Nov 2019 12:49
por JoséQuintas
Nota: editei o fonte anterior, estava com um erro no BrowseADO(), pra não gerar problemas depois.

Aqui um exemplo completo, que basta compilar.

#include "tbrowse.ch"
#include "directry.ch"
#define AD_BIGINT   20
#define AD_DATE     7
#define AD_VARCHAR  200

PROCEDURE Main

   LOCAL oTemporario, oTBrowse, oFile, aList

   SetMode( 40, 100 )
   SetCOlor( "W/B","N/w",,,"W/B" )
   CLS
   // cria estrutura
   oTemporario := win_OleCreateObject( "ADODB.Recordset" )
   WITH OBJECT oTemporario:Fields
      :Append( "NOME", AD_VARCHAR, 100 )
      :Append( "TAMANHO", AD_BIGINT, 11 )
      :Append( "DATA", AD_DATE )
      :Append( "HORA", AD_VARCHAR, 8 )
   ENDWITH
   // grava informação
   WITH OBJECT oTemporario
      :Open()
      aList := Directory( "*.*" )
      FOR EACH oFile IN aList
         :AddNew()
         :Fields( "NOME" ):Value := oFile[ F_NAME ]
         :Fields( "TAMANHO" ):Value := oFile[ F_SIZE ]
         :Fields( "DATA" ):Value := oFile[ F_DATE ]
         :Fields( "HORA" ):Value := oFile[ F_TIME ]
         :Update()
      NEXT
   ENDWITH
   oTemporario:MoveFirst()

   oTBrowse := { ;
      { "NOME",     { || Pad( oTemporario:Fields( "NOME" ):Value, 20 ) } }, ;
      { "TAMANHO",  { || Str( oTemporario:Fields( "TAMANHO" ):Value, 20 ) } }, ;
      { "DATA",     { || oTemporario:Fields( "DATA" ):Value } }, ;
      { "HORA",     { || oTemporario:Fields( "HORA" ):Value } } }
   BrowseADO( oTemporario, oTBrowse )

   oTemporario:Close()

   RETURN

FUNCTION BrowseADO( oTemporario, oTBrowse )

   LOCAL oBrowse, nKey, oElement

   oBrowse := TBrowseDB():new( 04, 3, MaxRow() - 7, MaxCol() - 3 )

   oBrowse:goTopBlock  := { || oTemporario:moveFirst() }
   oBrowse:goBottomBlock := { || oTemporario:moveLast() }
   oBrowse:skipBlock  := { | n | ADOSkipper( oTemporario, n ) }

   FOR EACH oElement IN oTBrowse
      oBrowse:AddColumn( TBColumnNew( oElement[ 1 ], oElement[ 2 ] ) )
   NEXT

   DO WHILE .T.
      oBrowse:forceStable()
//      oBrowse:ColorRect( { oBrowse:RowPos, oBrowse:LeftVisible, oBrowse:RowPos, oBrowse:RightVisible }, { 2, 1 } )
//      oBrowse:ColorRect( { oBrowse:RowPos, oBrowse:ColPos, oBrowse:RowPos, oBrowse:ColPos }, { 3, 2 } )
//      oBrowse:refreshCurrent()
      nKey := Inkey(0)
      DO CASE
      CASE oBrowse:ApplyKey( nKey ) == TBR_EXIT
         EXIT
      ENDCASE
   ENDDO

   RETURN NIL

STATIC FUNCTION ADOSkipper( oTemporario, nSkip )

   LOCAL nRec := oTemporario:AbsolutePosition

   IF ! ( oTemporario:Eof )
      oTemporario:Move( nSkip )
      IF oTemporario:Eof
         oTemporario:moveLast()
      ENDIF
      IF oTemporario:Bof
         oTemporario:moveFirst()
      ENDIF
   ENDIF

   RETURN oTemporario:AbsolutePosition - nRec


test1.png


test2.png

Browse com ADO

MensagemEnviado: 27 Nov 2019 13:06
por JoséQuintas
Faltou acrescentar:

Como dá pra perceber, dá pra usar ADO pra temporários também.
Gostei tanto do browse com ADO, que comecei a usar em outras situações.
Não precisa arquivo em disco, e o Windows se vira com isso.

Quando virar programa gráfico... só usar algum grid/browse equivalente pra ADO...

Pra usar MySQL ou SQL Server ou outro.... não precisa criar nem gravar no temporário, vém pronto do MySQL ou outro.

Algo mais legal ainda:
NÃO vou usar, mas..... no VB6 tem o Crystal Reports e o outro da Microsoft, pra gerar relatórios a partir do recordset ADO.
Poderia ter relatórios automáticos a partir desses recordsets !!!
Ou talvez NET mesmo, já que é grátis... quem sabe....

Browse com ADO

MensagemEnviado: 05 Dez 2019 12:53
por JoséQuintas
Esse negócio do browse ADO tá muito legal.

Imaginem substituir tudo que é Achoice()* por esse browse.....

Se pesquisar pela inicial já era interessante.... filtrar por qualquer texto é muito melhor...

E fica tudo padronizado, pro usuário ficar craque nisso.... ou sentir falta do recurso, se trocar de aplicativo... rs

Browse com ADO

MensagemEnviado: 15 Dez 2019 00:35
por cjp
Por favor, preciso de ajuda neste Browse com ADO, com um pequeno detalhe:

Meu código:

      oTBrowse := TBrowseDB():new( 05, 3, MaxRow() - 7, MaxCol() - 2 )

      oTBrowse:goTopBlock    := { || oRs:moveFirst() }
      oTBrowse:goBottomBlock := { || oRs:moveLast() }
      oTBrowse:skipBlock     := { | n | ADORecordSetSkipper( oRs, n ) }

      nLen := oRs:fields():count() - 1
      FOR i := 0 TO nLen
         oColumn       := TBColumnNew( oRs:fields(i):name(), ADORecordSetFieldBlock( oRs, i ) )
         oColumn:width := Max( Min( oRs:Fields(i):definedSize,50), Len( oRs:fields(i):name ) )
         oTBrowse:addColumn( oColumn )
      NEXT


Só preciso alterar uma pequena coisa: alterar o campo data (primeiro campo), que não está aparecendo completo. Imagino que o problema seja nesta linha:

         oColumn:width := Max( Min( oRs:Fields(i):definedSize,50), Len( oRs:fields(i):name ) )


Mas não sei como alterá-la para corrigir este problema.

Podem me ajudar?

Browse com ADO

MensagemEnviado: 15 Dez 2019 11:24
por JoséQuintas
O Browse deste post não tem esse problema.

A saída pra esse outro é ir ajustando conforme a necessidade.
Exemplo:

IF ValType( oRs:Fields(i):Value ) != "D"
   nFieldLen := Min( oRs:Fields(I):DefinedSize, 50 )
   oColumn:Width := Max( nFieldLen, Len( oRs:fields(i):name ) )
ENDIF


ou

IF ValType( oRs:Fields(i):Value ) == "D"
   nFieldLen := Len( Dtoc( Date() ) )
ELSE
   nFieldLen := Min( oRs:Fields(I):DefinedSize, 50 )
ENDIF
oColumn:Width := Max( nFieldLen, Len( oRs:fields(i):name ) )

Browse com ADO

MensagemEnviado: 15 Dez 2019 14:56
por cjp
Resolveu, muito obrigado.

Browse com ADO

MensagemEnviado: 16 Dez 2019 16:23
por cjp
Teria como colocar divisores entre as colunas, como no velho browse()?

Browse com ADO

MensagemEnviado: 16 Dez 2019 23:13
por JoséQuintas
Sim, é só usar as variáveis que existem no tbrowse pra isso.

   oBrowse:HeadSep       := Chr(196)
   oBrowse:ColSep        := Chr(179)
   oBrowse:FootSep       := ""

Browse com ADO

MensagemEnviado: 17 Dez 2019 00:53
por cjp
Deu certo, muito obrigado.

Browse com ADO

MensagemEnviado: 18 Dez 2019 23:29
por cjp
Estou tentando expandir meu uso desse browse, e surgiram duas necessidades:

1) como faço para mostrar no browse apenas alguns campos, não todos?

2) como faço para editar um registro? Na verdade só preciso ler o registro inteiro, não quero alterá-lo.

Browse com ADO

MensagemEnviado: 19 Dez 2019 14:39
por JoséQuintas
cjp escreveu:1) como faço para mostrar no browse apenas alguns campos, não todos?


Caso não tenha percebido, o browse deste post é pra isso.

cjp escreveu:2) como faço para editar um registro? Na verdade só preciso ler o registro inteiro, não quero alterá-lo.


Acho que quer ter acesso ao registro atual.
Como o recordset fica na variável, é só usar a variável.

Browse com ADO

MensagemEnviado: 21 Dez 2019 00:55
por cjp
Desculpe, eu não fui claro antes.

Eu preciso editar um campo, mas o problema é saber qual é o campo escolhido pelo usuário para isso.

No velho dbedit(), usava modo e coluna para isso. No tbrowse tem algo semelhante?

Browse com ADO

MensagemEnviado: 21 Dez 2019 11:44
por JoséQuintas
não uso isso, vai precisar dar uma olhada nas variáveis do tbrowse, em algum help do Clipper.
Ou... no fonte do browse do Harbour, ou em algum fonte de tbrowse do fórum.

Browse com ADO

MensagemEnviado: 13 Mar 2020 22:41
por JoséQuintas
Faltou colocar: com WITH OBJECT simplifica um pouco digitar também:

 oTemporario := oConexao:Execute( "SELECT CODIGO, NOME, ENDERECO FROM CLIENTES ORDER BY NOME" )
oTBrowse := { ;
   { "CODIGO", { || Pad( oTemporario:Fields( "CODIGO" ):Value, 10 ) } }, ;
   { "NOME",  { || Pad( oTemporario:Fields( "NOME" ):Value, 30 ) } }, ;
   { "ENDERECO", { || Pad( oTemporario:Fields( "ENDERECO" ):Value, 30 ) } } }
BrowseADO( oTemporario, oTBrowse )
oTemporario:Close()


Usando WITH OBJECT não precisa colocar oTemporario:Isto, oTemporario:Aquilo, basta :Isto, :Aquilo

 oTemporario := oConexao:Execute( "SELECT CODIGO, NOME, ENDERECO FROM CLIENTES ORDER BY NOME" )
WITH OBJECT oTemporario
oTBrowse := { ;
   { "CODIGO", { || Pad( :Fields( "CODIGO" ):Value, 10 ) } }, ;
   { "NOME",  { || Pad( :Fields( "NOME" ):Value, 30 ) } }, ;
   { "ENDERECO", { || Pad( :Fields( "ENDERECO" ):Value, 30 ) } } }
BrowseADO( oTemporario, oTBrowse )
:Close()
ENDWITH

Browse com ADO

MensagemEnviado: 14 Mar 2020 13:54
por Fernando queiroz
      cQuery:= "SELECT LOGGERAL_NUMNOT, LOGGERAL_CODPRO, LOGGERAL_DATMOV, LOGGERAL_TIPMOV, LOGGERAL_CODVEN, LOGGERAL_CLIFOR, LOGGERAL_QUANT, LOGGERAL_VALUNI, LOGGERAL_OPERADOR from loggeral"
      oTemporario := oCn:EXECUTE(cQuery)   
      

      INIT DIALOG oDlg TITLE "Log Geral - Consulta"  ;
         ICON MEMVAR->SGC_ICON  ;
         AT 0, 0 SIZE 1167,600 CLIPPER  NOEXIT 

      ThisBRW := oDlg      
      
      @ 4,70 BROWSE oBrowse1 ARRAY OF oDlg SIZE 1160,460 STYLE WS_BORDER + WS_VSCROLL +WS_HSCROLL ;
            ON SIZE ANCHOR_TOPABS + ANCHOR_LEFTABS + ANCHOR_RIGHTABS + ANCHOR_BOTTOMABS       

         oBrowse1:oStyleHead := HStyle():New( { 0xffffff, 0xbbbbbb }, 1,, 0.4, 16759929 )
         oBrowse1:oFont := HFont():Add( '',0,-15,700,,,)         
         oBrowse1:aArray := oTemporario
         oBrowse1:AddColumn( HColumn():New( "Nr.NOTA",{|v,o|o:aArray[o:nCurrent,1]},"C",16,0,.F., ) )
         oBrowse1:AddColumn( HColumn():New( "Codigo",{|v,o|o:aArray[o:nCurrent,2]},"C",10,0,.F., ) )
         oBrowse1:AddColumn( HColumn():New( "Movimento",{|v,o|o:aArray[o:nCurrent,3]},"D",12,0,.F., ) )
         oBrowse1:AddColumn( HColumn():New( "Tipo",{|v,o|o:aArray[o:nCurrent,4]},"N",1,0,.F., ) )
         oBrowse1:AddColumn( HColumn():New( "Vendedor",{|v,o|o:aArray[o:nCurrent,5]},"N",4,0,.F., ) )
         oBrowse1:AddColumn( HColumn():New( "Cli/For",{|v,o|o:aArray[o:nCurrent,6]},"C",10,0,.F., ) )
         oBrowse1:AddColumn( HColumn():New( "Quantidade",{|v,o|o:aArray[o:nCurrent,7]},"N",14,2,.F., ) )
         oBrowse1:AddColumn( HColumn():New( "Valor Unit.",{|v,o|o:aArray[o:nCurrent,8]},"N",14,2,.F., ) )
         oBrowse1:AddColumn( HColumn():New( "Operador",{|v,o|o:aArray[o:nCurrent,9]},"C",20,0,.F., ) )

      @ 8,-1 TOOLBAR oToolbar1  SIZE 1160,40 ;
         oToolbar1:AddButton("EXIT16BMP", , 4, 16, "Sair" ,{|| DBCLOSEALL(), oDlg:Close() },'Sair da rotina','', "oToolbutton14")
         oToolbar1:CreateTool()

      ACTIVATE DIALOG oDlg CENTER   

      oCn:Close()

RETURN NIL

STATIC FUNCTION MySqlConnection( cServer, cDatabase, cUser, cPassword, nPort )

   LOCAL cnConnection

   hb_Default( @nPort, 3306 )

   cnConnection:= win_OleCreateObject( "ADODB.Connection" )
   cnConnection:ConnectionString := iif( win_OsIs10(), "Provider=MSDASQL;", "" )
   cnConnection:ConnectionString += "Driver={MariaDB ODBC 3.1 Driver};"
   cnConnection:ConnectionString += ;
      "Server=" + cServer + ";" + ;
      "Port=" + Ltrim( Str( nPort ) ) + ";" + ;
      "Stmt=;" + ;
      "Database=" + cDatabase + ";" + ;
      "User=" + cUser + ";" + ;
      "Password=" + cPassword + ";" + ;
      "Collation=utf8_general_ci;" + ;
      "AUTO_RECONNECT=1;" + ;
      "COMPRESSED_PROTO=0;" + ;
      "PAD_SPACE=1"
   cnConnection:CursorLocation    := 3
   cnConnection:CommandTimeOut    := 600 // seconds
   cnConnection:ConnectionTimeOut := 600 // seconds

   RETURN cnConnection

STATIC FUNCTION win_OsIs10(); RETURN .T.


Fiz o código acima mas não estou tendo resultados, acontece o erro

Error WINOLE/1016 Argument error (DOS Error -2147352562)
Called from ->WIN_OLEAUTO:__OPARRAYINDEX(0)
Called from CONSULTALOGGERALMARIADB.PRG->LOGGERALMARIADB(40) essa linha (oBrowse1:AddColumn( HColumn():New( "Nr.NOTA",{|v,o|o:aArray[o:nCurrent,1]},"C",16,0,.F., ) ))
Called from SGC.PRG->(b)MAIN(367)
Called from source\winapi\htool.prg->HTOOLBAR:NOTIFY(414)
Called from source\winapi\hcwindow.prg->ONNOTIFY(263)
Called from source\winapi\hcwindow.prg->(b)(_INITSTATICS00005)(0)
Called from source\winapi\hcwindow.prg->HWINDOW:ONEVENT(191)
Called from source\winapi\hdialog.prg->HDIALOG:ONEVENT(219)
Called from ->HWG_DLGBOXINDIRECT(0)
Called from source\winapi\hdialog.prg->HDIALOG:ACTIVATE(156)
Called from SGC.PRG->MAIN(930)

HWGUI 2.22 Build 4
Date:14/03/2020
Time:11:52:33

alguém que possa dar uma ajuda , pois não sei o que retorna da query, to perdido

Browse com ADO

MensagemEnviado: 14 Mar 2020 14:43
por JoséQuintas
O SELECT retorna o recorset do ADO, no formato do ADO.

oRs := cn:Execute( "SELECT CODIGO, NOME.... " )
DO WHILE ! oRs:Eof()
   ? oRs:Fields( "CODIGO" ):Value // ou oRs:Fields( 0 ):Value
   ? oRs:Fields( "NOME" ):Value  // ou oRs:Fields( 1 ):Value
  oRs:MoveNext()
ENDDO
oRs:Close()


Acho que tá confundindo com hbMySql() que retorna como array.

Browse com ADO

MensagemEnviado: 17 Mar 2020 12:51
por Fernando queiroz
consegui fazer a coisa funcionar
MARIADB + ADO + HWGUI

/*
TITULO     : SISTEMA DE GEST¦O DE COMERCIO
DATA       : 14/03/2020
PROGRAMA   : CONSULTALOGGERAL.PRG
COMENTARIO : CONSULTA LOG GERAL COM MARIADB
*/
#pragma -w0
#pragma -es0

#include "hwgui.ch"
******************************************
FUNCTION LOGGERALMARIADB(  )
******************************************

LOCAL oDlg;
   , oLabel1, oLabel2, oLabel3;
   , obusca, oBrowse1 ;
   , oToolbar1;
   , oToolbutton1, oToolbutton2, oToolbutton3, oToolbutton4;
   , oDatepicker1 , oDatepicker2 ;
   , oColuna, bColorBlock ;
   , vBusca := "";
   , oQuery, oRow;
   , aArray, oElemento;
   , aResult:= {}

   
PRIVATE   cProgressKey:="" ,dDatepicker1:=(m->dat_hoje - 30), dDatepicker2:=m->dat_hoje, lFiltro:=.T., nCODPRO:=0;
      , oLabel5 :="",  oLabel7 :="", oLabel10 :="", oLabel11 :="", oLabel6 :="", oLabel9 :="", oLabel12 :="", oLabel18 :=""

   
   oServer := MySqlConnection( "192.168.15.200", "", "sgcroot", "20r13uqse" )
   oServer:Open()
   oServer:Execute( "USE AMADEU")
   oQuery := oServer:Execute( "SELECT LOGGERAL_NUMNOT,";
                              + "LOGGERAL_CODPRO,";
                              + "LOGGERAL_DATMOV,";
                              + "LOGGERAL_TIPMOV,";
                              + "LOGGERAL_CODVEN,";
                              + "LOGGERAL_CLIFOR,";
                              + "LOGGERAL_QUANT,";
                              + "LOGGERAL_VALUNI,";
                              + "LOGGERAL_OPERADOR ";
                        + "from loggeral LIMIT 9" )

   DO WHILE ! oQuery:Eof()
      aAdd( aResult, {oQuery:Fields( "LOGGERAL_NUMNOT" ):Value,;
                  oQuery:Fields( "LOGGERAL_CODPRO" ):Value,;
                  oQuery:Fields( "LOGGERAL_DATMOV" ):Value,;
                  oQuery:Fields( "LOGGERAL_TIPMOV" ):Value,;
                  oQuery:Fields( "LOGGERAL_CODVEN" ):Value,;
                  oQuery:Fields( "LOGGERAL_CLIFOR" ):Value,;
                  oQuery:Fields( "LOGGERAL_QUANT" ):Value,;
                  oQuery:Fields( "LOGGERAL_VALUNI" ):Value,;
                  oQuery:Fields( "LOGGERAL_OPERADOR" ):Value} )

      oQuery:MoveNext()
   ENDDO
   oQuery:Close()

   
      INIT DIALOG oDlg TITLE "Log Geral - Consulta"  ;
         ICON MEMVAR->SGC_ICON  ;
         AT 0, 0 SIZE 1167,600 CLIPPER  NOEXIT 

      ThisBRW := oDlg   
      
      @ 4,70 BROWSE oBrowse1 ARRAY OF oDlg SIZE 1160,460 STYLE WS_BORDER + WS_VSCROLL +WS_HSCROLL ;
            ON SIZE ANCHOR_TOPABS + ANCHOR_LEFTABS + ANCHOR_RIGHTABS + ANCHOR_BOTTOMABS    

         oBrowse1:oStyleHead := HStyle():New( { 0xffffff, 0xbbbbbb }, 1,, 0.4, 16759929 )
         oBrowse1:oFont := HFont():Add( '',0,-15,700,,,)         
         oBrowse1:aArray := aResult   

   
         oBrowse1:AddColumn( HColumn():New( "Nr.Nota",hwg_ColumnArBlock(),"C",12,0,.F., ) )
         oBrowse1:AddColumn( HColumn():New( "Codigo",hwg_ColumnArBlock(),"C",12,0,.F., ) )
         oBrowse1:AddColumn( HColumn():New( "Movimento",hwg_ColumnArBlock(),"C",12,0,.F., ) )
         oBrowse1:AddColumn( HColumn():New( "Tipo",hwg_ColumnArBlock(),"C",1,0,.F., ) )
         oBrowse1:AddColumn( HColumn():New( "Vendedor",hwg_ColumnArBlock(),"C",4,0,.F., ) )
         oBrowse1:AddColumn( HColumn():New( "Cli/For",hwg_ColumnArBlock(),"C",10,0,.F., ) )
         oBrowse1:AddColumn( HColumn():New( "Quantidade",hwg_ColumnArBlock(),"C",14,0,.F., ) )
         oBrowse1:AddColumn( HColumn():New( "Valor Unit.",hwg_ColumnArBlock(),"C",14,0,.F., ) )
         oBrowse1:AddColumn( HColumn():New( "Operador",hwg_ColumnArBlock(),"C",20,0,.F., ) )
         

      @ 8,-1 TOOLBAR oToolbar1  SIZE 1160,40 ;
         
//         oToolbar1:AddButton("BRW_FIL", , 4, 16, "Aplica" ,{||FILTROLOGGERAL(  ),obrowse1:REFRESH()},'Aplica Filtro no Arquivo de Log Geral','', "oToolbutton1")
//         oToolbar1:AddButton("BRW_DFIL", , 4, 16, "Remove" ,{||REMOVEFILTROLOGGERAL(  ),obrowse1:REFRESH()},'Remover Filtro do Arquivo de Log Geral','', "oToolbutton2")
         oToolbar1:AddButton("EXIT16BMP", , 4, 16, "Sair" ,{|| DBCLOSEALL(), oDlg:Close() },'Sair da rotina','', "oToolbutton14")
         oToolbar1:CreateTool()

      ACTIVATE DIALOG oDlg CENTER   

      oServer:Close()

RETURN NIL

FUNCTION MySqlConnection( cServer, cDatabase, cUser, cPassword, nPort )

   LOCAL cnConnection

   hb_Default( @nPort, 3306 )

   cnConnection:= win_OleCreateObject( "ADODB.Connection" )
   cnConnection:ConnectionString := iif( win_OsIs10(), "Provider=MSDASQL;", "" )
   cnConnection:ConnectionString += "Driver={MariaDB ODBC 3.1 Driver};"
   cnConnection:ConnectionString += ;
      "Server=" + cServer + ";" + ;
      "Port=" + Ltrim( Str( nPort ) ) + ";" + ;
      "Stmt=;" + ;
      "Database=" + cDatabase + ";" + ;
      "User=" + cUser + ";" + ;
      "Password=" + cPassword + ";" + ;
      "Collation=utf8_general_ci;" + ;
      "AUTO_RECONNECT=1;" + ;
      "COMPRESSED_PROTO=0;" + ;
      "PAD_SPACE=1"
   cnConnection:CursorLocation    := 3
   cnConnection:CommandTimeOut    := 600 // seconds
   cnConnection:ConnectionTimeOut := 600 // seconds

   RETURN cnConnection

FUNCTION win_OsIs10(); RETURN .T.


A TELA FICOU ASSIM , FALTA AJUSTES MAS ja deu uma boa iluminada

tela.jpg

Browse com ADO

MensagemEnviado: 17 Mar 2020 13:48
por alxsts
Olá!

Parabéns!

Dicas:

1 - Sempre declare as variáveis antes de as utilizar.

2 - Procure nunca usar variáveis PRIVATE e PUBLIC. Use LOCAL ou STATIC

3 - Este bloco de código
   DO WHILE ! oQuery:Eof()
      aAdd( aResult, {oQuery:Fields( "LOGGERAL_NUMNOT" ):Value,;
                  oQuery:Fields( "LOGGERAL_CODPRO" ):Value,;
                  oQuery:Fields( "LOGGERAL_DATMOV" ):Value,;
                  oQuery:Fields( "LOGGERAL_TIPMOV" ):Value,;
                  oQuery:Fields( "LOGGERAL_CODVEN" ):Value,;
                  oQuery:Fields( "LOGGERAL_CLIFOR" ):Value,;
                  oQuery:Fields( "LOGGERAL_QUANT" ):Value,;
                  oQuery:Fields( "LOGGERAL_VALUNI" ):Value,;
                  oQuery:Fields( "LOGGERAL_OPERADOR" ):Value} )

      oQuery:MoveNext()
   ENDDO

Pode ser trocado por apenas uma linha, utilizando-se um recurso do ADO que coloca o conteúdo de um record set em um array:
aResult := oQuery:getRows()
Ou na declaração do browse:
oBrowse1:aArray := oQuery:getRows()   

Browse com ADO

MensagemEnviado: 17 Mar 2020 13:53
por Fernando queiroz
Fazendo as correções ficou assim

      oBrowse1:AddColumn( HColumn():New( "Nr.Nota",hwg_ColumnArBlock(),"C",12,0,.F., ) )
         oBrowse1:AddColumn( HColumn():New( "Codigo",hwg_ColumnArBlock(),"C",12,0,.F., ) )
         oBrowse1:AddColumn( HColumn():New( "Movimento",hwg_ColumnArBlock(),"D",12,0,.F., ) )
         oBrowse1:AddColumn( HColumn():New( "Tipo", hwg_ColumnArBlock(),"N",12,0,.F., ) )
         oBrowse1:AddColumn( HColumn():New( "Vendedor",hwg_ColumnArBlock(),"N",10,0,.F.,1,2,'9999' ) )
         oBrowse1:AddColumn( HColumn():New( "Cli/For",hwg_ColumnArBlock(),"C",10,0,.F., ) )
         oBrowse1:AddColumn( HColumn():New( "Quantidade",hwg_ColumnArBlock(),"N",14,2,.F.,1,2,'99999999999.99' ) )
         oBrowse1:AddColumn( HColumn():New( "Valor Unit.", hwg_ColumnArBlock(),'N',14,2,.F.,1,2,'@E 99,999,999,999.99' ) )
         oBrowse1:AddColumn( HColumn():New( "Operador",hwg_ColumnArBlock(),"C",20,0,.F., ) )


resultado final , muito bom
tela.jpg

Browse com ADO

MensagemEnviado: 17 Mar 2020 13:59
por Fernando queiroz
alxsts escreveu:Olá!

Parabéns!

Dicas:

1 - Sempre declare as variáveis antes de as utilizar.

2 - Procure nunca usar variáveis PRIVATE e PUBLIC. Use LOCAL ou STATIC

3 - Este bloco de código
   DO WHILE ! oQuery:Eof()
      aAdd( aResult, {oQuery:Fields( "LOGGERAL_NUMNOT" ):Value,;
                  oQuery:Fields( "LOGGERAL_CODPRO" ):Value,;
                  oQuery:Fields( "LOGGERAL_DATMOV" ):Value,;
                  oQuery:Fields( "LOGGERAL_TIPMOV" ):Value,;
                  oQuery:Fields( "LOGGERAL_CODVEN" ):Value,;
                  oQuery:Fields( "LOGGERAL_CLIFOR" ):Value,;
                  oQuery:Fields( "LOGGERAL_QUANT" ):Value,;
                  oQuery:Fields( "LOGGERAL_VALUNI" ):Value,;
                  oQuery:Fields( "LOGGERAL_OPERADOR" ):Value} )

      oQuery:MoveNext()
   ENDDO

Pode ser trocado por apenas uma linha, utilizando-se um recurso do ADO que coloca o conteúdo de um record set em um array:
aResult := oQuery:getRows()
Ou na declaração do browse:
oBrowse1:aArray := oQuery:getRows()   


fiz o que você falou e trazia os dados de uma linha como uma coluna
pode ser a versão do harbour 3.2 que eu tenho que pode estar errada

Browse com ADO

MensagemEnviado: 17 Mar 2020 17:46
por JoséQuintas
Fernando queiroz escreveu:fiz o que você falou e trazia os dados de uma linha como uma colunapode ser a versão do harbour 3.2 que eu tenho que pode estar errada


Lembro de alguma alteração no Harbour sobre transferir array.
Inclusive, se não me engano, não tem no Harbour 3.4.

Lembro de ter lido mensagem.
Na época tinha a ver com gravar as colunas direto no Excel, e não dava certo.
Se não me engano era esse problema, mas só detectaram pra Excel.
Lógico, ao resolver, já resolveria pro ADO também.

Browse com ADO

MensagemEnviado: 17 Mar 2020 17:58
por JoséQuintas

Browse com ADO

MensagemEnviado: 17 Mar 2020 18:11
por JoséQuintas
Só comentário extra:

É tipo.... gravar o array diretamente no Excel, ou vice-versa.
Tem a ver com a hbwin, e o tratamento de OLE "CreateObject()"

No caso do Excel, é a diferença entre gravar uma coluna de cada vez, ou a planilha inteira de uma vez.
Então... o assunto é interessante, porque o ganho de velocidade pode ser extremo.

Por isso lembrei dele, porque um dia poderia me ser útil.

O problema da época era essa inversão do array multidimensional.

Browse com ADO

MensagemEnviado: 17 Mar 2020 21:14
por Fernando queiroz
QUINTAS fazendo como fiz na rotina o legal é que posso fazer algumas coisas no query e depois so mudar a coluna de lugar , facilita muito

ex:

      oQuery := oServer:Execute( "SELECT LOGGERAL_NUMNOT,";
                                 + "LOGGERAL_CODPRO,";
                                 + "LOGGERAL_DATMOV,";
                                 + "LOGGERAL_CODVEN,";
                                 + "LOGGERAL_CLIFOR,";
                                 + "LOGGERAL_QUANT,";
                                 + "LOGGERAL_VALUNI,";
                                 + "LOGGERAL_OPERADOR, ";
                                 + "CASE WHEN LOGGERAL_TIPMOV IS TRUE THEN 'ENTRADA' ELSE 'SAIDAS' END AS STATUS_GERAL ";
                           + "from loggeral WHERE LOGGERAL_CODPRO = " + STRZERO(nCODPRO,7,0);
                           + " AND  LOGGERAL_DATMOV BETWEEN '" ;
                           + STRZERO(YEAR(dDatepicker1),4,0) + "-" + STRZERO(MONTH(dDatepicker1),2,0) + "-" + STRZERO(DAY(dDatepicker1),2,0);
                           + "' AND '";
                           + STRZERO(YEAR(dDatepicker2),4,0) + "-" + STRZERO(MONTH(dDatepicker2),2,0) + "-" + STRZERO(DAY(dDatepicker2),2,0);
                           + "'" )

      DO WHILE ! oQuery:Eof()
         aAdd( aResult, {oQuery:Fields( "LOGGERAL_NUMNOT" ):Value,;
                     oQuery:Fields( "LOGGERAL_CODPRO" ):Value,;
                     oQuery:Fields( "LOGGERAL_DATMOV" ):Value,;
                     oQuery:Fields( "STATUS_GERAL" ):Value,;
                     oQuery:Fields( "LOGGERAL_CODVEN" ):Value,;
                     oQuery:Fields( "LOGGERAL_CLIFOR" ):Value,;
                     oQuery:Fields( "LOGGERAL_QUANT" ):Value,;
                     oQuery:Fields( "LOGGERAL_VALUNI" ):Value,;
                     oQuery:Fields( "LOGGERAL_OPERADOR" ):Value} )

         oQuery:MoveNext()
      ENDDO
      oQuery:Close()


onde o STATUS_GERAL nao existe no banco , eu criei ele baseado em uma condição do LOGGERAL_TIPMOV e já joguei no local certo como o TIPO

tela.jpg

Browse com ADO

MensagemEnviado: 18 Mar 2020 09:28
por gilbertosilverio
Ola Fernando,

Não é possível você postar toda a rotina de como você fez o filtro desta pesquisa em ADO/MARIADB, para eu poder estudar, pois por mais que eu tente não consigo entender como funciona.

Ja li muito e vi muito exemplos postados pelo Quintas e pelo Simões, mais não tem jeito, pela complexidade, não consigo fazer funcionar na HWGUI.

Com este teu exemplo por ser básico, consegui fazer algo, mais parei ai...

Se você também tiver um exemplo básico de como salvar os dados em uma alteração, inclusao, exclução, com ADO/MARIADB para eu estudar e ver como funciona ficaria muito agradecido, pois os exemplos que encontrei são muito complexos, e meu tico/teco se perdem... kkkk

Browse com ADO

MensagemEnviado: 18 Mar 2020 09:38
por Fernando queiroz
/*
TITULO     : SISTEMA DE GEST¦O DE COMERCIO
DATA       : 14/03/2020
PROGRAMA   : CONSULTALOGGERAL.PRG
COMENTARIO : CONSULTA LOG GERAL COM MARIADB
*/
#pragma -w0
#pragma -es0

#include "hwgui.ch"
******************************************
FUNCTION LOGGERALMARIADB(  )
******************************************

LOCAL oDlg;
   , oLabel1, oLabel2, oLabel3;
   , obusca, oBrowse1 ;
   , oToolbar1;
   , oToolbutton1, oToolbutton2, oToolbutton3, oToolbutton4;
   , oDatepicker1 , oDatepicker2 ;
   , oColuna, bColorBlock ;
   , vBusca := "";
   , oQuery, oRow;
   , aArray, oElemento;
   , aResult:= {}
   
PRIVATE   cProgressKey:="" ,dDatepicker1:=(m->dat_hoje - 30), dDatepicker2:=m->dat_hoje, lFiltro:=.T., nCODPRO:=0;
      , oLabel5 :="",  oLabel7 :="", oLabel10 :="", oLabel11 :="", oLabel6 :="", oLabel9 :="", oLabel12 :="", oLabel18 :="";
      

   IF ! ABRE_PRODUTOS( )
      DBCLOSEALL()
      RETURN
   END
   
   oServer := MySqlConnection( "192.168.15.200", "", "sgcroot", "20r13uqse" )
   oServer:Open()
   oServer:Execute( "USE AMADEU")
   oQuery := oServer:Execute( "SELECT LOGGERAL_NUMNOT,";
                              + "LOGGERAL_CODPRO,";
                              + "LOGGERAL_DATMOV,";
                              + "LOGGERAL_CODVEN,";
                              + "LOGGERAL_CLIFOR,";
                              + "LOGGERAL_QUANT,";
                              + "LOGGERAL_VALUNI,";
                              + "LOGGERAL_OPERADOR, ";
                              + "CASE WHEN LOGGERAL_TIPMOV IS TRUE THEN 'ENTRADA' ELSE 'SAIDAS' END AS STATUS_TIPO ";
                        + "from loggeral WHERE LOGGERAL_DATMOV BETWEEN '";
                        + STRZERO(YEAR(dDatepicker1),4,0) + "-" + STRZERO(MONTH(dDatepicker1),2,0) + "-" + STRZERO(DAY(dDatepicker1),2,0);
                        + "' AND '";
                        + STRZERO(YEAR(dDatepicker2),4,0) + "-" + STRZERO(MONTH(dDatepicker2),2,0) + "-" + STRZERO(DAY(dDatepicker2),2,0);
                        + "'" )

   DO WHILE ! oQuery:Eof()
      aAdd( aResult, {oQuery:Fields( "LOGGERAL_NUMNOT" ):Value,;
                  oQuery:Fields( "LOGGERAL_CODPRO" ):Value,;
                  oQuery:Fields( "LOGGERAL_DATMOV" ):Value,;
                  oQuery:Fields( "STATUS_TIPO" ):Value,;
                  oQuery:Fields( "LOGGERAL_CODVEN" ):Value,;
                  oQuery:Fields( "LOGGERAL_CLIFOR" ):Value,;
                  oQuery:Fields( "LOGGERAL_QUANT" ):Value,;
                  oQuery:Fields( "LOGGERAL_VALUNI" ):Value,;
                  oQuery:Fields( "LOGGERAL_OPERADOR" ):Value} )

      oQuery:MoveNext()
   ENDDO
   oQuery:Close()

   
   INIT DIALOG oDlg TITLE "Log Geral - Consulta"  ;
      ICON MEMVAR->SGC_ICON  ;
      AT 0, 0 SIZE 1167,600 CLIPPER  NOEXIT 

   ThisBRW := oDlg   
   
   @ 4,70 BROWSE oBrowse1 ARRAY OF oDlg SIZE 1160,495 STYLE WS_BORDER + WS_VSCROLL +WS_HSCROLL ;
         ON SIZE ANCHOR_TOPABS + ANCHOR_LEFTABS + ANCHOR_RIGHTABS + ANCHOR_BOTTOMABS    

      oBrowse1:oStyleHead := HStyle():New( { 0xffffff, 0xbbbbbb }, 1,, 0.4, 16759929 )
      oBrowse1:oFont := HFont():Add( '',0,-15,700,,,)         
      oBrowse1:aArray := aResult   

      oBrowse1:AddColumn( HColumn():New( "Nr.Nota",hwg_ColumnArBlock(),"C",12,0,.F., ) )
      oBrowse1:AddColumn( HColumn():New( "Codigo",hwg_ColumnArBlock(),"C",12,0,.F., ) )
      oBrowse1:AddColumn( HColumn():New( "Movimento",hwg_ColumnArBlock(),"D",12,0,.F., ) )
      oBrowse1:AddColumn( HColumn():New( "Tipo", hwg_ColumnArBlock(),"C",12,0,.F., ) )
      oBrowse1:AddColumn( HColumn():New( "Vendedor",hwg_ColumnArBlock(),"N",10,0,.F.,1,2,'9999' ) )
      oBrowse1:AddColumn( HColumn():New( "Cli/For",hwg_ColumnArBlock(),"C",10,0,.F., ) )
      oBrowse1:AddColumn( HColumn():New( "Quantidade",hwg_ColumnArBlock(),"N",14,3,.F.,1,2,'99999999999.999' ) )
      oBrowse1:AddColumn( HColumn():New( "Valor Unit.", hwg_ColumnArBlock(),'N',14,2,.F.,1,2,'@E 99,999,999,999.99' ) )
      oBrowse1:AddColumn( HColumn():New( "Operador",hwg_ColumnArBlock(),"C",20,0,.F., ) )
      

   @ 8,-1 TOOLBAR oToolbar1  SIZE 1160,40 ;
      
      oToolbar1:AddButton("BRW_FIL", , 4, 16, "Filtra" ,{||oBrowse1:aArray := FILTROLOGGERAL( ), obrowse1:REFRESH()},'Filtra o Arquivo de Log Geral','', "oToolbutton1")
      oToolbar1:AddButton("EXIT16BMP", , 4, 16, "Sair" ,{|| DBCLOSEALL(), oDlg:Close() },'Sair da rotina','', "oToolbutton14")
      oToolbar1:CreateTool()

    ADD STATUS PANEL TO oDlg HEIGHT 30  PARTS 200,120,300
   
   @ 4,43 SAY oLabel1 CAPTION "Codigo"  SIZE 138,25 ;
      STYLE SS_CENTER +WS_DLGFRAME
   @ 150,43 GET oEdit1 VAR nCODPRO SIZE 90,25 STYLE ES_RIGHT PICTURE '9999999' MAXLENGTH 7       
      
   @ 245,43 OWNERBUTTON oOwnerbutton1  SIZE 24,24   ;
      TEXT ''  ;
      COORDINATES 0, 0, 0, 0  ;
      BITMAP 'FINDBMP' FROM RESOURCE TRANSPARENT;
      COORDINATES 0, 0, 0, 0 ;
      ON CLICK {|| ThisBRW:oEdit1:SETFOCUS(), CONSULTA_PRODUTOS( ), nCODPRO := VAL(PRODUTOS->CODPRO), ThisBRW:oEdit1:REFRESH() }
      
   @ 283,47 SAY oLabel2 CAPTION "Periodo:"  SIZE 56,18 
   @ 349,43 GET DATEPICKER oDatepicker1 VAR dDatepicker1 SIZE 125,24 VALID {|| (dDatepicker1 < dDatepicker2) }
   @ 482,47 SAY oLabel3 CAPTION "A"  SIZE 10,18
   @ 499,43 GET DATEPICKER oDatepicker2 VAR dDatepicker2 SIZE 125,24
   
   ACTIVATE DIALOG oDlg CENTER   

   DBCLOSEALL()
   oServer:Close()

RETURN NIL
************************************************************************************
FUNCTION MySqlConnection( cServer, cDatabase, cUser, cPassword, nPort )
************************************************************************************
   LOCAL cnConnection

   hb_Default( @nPort, 3306 )

   cnConnection:= win_OleCreateObject( "ADODB.Connection" )
   cnConnection:ConnectionString := iif( win_OsIs10(), "Provider=MSDASQL;", "" )
   cnConnection:ConnectionString += "Driver={MariaDB ODBC 3.1 Driver};"
   cnConnection:ConnectionString += ;
      "Server=" + cServer + ";" + ;
      "Port=" + Ltrim( Str( nPort ) ) + ";" + ;
      "Stmt=;" + ;
      "Database=" + cDatabase + ";" + ;
      "User=" + cUser + ";" + ;
      "Password=" + cPassword + ";" + ;
      "Collation=utf8_general_ci;" + ;
      "AUTO_RECONNECT=1;" + ;
      "COMPRESSED_PROTO=0;" + ;
      "PAD_SPACE=1"
   cnConnection:CursorLocation    := 3
   cnConnection:CommandTimeOut    := 600 // seconds
   cnConnection:ConnectionTimeOut := 600 // seconds

   RETURN cnConnection
******************************************
FUNCTION win_OsIs10(); RETURN .T.
******************************************

*****************************************
STATIC FUNCTION onDlgInit(  )
*****************************************
   hwg_WriteStatus( ThisBRW,1,"Tabela: " + Alias())
   hwg_WriteStatus( ThisBRW,2,LTrim(Str( RecNo(),8))+ "/" +LTrim(Str( Lastrec(),8)))
   hwg_WriteStatus( ThisBRW,3,"Ordem: Codigo/Data Movimento")   

RETURN Nil

********************************************************
STATIC FUNCTION FILTROLOGGERAL(  )
********************************************************
LOCAL nI, aResult:={}

//   FOR nI = Len( aResult ) TO 1 STEP -1
//      hb_ADel( aResult, nI, .T. )
//   NEXT

   IF nCODPRO # 0
      oQuery := oServer:Execute( "SELECT LOGGERAL_NUMNOT,";
                                 + "LOGGERAL_CODPRO,";
                                 + "LOGGERAL_DATMOV,";
                                 + "LOGGERAL_CODVEN,";
                                 + "LOGGERAL_CLIFOR,";
                                 + "LOGGERAL_QUANT,";
                                 + "LOGGERAL_VALUNI,";
                                 + "LOGGERAL_OPERADOR, ";
                                 + "CASE WHEN LOGGERAL_TIPMOV IS TRUE THEN 'ENTRADA' ELSE 'SAIDAS' END AS STATUS_TIPO ";
                           + "from loggeral WHERE LOGGERAL_CODPRO = " + STRZERO(nCODPRO,7,0);
                           + " AND  LOGGERAL_DATMOV BETWEEN '" ;
                           + STRZERO(YEAR(dDatepicker1),4,0) + "-" + STRZERO(MONTH(dDatepicker1),2,0) + "-" + STRZERO(DAY(dDatepicker1),2,0);
                           + "' AND '";
                           + STRZERO(YEAR(dDatepicker2),4,0) + "-" + STRZERO(MONTH(dDatepicker2),2,0) + "-" + STRZERO(DAY(dDatepicker2),2,0);
                           + "'" )

      DO WHILE ! oQuery:Eof()
         aAdd( aResult, {oQuery:Fields( "LOGGERAL_NUMNOT" ):Value,;
                     oQuery:Fields( "LOGGERAL_CODPRO" ):Value,;
                     oQuery:Fields( "LOGGERAL_DATMOV" ):Value,;
                     oQuery:Fields( "STATUS_TIPO" ):Value,;
                     oQuery:Fields( "LOGGERAL_CODVEN" ):Value,;
                     oQuery:Fields( "LOGGERAL_CLIFOR" ):Value,;
                     oQuery:Fields( "LOGGERAL_QUANT" ):Value,;
                     oQuery:Fields( "LOGGERAL_VALUNI" ):Value,;
                     oQuery:Fields( "LOGGERAL_OPERADOR" ):Value} )

         oQuery:MoveNext()
      ENDDO
      oQuery:Close()
   ELSE
      oQuery := oServer:Execute( "SELECT LOGGERAL_NUMNOT,";
                                 + "LOGGERAL_CODPRO,";
                                 + "LOGGERAL_DATMOV,";
                                 + "LOGGERAL_CODVEN,";
                                 + "LOGGERAL_CLIFOR,";
                                 + "LOGGERAL_QUANT,";
                                 + "LOGGERAL_VALUNI,";
                                 + "LOGGERAL_OPERADOR, ";
                                 + "CASE WHEN LOGGERAL_TIPMOV IS TRUE THEN 'ENTRADA' ELSE 'SAIDAS' END AS STATUS_TIPO ";
                           + "from loggeral WHERE LOGGERAL_DATMOV BETWEEN '";
                           + STRZERO(YEAR(dDatepicker1),4,0) + "-" + STRZERO(MONTH(dDatepicker1),2,0) + "-" + STRZERO(DAY(dDatepicker1),2,0);
                           + "' AND '";
                           + STRZERO(YEAR(dDatepicker2),4,0) + "-" + STRZERO(MONTH(dDatepicker2),2,0) + "-" + STRZERO(DAY(dDatepicker2),2,0);
                           + "'" )

      DO WHILE ! oQuery:Eof()
         aAdd( aResult, {oQuery:Fields( "LOGGERAL_NUMNOT" ):Value,;
                     oQuery:Fields( "LOGGERAL_CODPRO" ):Value,;
                     oQuery:Fields( "LOGGERAL_DATMOV" ):Value,;
                     oQuery:Fields( "STATUS_TIPO" ):Value,;
                     oQuery:Fields( "LOGGERAL_CODVEN" ):Value,;
                     oQuery:Fields( "LOGGERAL_CLIFOR" ):Value,;
                     oQuery:Fields( "LOGGERAL_QUANT" ):Value,;
                     oQuery:Fields( "LOGGERAL_VALUNI" ):Value,;
                     oQuery:Fields( "LOGGERAL_OPERADOR" ):Value} )

         oQuery:MoveNext()
      ENDDO
      oQuery:Close()   
   ENDIF
   
RETURN aResult

****************************************
STATIC FUNCTION CONSULTA_PRODUTOS(  )
****************************************
LOCAL oDlgPro ;
   , oLabel1, oLabel2 ;
   , oBrowse4 ;
   , oColuna, bColorBlock, vBusca ;
   , oToolbar1 ;
   , nKeyPress

PRIVATE cProgressKey:=""

   DBSELECTAREA("PRODUTOS")
   ORDSETFOCUS( 2 )
   PRODUTOS->(dbgotop())

   

  INIT DIALOG oDlgPro TITLE "Nota de Pedido - Consulta Produtos"  ;
      ICON MEMVAR->SGC_ICON  ;
      AT 0, 0 SIZE 1006,582 CLIPPER  NOEXIT NOCLOSABLE ;
      ON INIT {|This| onDlgInit3( This, oDlgPro ) }
    PRODUTOSBRW := oDlgPro

   @ 4,70 BROWSE oBrowse4 DATABASE OF oDlgPro SIZE 1000,480 STYLE WS_BORDER + WS_VSCROLL +WS_HSCROLL ;
         ON SIZE ANCHOR_TOPABS + ANCHOR_LEFTABS + ANCHOR_RIGHTABS + ANCHOR_BOTTOMABS ;
         ON POSCHANGE {|| hwg_WriteStatus( oDlgPro,2,LTrim(Str( RecNo(),8))+ "/" +LTrim(Str( Lastrec(),8))) } ;
         ON CLICK {|| PESQUISAPRODUTO_onClick(  ) } ;
         ON KEYDOWN {|oBrowse4,nKeyPress| PESQUISAPRODUTO_onKeyDown( oBrowse4,nKeyPress ) }

      oBrowse4:oStyleHead := HStyle():New( { 0xffffff, 0xbbbbbb }, 1,, 0.4, 16759929 )
      oBrowse4:oFont := HFont():Add( '',0,-18,700,,,)   
      oBrowse4:freeze := 2
//      oBrowse4:alias := 'PRODUTOS'
//      SELECT (oBrowse4:alias) 
      bColorBlock :={|| IIF(PRODUTOS->ESTATU + PRODUTOS->ESTL02 = 0.0000 ,{255, 16777215 ,16777215,255 },{0,16777215,, }) }   
      
      oBrowse4:AddColumn( HColumn():New('Codigo', FieldBlock( 'codpro' ) ,'C',9, 0 ,.F.,1,2,'@R 999999-9',,,,,;
                          {|| Ordsetfocus(1), Dbgotop(), obrowse4:Refresh(), vBusca:="" ,  ;
                     hwg_WriteStatus( oDlgPro,3,"Ordem: Codigo   ") } ,,,,))
                     
      oBrowse4:AddColumn( HColumn():New('Descrição/Nome Produto', FieldBlock( 'despro' ) ,'C',58, 0 ,.F.,1,,'@S58',,,,,;
                  {|| Ordsetfocus(2), Dbgotop(), obrowse4:Refresh(), vBusca:="" , ;
                  hwg_WriteStatus( oDlgPro,3,"Ordem: Descriçao") } ,,,,))

      oBrowse4:AddColumn( HColumn():New('Unidade', FieldBlock( 'TIPUNI' ) ,'C',9, 0 ,.F.,1,,,,,,,,,,,))

      oBrowse4:AddColumn( HColumn():New('Preço Venda', FieldBlock( 'preven' ) ,'N',14, 2 ,.F.,1,2,'@E 999,999.99',,,,,,,,,))
      
      oBrowse4:AddColumn( HColumn():New('Estoque Loja', {|| IF(PROSER = "1",ESTATU,ESTATU*(-1)) } ,'N',12, 3 ,.F.,1,2,,,,,,,,,,))

//      bColorBlock :={|| IIF(PRODUTOS->ESTATU + PRODUTOS->ESTL02 = 0.0000 ,{255, 16777215 ,16777215,255 },{0,16777215,, }) }   

      FOR EACH oColuna IN oBrowse4:aColumns
         oColuna:bColorBlock := bColorBlock
      NEXT      
      

      
   @ 8,-1 TOOLBAR oToolbar1  SIZE 945,40 ;
      
      oToolbar1:AddButton("EXIT16BMP", , 4, 16, "Sair" ,{|| oDlgPro:Close() },'Sair da rotina','', "oToolbutton8")
      oToolbar1:CreateTool()

    ADD STATUS PANEL TO oDlgPro HEIGHT 30  PARTS 200,120,300
   @ 4,43 SAY oLabel1 CAPTION "Pesquisar"  SIZE 138,25 ;
      STYLE SS_CENTER +WS_DLGFRAME    
   @ 150,43 SAY oLabel2 CAPTION "" SIZE 410,25 ;
        STYLE WS_BORDER;
        COLOR 16777215  BACKCOLOR 255

   ACTIVATE DIALOG oDlgPro  CENTER   

   
RETURN .T.

***********************************************************************************
STATIC FUNCTION onDlgInit3( This, oDlgPro )
   hwg_WriteStatus( oDlgPro,1,"Tabela: " + Alias())
   hwg_WriteStatus( oDlgPro,2,LTrim(Str( RecNo(),8))+ "/" +LTrim(Str( Lastrec(),8)))
   hwg_WriteStatus( oDlgPro,3,"Ordem: Descrição")   
RETURN .T.

******************************************************
STATIC FUNCTION PESQUISAPRODUTO_onClick(  )
   IF hwg_LastKey() ==   MK_LBUTTON
      PRODUTOSBRW:Close()
   ENDIF
RETURN .T.
********************************************************
STATIC FUNCTION PESQUISAPRODUTO_onKeyDown( oBrowse4,nKey )
   LOCAL nPosicao:=0, nKeyPress:=nkey
   LOCAL cRegEx := "[a-zA-Z0-9 ]{1}"
   KSETCAPS(.T.)

   aResult:=HB_RegExALL( cRegEx, Chr(nKeyPress) )

   IF nKeyPress # 8 .AND. AllTrim(Str(nKeyPress)) $ "34|33|37|38|39|40|20|16"
      cProgressKey:=""
      PRODUTOSBRW:oLabel2:settext(cProgressKey)
      RETURN .T.
   ELSEIF nKeyPress # 8 .AND. AllTrim(Str(nKeyPress)) $ [90]
      nKeyPress := 90
   ELSEIF nKeyPress # 8 .AND. AllTrim(Str(nKeyPress)) $ [96]
      nKeyPress := 48
   ELSEIF nKeyPress # 8 .AND. AllTrim(Str(nKeyPress)) $ [97]
      nKeyPress := 49
   ELSEIF nKeyPress # 8 .AND. AllTrim(Str(nKeyPress)) $ [98]
      nKeyPress := 50
   ELSEIF nKeyPress # 8 .AND. AllTrim(Str(nKeyPress)) $ [99]
      nKeyPress := 51
   ELSEIF nKeyPress # 8 .AND. AllTrim(Str(nKeyPress)) $ [100]
      nKeyPress := 52
   ELSEIF nKeyPress # 8 .AND. AllTrim(Str(nKeyPress)) $ [101]
      nKeyPress := 53
   ELSEIF nKeyPress # 8 .AND. AllTrim(Str(nKeyPress)) $ [102]
      nKeyPress := 54
   ELSEIF nKeyPress # 8 .AND. AllTrim(Str(nKeyPress)) $ [103]
      nKeyPress := 55
   ELSEIF nKeyPress # 8 .AND. AllTrim(Str(nKeyPress)) $ [104]
      nKeyPress := 56
   ELSEIF nKeyPress # 8 .AND. AllTrim(Str(nKeyPress)) $ [105]
      nKeyPress := 57
   ELSEIF nKeyPress # 8 .AND. AllTrim(Str(nKeyPress)) $ [106]
      nKeyPress := 42
   ELSEIF nKeyPress # 8 .AND. AllTrim(Str(nKeyPress)) $ [190]
      nKeyPress := 46
   ELSEIF nKeyPress == Asc("8") .AND. hwg_isCtrlShift( .F.,.T. )
     nKeyPress := 42      
   ENDIF   

   IF    nKeyPress = VK_RETURN .OR. nKeyPress = VK_ESCAPE
      PRODUTOSBRW:Close()      
      RETURN .T.   
   ENDI

      
// IF IsAscii(Chr(nKeyPress)) .AND. nKeyPress # 8
   If nKeyPress # 8
      cProgressKey += Chr(nKeyPress)
      nPosicao:=AScan(PRODUTOSBRW:oBrowse4:aArray,cProgressKey)
      PRODUTOSBRW:oLabel2:settext(cProgressKey)
      PRODUTOSBRW:oBrowse4:TOP()
      DBSEEK(cProgressKey,.T.)

   ELSEIF nKeyPress = 8 .AND. Len(cProgressKey) >= 1
      cProgressKey:=Left(cProgressKey,Len(cProgressKey) - 1)
      nPosicao:=AScan(PRODUTOSBRW:oBrowse4:aArray,cProgressKey)
      PRODUTOSBRW:oLabel2:settext(cProgressKey)
      PRODUTOSBRW:oBrowse4:TOP()
      DBSEEK(cProgressKey,.T.)
   ENDIF   
   IF nPosicao # 0
      oBrowse4:rowPos := nPosicao
      Eval( PRODUTOSBRW:oBrowse4:bGoTo, PRODUTOSBRW:oBrowse4, nPosicao )
      PRODUTOSBRW:oBrowse4:Refresh()
   ENDIF   
return .t. 



rotina completa para estudos , tem alguma coisas que podem ser melhoradas, como declarações de variaveis , mas era somente um teste
nao tive muita preocupação de deixar tudo bonitinho.

Browse com ADO

MensagemEnviado: 18 Mar 2020 11:10
por gilbertosilverio
Fernando,

Muito obrigado.

E so pra eu tentar entender como funciona, como sou leigo (burro mesmo... kkkk) e com do básico que consigo dar inicio e ir avançando.

Valeu...

Browse com ADO

MensagemEnviado: 18 Mar 2020 14:28
por Fernando queiroz
Dando uma melhorada na QUERY de filtragem, ficou muito show

*************************************************************************************************************
STATIC FUNCTION FILTROLOGGERAL( oServer, nCODPRO, dDatepicker1, dDatepicker2, lEntradas , lSaidas)
*************************************************************************************************************
LOCAL aResult:={};
   , oQuery;
   , cQuery

   cQuery := "SELECT LOGGERAL_NUMNOT, ";
               + "LOGGERAL_CODPRO, ";
               + "LOGGERAL_DATMOV, ";
               + "LOGGERAL_CODVEN, ";
               + "LOGGERAL_CLIFOR, ";
               + "LOGGERAL_QUANT, ";
               + "LOGGERAL_VALUNI, ";
               + "LOGGERAL_OPERADOR, ";
               + "CASE WHEN LOGGERAL_TIPMOV IS TRUE THEN 'ENTRADA' ELSE 'SAIDA' END AS STATUS_TIPO ";
               
               IF nCODPRO # 0
                  cQuery += "from loggeral WHERE LOGGERAL_CODPRO = '" + STRZERO(nCODPRO,7,0) + "' AND "
               ELSE
                  cQuery += "from loggeral WHERE "
               ENDIF
               
               cQuery  += "LOGGERAL_DATMOV BETWEEN " ;
                     + "'" + STRZERO(YEAR(dDatepicker1),4,0) + "-" + STRZERO(MONTH(dDatepicker1),2,0) + "-" + STRZERO(DAY(dDatepicker1),2,0) + "'";
                     + " AND ";
                     + "'" + STRZERO(YEAR(dDatepicker2),4,0) + "-" + STRZERO(MONTH(dDatepicker2),2,0) + "-" + STRZERO(DAY(dDatepicker2),2,0) + "'"
         
               IF lEntradas .AND. ! lSaidas
                  cQuery += " AND LOGGERAL_TIPMOV IS TRUE "
               ELSEIF ! lEntradas .AND. lSaidas
                  cQuery += " AND LOGGERAL_TIPMOV IS FALSE "
               ENDIF
               
//               hwg_MsgInfo( cQuery,"QUERY" )
                        
   oQuery := oServer:Execute(cQuery)

   DO WHILE ! oQuery:Eof()
      aAdd( aResult, {oQuery:Fields( "LOGGERAL_NUMNOT" ):Value,;
                  oQuery:Fields( "LOGGERAL_CODPRO" ):Value,;
                  oQuery:Fields( "LOGGERAL_DATMOV" ):Value,;
                  oQuery:Fields( "STATUS_TIPO" ):Value,;
                  oQuery:Fields( "LOGGERAL_CODVEN" ):Value,;
                  oQuery:Fields( "LOGGERAL_CLIFOR" ):Value,;
                  oQuery:Fields( "LOGGERAL_QUANT" ):Value,;
                  oQuery:Fields( "LOGGERAL_VALUNI" ):Value,;
                  oQuery:Fields( "LOGGERAL_OPERADOR" ):Value} )

      oQuery:MoveNext()
   ENDDO
   oQuery:Close()

RETURN aResult


resultado

tela.jpg

Browse com ADO

MensagemEnviado: 18 Mar 2020 14:43
por gilbertosilverio
Fernando,

Estava vendo teu codigo, e pelo que entendi, voce trabalha com MARIADB e DBF, pela chamada que voce faz na consulta de produtos correto?

Da pra trabalhar com duas base de dados?

Browse com ADO

MensagemEnviado: 18 Mar 2020 15:19
por Fernando queiroz
gilbertosilverio escreveu:Fernando,

Estava vendo teu codigo, e pelo que entendi, voce trabalha com MARIADB e DBF, pela chamada que voce faz na consulta de produtos correto?

Da pra trabalhar com duas base de dados?


pode sim , sem problemas

na realidade estou trabalhando com o LETODBF e MARIADB

mas ja converti todos os arquivos DBF em MARIADB

e agora estou brincando com os dois, e no futuro migrar tudo, to fazendo que nem o QUINTAS vamos brincar e aprender e depois migrar

Browse com ADO

MensagemEnviado: 23 Mar 2020 16:04
por Fernando queiroz
Fonte completo de uma rotina de CONSULTA, INCLUSÃO , EXCLUSÃO, ALTERAÇÃO em MARIADB

Gostaria da ajuda dos amigos para umas dicas de como posicionar novamente no mesmo registro do browse array apos a inc/alt
Dicas de como melhorar alguns procedimento serão bem vindas.

/*
TITULO     : SISTEMA DE GESTÇO DE COMERCIO
DATA       : 09/03/2020
PROGRAMA   : CADASTROCLIENTES_MARIADB.PRG
COMENTARIO : CADASTRO/RELATORIO (/Clientes)/
*/
#pragma -w0
#pragma -es0

#include "hbgtinfo.ch"
#include "hwgui.ch"
#include "SEFAZ_CIDADE.CH"
#include "SEFAZ_UF.CH"
#define PDFCLASS_PORTRAIT  1
#define PDFCLASS_LANDSCAPE 2
#define PDFCLASS_TXT       3
#define PDFCLASS_ROLLS     4

****************************************
FUNCTION CADASTROCLIENTESMARIADB( )
****************************************
   LOCAL oDlg ;
      , oLabel1, oLabel4 ;
      , oBrowse1 ;
      , oToolbar1 ;
      , nKeyPress ;
      , oColuna, bColorBlock
   
      
      
   PRIVATE   cProgressKey:="";
         , cConsulta:="";
         , cAlvo_Consulta:="CLIENTES_NRAZ_SOC"
         

   oServer := MySqlConnection(  )
   oServer:Open()

******************************************************************************************************************************************************
   aVENBLO    := {"0 - Liberado","1 - Bloqueado"}
   aISENTO    := {"1 - CONTRIBUINTE DE ICMS","2 - CONTRIBUINTE ISENTO","9 - NAO CONTRIBUINTE"}

******************************************************************************************************************************************************

   INIT DIALOG oDlg TITLE "Cadastro de Clientes"  ;
      ICON MEMVAR->SGC_ICON  ;
      AT 0, 0 SIZE 1008,600 CLIPPER  NOEXIT  ;
      ON INIT {|| onDlgInit( oDlg ) }
   
   @ 4,70 BROWSE oBrowse1 ARRAY OF oDlg SIZE 1000,497 STYLE WS_BORDER + WS_VSCROLL +WS_HSCROLL ;
         ON SIZE ANCHOR_TOPABS + ANCHOR_LEFTABS + ANCHOR_RIGHTABS + ANCHOR_BOTTOMABS ;
         ON POSCHANGE {|| hwg_WriteStatus( oDlg,2,LTrim(Str( RecNo(),8))+ "/" +LTrim(Str( Lastrec(),8))) } ;
         ON CLICK {|| oBrowse1_onClick( oDlg, oServer ) } ;
         ON KEYDOWN {|oBrowse1,nKeyPress| oBrowse1_onKeyDown( oBrowse1,nKeyPress, oDlg, oServer ) }

      oBrowse1:oStyleHead := HStyle():New( { 0xffffff, 0xbbbbbb }, 1,, 0.4, 16759929 )
      oBrowse1:oFont := HFont():Add( '',0,-15,700,,,)
      oBrowse1:freeze := 2
      oBrowse1:aArray := CARREGA_CLIENTES( oServer, "ORDER BY CLIENTES_NRAZ_SOC" )

      oBrowse1:AddColumn( HColumn():New( "Codigo",hwg_ColumnArBlock(),"C",08,0,.F.,,,,,,,,;
               {|| oBrowse1:aArray := CARREGA_CLIENTES( oServer, "ORDER BY CLIENTES_UCLIENTE" ), cAlvo_Consulta:="CLIENTES_UCLIENTE",obrowse1:Refresh(), hwg_WriteStatus( oDlg,3,"Ordem: Codigo") } ,,,,))
      oBrowse1:AddColumn( HColumn():New( "Nome Cliente/Razao Social",hwg_ColumnArBlock(),"C",65,0,.F.,,,,,,,,;
               {|| oBrowse1:aArray := CARREGA_CLIENTES( oServer, "ORDER BY CLIENTES_NRAZ_SOC" ), cAlvo_Consulta:="CLIENTES_NRAZ_SOC", obrowse1:Refresh(), hwg_WriteStatus( oDlg,3,"Ordem: Nome Cliente/Razao Social") } ,,,,))
      oBrowse1:AddColumn( HColumn():New( "CPF/CNPJ",hwg_ColumnArBlock(),"C",18,0,.F.,,,,,,,,;
               {|| oBrowse1:aArray := CARREGA_CLIENTES( oServer, "ORDER BY CLIENTES_CPFCGC"), cAlvo_Consulta:="CLIENTES_CPFCGC", obrowse1:Refresh(), hwg_WriteStatus( oDlg,3,"Ordem: CPF/CNPJ") } ,,,,))
      oBrowse1:AddColumn( HColumn():New( "FONE", hwg_ColumnArBlock(),"C",18,0,.F.,,,,,,,,;
               {|| oBrowse1:aArray := CARREGA_CLIENTES( oServer, "ORDER BY CLIENTES_FONE"), cAlvo_Consulta:="CLIENTES_FONE", obrowse1:Refresh(), hwg_WriteStatus( oDlg,3,"Ordem: FONE") } ,,,,))
      oBrowse1:AddColumn( HColumn():New('E-Mail', hwg_ColumnArBlock() ,'C',60, 0 ,.F.,,,,,,,,))
      oBrowse1:AddColumn( HColumn():New( "Insc.Estadual",hwg_ColumnArBlock(),"C",18,0,.F.,,, ) )
      oBrowse1:AddColumn( HColumn():New( "TC",hwg_ColumnArBlock(),"C",4,0,.F., ) )
      oBrowse1:AddColumn( HColumn():New( "Logradouro",hwg_ColumnArBlock(),"C",60,0,.F., ) )
      oBrowse1:AddColumn( HColumn():New( "Numero", hwg_ColumnArBlock(),'N',9,0,.F.,1,2, ) )
      oBrowse1:AddColumn( HColumn():New( "Complemento",hwg_ColumnArBlock(),"C",60,0,.F., ) )
      oBrowse1:AddColumn( HColumn():New('Bairro', hwg_ColumnArBlock() ,'C',60, 0 ,.F.,,,,,,,,,,,,,))
      oBrowse1:AddColumn( HColumn():New('CEP', hwg_ColumnArBlock() ,'C',12, 0 ,.F.,,,,,,,,,,,,,))
      oBrowse1:AddColumn( HColumn():New('Cod.Pais', hwg_ColumnArBlock() ,'C',7, 0 ,.F.,,,,,,,,,,,,,))
      oBrowse1:AddColumn( HColumn():New('Pais', hwg_ColumnArBlock() ,'C',50, 0 ,.F.,,,,,,,,,,,,))
      oBrowse1:AddColumn( HColumn():New('UF', hwg_ColumnArBlock() ,'C',4, 0 ,.F.,,,,,,,,,,,,))
      oBrowse1:AddColumn( HColumn():New('Cod.Mun.', hwg_ColumnArBlock() ,'C',7, 0 ,.F.,,,,,,,,,,,,))
      oBrowse1:AddColumn( HColumn():New('Municipio', hwg_ColumnArBlock() ,'C',50, 0 ,.F.,,,,,,,,,,,,))
      oBrowse1:AddColumn( HColumn():New('Contato', hwg_ColumnArBlock() ,'C',50, 0 ,.F.,,,,,,,,,,,,))
      oBrowse1:AddColumn( HColumn():New('Data Alteração', hwg_ColumnArBlock() ,'D',12, 0 ,.F.,,,,,,,,,,,,))
      oBrowse1:AddColumn( HColumn():New('Operador', hwg_ColumnArBlock() ,'C',20, 0 ,.F.,,,,,,,,,,,,))
      oBrowse1:AddColumn( HColumn():New('Operador/Computador DATA/HORA', hwg_ColumnArBlock() ,'C',60, 0 ,.F.,,,,,,,,))
      oBrowse1:AddColumn( HColumn():New('CLIENTES ID', hwg_ColumnArBlock() ,'N',14, 0 ,.F.,1,2,,,,,,;
               {|| oBrowse1:aArray := CARREGA_CLIENTES( oServer, "ORDER BY CLIENTES_ID"), cAlvo_Consulta:="CLIENTES_ID", obrowse1:Refresh(), hwg_WriteStatus( oDlg,3,"Ordem: CHAVE ID") } ,,,,))

      bColorBlock := {|| {0,16777215,, } }      
      FOR EACH oColuna IN oBrowse1:aColumns
         oColuna:bColorBlock := bColorBlock
      NEXT

   @ 1,-1 TOOLBAR oToolbar1  SIZE hwg_Getdesktopwidth(),43     
               
      oToolbar1:AddButton("CMDINSERT", , 0, 16, "Inclui" ,{||CADCLIENTES( oServer, , "INCLUIR"  ), oBrowse1:aArray := CARREGA_CLIENTES( oServer, "ORDER BY " + cAlvo_Consulta ), obrowse1:REFRESH()},'Incluir novo Cliente','', "oToolbutton1")
      oToolbar1:AddButton("CMDEDIT", , 0, 16, "Altera"   ,{||CADCLIENTES( oServer, LTRIM(str(oDlg:oBrowse1:aArray[ oDlg:oBrowse1:nCurrent, 22])), "ALTERAR"  ), oBrowse1:aArray := CARREGA_CLIENTES( oServer, "ORDER BY " + cAlvo_Consulta ), obrowse1:REFRESH()},'Altera os dados do Cliente','', "oToolbutton2")
      oToolbar1:AddButton("CMDDELETE", , 0, 16, "Exclui" ,{||CADCLIENTES_EXCLUI( oDlg, oServer ), oBrowse1:aArray := CARREGA_CLIENTES( oServer, "ORDER BY " + cAlvo_Consulta ), obrowse1:REFRESH() },'Exclui os dados do Cliente','', "oToolbutton3")
//      oToolbar1:AddButton("CLFLBMP", , 4, 16, "Consulta" ,{||CONSULTACADCLIENTES( )},'Consulta dados do Cadastro de Clientes','', "oToolbutton5")
      oToolbar1:AddButton("rel_print",, 4, 128, "Relatórios" ,,, {{"Cadastro de Clientes ", 4,{| This, nId | RELATORIO_CLIENTES( ) }}};
                                                   , "oToolbutton6")
      oToolbar1:AddButton("EXIT16BMP", , 4, 16, "Sair" ,{|| DBCLOSEALL(), oDlg:Close() },'Sair da rotina','', "oToolbutton7")
      oToolbar1:CreateTool()

    ADD STATUS PANEL TO oDlg HEIGHT 30  PARTS 200,120,300
   @ 4,45 SAY oLabel1 CAPTION "Pesquisar"  SIZE 138,25 ;
      STYLE SS_CENTER +WS_DLGFRAME    
   @ 150,45 SAY oLabel4 CAPTION "" SIZE 410,25 ;
        STYLE WS_BORDER;
        COLOR 16777215  BACKCOLOR 255

   
      
   ACTIVATE DIALOG oDlg CENTER   
   oServer:Close()
   
RETURN NIL

******************************************************************
STATIC FUNCTION CARREGA_CLIENTES( oServer, cAlvo_Consulta )
******************************************************************
LOCAL aResult :={};
   , oQuery;
   , cQuery
   
   cQuery := "SELECT CLIENTES_UCLIENTE, ";
               + "CLIENTES_NRAZ_SOC, ";
               + "CLIENTES_CPFCGC, ";
               + "CLIENTES_FONE, ";
               + "CLIENTES_EMAIL, ";
               + "CLIENTES_INSEST, ";
               + "CLIENTES_ISENTO, ";
               + "CLIENTES_ENDER, ";
               + "CLIENTES_NUMERO, ";
               + "CLIENTES_COMPLEM, ";
               + "CLIENTES_BAIR, ";
               + "CLIENTES_CEP, ";
               + "CLIENTES_CODPAIS, ";
               + "CLIENTES_PAIS, ";
               + "CLIENTES_UF, ";
               + "CLIENTES_CODMUN, ";
               + "CLIENTES_CIDADE, ";
               + "CLIENTES_CONTATO, ";
               + "CLIENTES_DATALT, ";
               + "CLIENTES_USUALT, ";                              
               + "CLIENTES_QUEM_BLOQ, ";
               + "CLIENTES_ID ";
               + "from CLIENTES ";
               + cAlvo_Consulta

   oQuery := oServer:Execute(cQuery)

   DO WHILE ! oQuery:Eof()
      aAdd( aResult, {oQuery:Fields( "CLIENTES_UCLIENTE" ):Value,;
                  oQuery:Fields( "CLIENTES_NRAZ_SOC" ):Value,;
                  oQuery:Fields( "CLIENTES_CPFCGC" ):Value,;
                  oQuery:Fields( "CLIENTES_FONE" ):Value,;
                  oQuery:Fields( "CLIENTES_EMAIL" ):Value,;
                  oQuery:Fields( "CLIENTES_INSEST" ):Value,;
                  oQuery:Fields( "CLIENTES_ISENTO" ):Value,;
                  oQuery:Fields( "CLIENTES_ENDER" ):Value,;
                  oQuery:Fields( "CLIENTES_NUMERO" ):Value,;
                  oQuery:Fields( "CLIENTES_COMPLEM" ):Value,;
                  oQuery:Fields( "CLIENTES_BAIR" ):Value,;
                  oQuery:Fields( "CLIENTES_CEP" ):Value,;
                  oQuery:Fields( "CLIENTES_CODPAIS" ):Value,;
                  oQuery:Fields( "CLIENTES_PAIS" ):Value,;
                  oQuery:Fields( "CLIENTES_UF" ):Value,;
                  oQuery:Fields( "CLIENTES_CODMUN" ):Value,;
                  oQuery:Fields( "CLIENTES_CIDADE" ):Value,;
                  oQuery:Fields( "CLIENTES_CONTATO" ):Value,;
                  oQuery:Fields( "CLIENTES_DATALT" ):Value,;
                  oQuery:Fields( "CLIENTES_USUALT" ):Value,;
                  oQuery:Fields( "CLIENTES_QUEM_BLOQ" ):Value,;
                  oQuery:Fields( "CLIENTES_ID" ):Value} )

      oQuery:MoveNext()
   ENDDO
   oQuery:Close()   
      
RETURN aResult

******************************************************************
STATIC FUNCTION onDlgInit( oDlg )
******************************************************************
      oDlg:oToolbar1:oToolbutton1:ENABLE()
      oDlg:oToolbar1:oToolbutton2:ENABLE()
      IF strzero(M->NIV_ACESSO,1,0)$"689"
         oDlg:oToolbar1:oToolbutton3:ENABLE()
      ENDIF

   hwg_WriteStatus( oDlg,1,"Tabela: CLIENTES")
    hwg_WriteStatus( oDlg,2,oDlg:oBrowse1:nCurrent)                 
    hwg_WriteStatus( oDlg,3,"Ordem: Nome Cliente/Razao Social")   
RETURN Nil

******************************************************
STATIC FUNCTION CADCLIENTES_EXCLUI( oDlg, oServer )
******************************************************
LOCAL oQuery;
   
   IF hwg_MsgYesNo("DESEJA excluir, Tem certeza disso ?","Excluindo Cliente")
      BEGIN SEQUENCE
         oQuery := oServer:Execute("DELETE FROM clientes WHERE CLIENTES_Id='" + LTRIM(str(oDlg:oBrowse1:aArray[ oDlg:oBrowse1:nCurrent, 22])) + "'")
      RECOVER
         hwg_msginfo("REGISTRO NÃO FOI EXCLUIDO, ERRO DE ESCLUSÃO","Excluindo Cliente")
      END SEQUENCE
   ENDIF

RETURN NIL

***********************************************************
STATIC FUNCTION oBrowse1_onClick( oDlg, oServer )
***********************************************************
   IF hwg_LastKey() ==   MK_LBUTTON
      CADCLIENTES( oServer, LTRIM(str(oDlg:oBrowse1:aArray[ oDlg:oBrowse1:nCurrent, 22])), "CONSULTAR"  )
      oDlg:oBrowse1:Refresh()
      RETURN .T.
   ENDIF
RETURN .T.


*******************************************************************
STATIC FUNCTION oBrowse1_onKeyDown( oBrowse1, nKey, oDlg, oServer )
*******************************************************************
LOCAL nPosicao:=0;
   , nKeyPress:=nkey;
   , cRegEx := "[a-zA-Z0-9 ]{1}";
   , cQuery
   
   KSETCAPS(.T.);

   IF nKeyPress # 8 .AND. AllTrim(Str(nKeyPress)) $ "34|33|37|38|39|40|20|16"
      cProgressKey:=""
      oDlg:oLabel4:settext(cProgressKey)
      RETURN .T.
   ELSEIF nKeyPress # 8 .AND. AllTrim(Str(nKeyPress)) $ [90]
      nKeyPress := 90
   ELSEIF nKeyPress # 8 .AND. AllTrim(Str(nKeyPress)) $ [96]
      nKeyPress := 48
   ELSEIF nKeyPress # 8 .AND. AllTrim(Str(nKeyPress)) $ [97]
      nKeyPress := 49
   ELSEIF nKeyPress # 8 .AND. AllTrim(Str(nKeyPress)) $ [98]
      nKeyPress := 50
   ELSEIF nKeyPress # 8 .AND. AllTrim(Str(nKeyPress)) $ [99]
      nKeyPress := 51
   ELSEIF nKeyPress # 8 .AND. AllTrim(Str(nKeyPress)) $ [100]
      nKeyPress := 52
   ELSEIF nKeyPress # 8 .AND. AllTrim(Str(nKeyPress)) $ [101]
      nKeyPress := 53
   ELSEIF nKeyPress # 8 .AND. AllTrim(Str(nKeyPress)) $ [102]
      nKeyPress := 54
   ELSEIF nKeyPress # 8 .AND. AllTrim(Str(nKeyPress)) $ [103]
      nKeyPress := 55
   ELSEIF nKeyPress # 8 .AND. AllTrim(Str(nKeyPress)) $ [104]
      nKeyPress := 56
   ELSEIF nKeyPress # 8 .AND. AllTrim(Str(nKeyPress)) $ [105]
      nKeyPress := 57
   ELSEIF nKeyPress # 8 .AND. AllTrim(Str(nKeyPress)) $ [106]
      nKeyPress := 42
   ELSEIF nKeyPress # 8 .AND. AllTrim(Str(nKeyPress)) $ [190]
      nKeyPress := 46
   ELSEIF nKeyPress == Asc("8") .AND. hwg_isCtrlShift( .F.,.T. )
      nKeyPress := 42      
   ENDIF   
   
   IF  nKeyPress = VK_RETURN
      CADCLIENTES( oServer, LTRIM(str(oDlg:oBrowse1:aArray[ oDlg:oBrowse1:nCurrent, 22])), "CONSULTAR"  )
      oDlg:oBrowse1:Refresh()
      RETURN .T.   
   ELSEIF nKeyPress = VK_ESCAPE
      oDlg:Close()      
      RETURN .T.
   ENDIF
      
   If nKeyPress # 8
      cProgressKey += Chr(nKeyPress)
      nPosicao:=AScan(oDlg:oBrowse1:aArray,cProgressKey)
      oDlg:oLabel4:settext(cProgressKey)
      cConsulta:= "WHERE " + cAlvo_Consulta + " LIKE '" + cProgressKey + "%'" + " ORDER BY CLIENTES_NRAZ_SOC"
      oBrowse1:aArray := CARREGA_CLIENTES( oServer, cConsulta )
      oDlg:obrowse1:REFRESH()
   ELSEIF nKeyPress = 8 .AND. Len(cProgressKey) >= 1
      cProgressKey:=Left(cProgressKey,Len(cProgressKey) - 1)
      nPosicao:=AScan(oDlg:oBrowse1:aArray,cProgressKey)
      oDlg:oLabel4:settext(cProgressKey)
      cConsulta:= "WHERE " + cAlvo_Consulta + " LIKE '" + cProgressKey + "%'" + " ORDER BY CLIENTES_NRAZ_SOC"
      oBrowse1:aArray := CARREGA_CLIENTES( oServer, cConsulta )
      oDlg:obrowse1:REFRESH()
   ENDIF   
   IF nPosicao # 0
      cConsulta:= "WHERE " + cAlvo_Consulta + " LIKE '" + cProgressKey + "%'" + " ORDER BY CLIENTES_NRAZ_SOC"
      oBrowse1:aArray := CARREGA_CLIENTES( oServer, cConsulta )
      oDlg:obrowse1:REFRESH()
   ENDIF 

return .T.   
   
***********************************************************
STATIC FUNCTION CADCLIENTES( oServer, cClientes_Id, cAcao )
***********************************************************

LOCAL     oDlg,  oStatus1, oLine1,oLine2, oEdit1, oLabel1, oEdit2, oLabel2, oEdit3 ;
      , oLabel3, oEdit4, oLabel4, oEdit5, oLabel5, oEdit6, oLabel6, oOwnerbutton1 ;
      , oCombo1, oLabel7, oLink1, oLink2, oEdit7, oLabel8, oEdit8, oLabel9, oEdit9 ;
      , oLabel10, oEdit10, oLabel11, oEdit11, oLabel12, oLabel13, oCombo2, oLabel14 ;
      , oCombo3, oLabel15, oEdit13, oLabel16, oEdit14, oLabel17, oCombo4, oEdit12 ;
      , oCombo5, oCombo6, oLabel19, oLabel18, oEdit15, oLabel20, oEdit16, oLabel21, oEdit17 ;
      , oLabel22, oOwnerbutton2, oOwnerbutton3, oOwnerbutton4, oPanel1, oLabel24, oLabel25, oLabel26 ;
      , oPAIS, oUF, oCIDADE;
      , cEdit1 := "" , nEdit2 := 0 , nEdit3 := 0 , nEdit4 := 0 , nEdit5 := 0 , cEdit6 := "" ;
      , cEdit7 := "" , nEdit8 := 0 , cEdit9 := "" , cEdit10 := "" , nEdit11 := 0  ;
      , cEdit13 := "" , cEdit14 := ""  , nEdit12 := 0 , nCombo5 := 1 , nEdit15 := 0 ;
      , dEdit16 := DATE() , dEdit17 := DATE() ;
      , oQuery;
      , cQuery;
      
private   aPAIS:= {};      
      , aUF:= {};
      , aMunicipios:= {};
      , nCombo1 := 1;
      , nCombo2 := 1;
      , nCombo6 := 1;
      , nCombo3 := 1;
      , nCombo4 := 1

   hb_Default( @cAcao, "CONSULTAR" )
   hb_Default( @cClientes_Id, "0" )
      
//   hwg_MsgInfo(cAcao + "/" + cClientes_Id)
//   RETURN NIL
      
   IF cAcao = "INCLUIR"
      MEMVAR->ID         :=0
      MEMVAR->TIPCLI     :=1
      MEMVAR->NRAZ_SOC   :=SPACE(60)
      MEMVAR->TIPDOC     :=1
      MEMVAR->CPFCGC     :=SPACE(18)
      MEMVAR->CPFCGC_ANT   :=SPACE(18)
      MEMVAR->INSEST     :=SPACE(18)
      MEMVAR->INSMUN     :=SPACE(18)
      MEMVAR->ISENTO     :=SPACE(01)
      MEMVAR->SUFRAMA    :=SPACE(18)
      MEMVAR->EMAIL      :=SPACE(60)
      MEMVAR->ENDER      :=SPACE(60)
      MEMVAR->NUMERO     :=0
      MEMVAR->COMPLEM    :=SPACE(60)
      MEMVAR->BAIR       :=SPACE(50)
      MEMVAR->CEP        :=space(09)
      MEMVAR->CODPAIS    :="1058"
      MEMVAR->PAIS       :="BRASIL"
      MEMVAR->UF         :="AC"
      MEMVAR->CIDADE     :="RIO BRANCO"
      MEMVAR->CODMUN     :="1200401"
      MEMVAR->FONE       :=SPACE(14)
      MEMVAR->CONTATO    :=SPACE(80)
      MEMVAR->LIMCRE     :=0.00
      MEMVAR->TOTCRE     :=0.00 
      MEMVAR->VENBLO     :="1"
      MEMVAR->DATCAD     :=M->DAT_HOJE
      MEMVAR->DATALT     :=M->DAT_HOJE
      MEMVAR->USUALT     :=M->OPERADOR
      MEMVAR->TAXCLI     :=0.00
      MEMVAR->NUMPAR     :=0.00
      MEMVAR->PERDES     :=0.00
      MEMVAR->VALMIN     :=0.00
   ELSE
      cQuery := "SELECT  CLIENTES_ID, ";
                  + "CLIENTES_TIPCLI, ";
                  + "CLIENTES_NRAZ_SOC, ";
                  + "CLIENTES_TIPDOC, ";
                  + "CLIENTES_CPFCGC, ";
                  + "CLIENTES_INSEST, ";
                  + "CLIENTES_INSMUN, ";
                  + "CLIENTES_ISENTO, ";
                  + "CLIENTES_SUFRAMA, ";
                  + "CLIENTES_EMAIL, ";
                  + "CLIENTES_ENDER, ";
                  + "CLIENTES_NUMERO, ";
                  + "CLIENTES_COMPLEM, ";
                  + "CLIENTES_BAIR, ";
                  + "CLIENTES_CEP, ";
                  + "CLIENTES_CODPAIS, ";
                  + "CLIENTES_PAIS, ";
                  + "CLIENTES_UF, ";
                  + "CLIENTES_CIDADE, ";
                  + "CLIENTES_CODMUN, ";
                  + "CLIENTES_FONE, ";
                  + "CLIENTES_CONTATO, ";
                  + "CLIENTES_LIMCRE, ";
                  + "CLIENTES_TOTCRE, ";
                  + "CLIENTES_VENBLO, ";
                  + "CLIENTES_DATCAD, ";
                  + "CLIENTES_DATALT, ";
                  + "CLIENTES_USUALT, ";
                  + "CLIENTES_TAXCLI, ";
                  + "CLIENTES_NUMPAR, ";
                  + "CLIENTES_PERDES, ";
                  + "CLIENTES_VALMIN ";
                  + "FROM CLIENTES ";
                  + "WHERE CLIENTES_ID = ";
                  + "'" + cClientes_Id + "'"
               
      oQuery := oServer:Execute(cQuery)         
   
      MEMVAR->ID         :=cClientes_Id
      MEMVAR->TIPCLI     :=VAL(oQuery:Fields( "CLIENTES_TIPCLI" ):Value)
      MEMVAR->NRAZ_SOC   :=oQuery:Fields( "CLIENTES_NRAZ_SOC" ):Value
      MEMVAR->TIPDOC     :=VAL(oQuery:Fields( "CLIENTES_TIPDOC" ):Value)
      MEMVAR->CPFCGC     :=oQuery:Fields( "CLIENTES_CPFCGC" ):Value
      MEMVAR->INSEST     :=oQuery:Fields( "CLIENTES_INSEST" ):Value
      MEMVAR->INSMUN     :=oQuery:Fields( "CLIENTES_INSMUN" ):Value
      MEMVAR->ISENTO     :=oQuery:Fields( "CLIENTES_ISENTO" ):Value
      MEMVAR->SUFRAMA    :=oQuery:Fields( "CLIENTES_SUFRAMA" ):Value
      MEMVAR->EMAIL      :=oQuery:Fields( "CLIENTES_EMAIL" ):Value
      MEMVAR->ENDER      :=oQuery:Fields( "CLIENTES_ENDER" ):Value
      MEMVAR->NUMERO     :=oQuery:Fields( "CLIENTES_NUMERO" ):Value
      MEMVAR->COMPLEM    :=oQuery:Fields( "CLIENTES_COMPLEM" ):Value
      MEMVAR->BAIR       :=oQuery:Fields( "CLIENTES_BAIR" ):Value
      MEMVAR->CEP        :=oQuery:Fields( "CLIENTES_CEP" ):Value
      MEMVAR->CODPAIS    :=oQuery:Fields( "CLIENTES_CODPAIS" ):Value
      MEMVAR->PAIS       :=oQuery:Fields( "CLIENTES_PAIS" ):Value
      MEMVAR->UF         :=oQuery:Fields( "CLIENTES_UF" ):Value
      MEMVAR->CIDADE     :=oQuery:Fields( "CLIENTES_CIDADE" ):Value
      MEMVAR->CODMUN     :=oQuery:Fields( "CLIENTES_CODMUN" ):Value
      MEMVAR->FONE       :=oQuery:Fields( "CLIENTES_FONE" ):Value
      MEMVAR->CONTATO    :=oQuery:Fields( "CLIENTES_CONTATO" ):Value
      MEMVAR->LIMCRE     :=oQuery:Fields( "CLIENTES_LIMCRE" ):Value
      MEMVAR->TOTCRE     :=oQuery:Fields( "CLIENTES_TOTCRE" ):Value
      MEMVAR->VENBLO     :=oQuery:Fields( "CLIENTES_VENBLO" ):Value
      MEMVAR->DATCAD     :=oQuery:Fields( "CLIENTES_DATCAD" ):Value
      MEMVAR->DATALT     :=M->DAT_HOJE
      MEMVAR->USUALT     :=M->OPERADOR
      MEMVAR->TAXCLI     :=oQuery:Fields( "CLIENTES_TAXCLI" ):Value
      MEMVAR->NUMPAR     :=oQuery:Fields( "CLIENTES_NUMPAR" ):Value
      MEMVAR->PERDES     :=oQuery:Fields( "CLIENTES_PERDES" ):Value
      MEMVAR->VALMIN     :=oQuery:Fields( "CLIENTES_VALMIN" ):Value
      
      MEMVAR->CPFCGC_ANT   :=MEMVAR->CPFCGC
   ENDIF

   FOR EACH oPAIS IN SEFAZ_CIDADE
      IF oPAIS[1] == "EX"
         AAdd(aPAIS,oPAIS[3])
      ENDIF
   NEXT
   
   FOR EACH oUF IN SEFAZ_UF
      AAdd(aUF,oUF[1])
   NEXT
   
   FOR EACH oCIDADE IN SEFAZ_CIDADE
      IF oCIDADE[1] == MEMVAR->UF
         AAdd(aMunicipios,oCIDADE[3])
      ENDIF
   NEXT
      
********************************************************************************

  INIT DIALOG oDlg TITLE "Cadastro de Cliente - "+cAcao ;
      ICON MEMVAR->SGC_ICON  ;
      AT 0, 0 SIZE 1008,600 CLIPPER  NOEXIT 
      
    ThisCAD := oDlg
   hwg_SetColorinFocus( oDlg,, 13172680 )

//    ADD STATUS PANEL TO oDlg HEIGHT 30  PARTS 200,120,300
   @ 0,175 LINE oLine1 LENGTH 1008
        oLine1:Anchor := 11
   @ 415,15 SAY oLink1 CAPTION "http://www.sintegra.gov.br"  ;
        LINK 'http://www.sintegra.gov.br/new_bv.html'  SIZE 180,22       
   @ 79,17 SAY oLabel2 CAPTION "CNPJ/CPF"  SIZE 67,21       
   @ 150,15 GET oEdit2 VAR MEMVAR->CPFCGC SIZE 201,24 ;
        STYLE ES_LEFT  MAXLENGTH 14   VALID  {|| VERIFICA_CPFCNPJ( oDlg, oServer ) }
      
   @ 16,49 SAY oLabel1 CAPTION "Nome/Razão Social"  SIZE 131,21
   @ 150,47 GET oEdit1 VAR MEMVAR->NRAZ_SOC SIZE 657,24 STYLE ES_UPPERCASE PICTURE '@!' MAXLENGTH 60 VALID  {|| VERIFICA_NRAZ_SOC( oDlg, cAcao ) }
        oEdit1:Anchor := 11
   @ 25,81 SAY oLabel3 CAPTION "Inscrição Estadual"  SIZE 122,21   
   @ 150,79 GET oEdit3 VAR MEMVAR->INSEST SIZE 202,24 ;
        STYLE ES_LEFT  MAXLENGTH 15  ;
        VALID  {|| oEdit3_onLostFocus(  ) }
      
   @ 404,81 SAY oLabel7 CAPTION "Tipo Contribuinte"  SIZE 112,21
   @ 521,79 GET COMBOBOX oCombo1 VAR nCombo1 ;
        ITEMS aISENTO  ;
        SIZE 218,24 
   @ 18,113 SAY oLabel4 CAPTION "Inscrição Municipal"  SIZE 128,21       
   @ 150,111 GET oEdit4 VAR MEMVAR->INSMUN SIZE 202,24 ;
        STYLE ES_RIGHT  MAXLENGTH 15       
   @ 397,113 SAY oLabel5 CAPTION "Inscrição Suframa"  SIZE 119,21      
   @ 521,111 GET oEdit5 VAR MEMVAR->SUFRAMA SIZE 201,24 ;   
        STYLE ES_RIGHT  MAXLENGTH 15   
   @ 101,146 SAY oLabel6 CAPTION "E-Mail"  SIZE 43,21      
   @ 149,144 GET oEdit6 VAR MEMVAR->EMAIL SIZE 657,24 STYLE ES_LOWERCASE MAXLENGTH 60 
        oEdit6:Anchor := 11       
   @ 69,185 SAY oLabel9 CAPTION "CEP"  SIZE 29,24 
   @ 105,183 GET oEdit8 VAR MEMVAR->CEP SIZE 80,24  STYLE ES_RIGHT PICTURE '99999-999'  MAXLENGTH 9
   
   @ 246,187 SAY oLink2 CAPTION "http://www.correios.com.br"  ;
        LINK 'http://www.buscacep.correios.com.br/sistemas/buscacep/buscaEndereco.cfm'  SIZE 181,22   
   
   @ 22,216 SAY oLabel10 CAPTION "Logradouro"  SIZE 76,24 
   @ 105,214 GET oEdit9 VAR MEMVAR->ENDER SIZE 703,24 STYLE ES_UPPERCASE PICTURE '@!' MAXLENGTH 60 
        oEdit9:Anchor := 11   
   @ 45,248 SAY oLabel11 CAPTION "Numero"  SIZE 53,21
   @ 105,246 GET oEdit11 VAR MEMVAR->NUMERO SIZE 80,24 ;
        STYLE ES_RIGHT  MAXLENGTH 20
   @ 7,280 SAY oLabel8 CAPTION "Complemento"  SIZE 91,24
   @ 104,278 GET oEdit7 VAR MEMVAR->COMPLEM SIZE 490,24 STYLE ES_UPPERCASE PICTURE '@!' MAXLENGTH 60       
   @ 56,311 SAY oLabel12 CAPTION "Bairro"  SIZE 42,24 
   @ 105,309 GET oEdit13 VAR MEMVAR->BAIR SIZE 490,24 STYLE ES_UPPERCASE PICTURE '@!' MAXLENGTH 50
   @ 67,341 SAY oLabel13 CAPTION "Pais"  SIZE 31,24 
   @ 105,339 GET COMBOBOX oCombo4 VAR nCombo4 ;
        ITEMS aPAIS  ;
        SIZE 259,24  DISPLAYCOUNT 8   
   @ 78,376 SAY oLabel14 CAPTION "UF"  SIZE 20,24
   @ 105,374 GET COMBOBOX oCombo2 VAR nCombo2 ;
        ITEMS aUF  ;
        SIZE 65,24  DISPLAYCOUNT 8 ;
      ON CHANGE {|| oCombo2_onChange( oDlg, aUF[nCombo2] ),oCombo3:REFRESH() }
      
   @ 33,407 SAY oLabel15 CAPTION "Municipio"  SIZE 65,24
   @ 105,405 GET COMBOBOX oCombo3 VAR nCombo3  ITEMS aMunicipios  ;
        SIZE 259,24 DISPLAYCOUNT 7 
      
   @ 40,436 SAY oLabel16 CAPTION "Telefone"  SIZE 58,24       
   @ 105,434 GET oEdit10 VAR MEMVAR->FONE SIZE 260,24  MAXLENGTH 14  ;
         VALID  {|| oEdit10_onLostFocus(  ) } 
   
   @ 47,465 SAY oLabel17 CAPTION "Contato"  SIZE 51,24
   @ 105,463 GET oEdit14 VAR MEMVAR->CONTATO SIZE 495,24  MAXLENGTH 80 


   @ 355,14 OWNERBUTTON oOwnerbutton1  SIZE 24,24 ;
        TEXT ''  ;
        COORDINATES 0, 0, 0, 0  ;
        BITMAP 'FINDBMP' FROM RESOURCE TRANSPARENT;
        COORDINATES 0, 0, 0, 0 ;
      ON CLICK {|| oEdit2:setfocus(), CADASTROCLIENTES_CONSULTA_CNPJ(  ) }

   @ 191,183 OWNERBUTTON oOwnerbutton4  SIZE 24,24   ;
        TEXT ''  ;
        COORDINATES 0, 0, 0, 0  ;
        BITMAP 'FINDBMP' FROM RESOURCE TRANSPARENT;
        COORDINATES 0, 0, 0, 0 ;
      ON CLICK {|| oEdit8:setfocus(), CADASTROCLIENTES_CONSULTA_CEP( MEMVAR->CEP )}

   IF cAcao != "CONSULTAR"
      @ 904,560  OWNERBUTTON oOwnerbutton2  SIZE 98,32 DISABLED  ;
         TEXT 'Salvar'  ;
         COORDINATES 30, 0, 0, 0  ;
         BITMAP 'APPLYBMP' FROM RESOURCE TRANSPARENT;
         COORDINATES 5, 0, 0, 0;
         ON CLICK {|| SALVA_CLIENTES( oServer, cClientes_Id, cAcao ), hwg_Enddialog() }      
         oOwnerbutton2:Anchor := 12
   ENDIF

   @ 830,240 GROUPBOX oGroup1 CAPTION ""  SIZE 173,267

   @ 840,251 SAY oLabel21 CAPTION "Faturamento"  SIZE 110,21
   @ 840,272 GET COMBOBOX oCombo6 VAR nCombo6 ITEMS aVENBLO SIZE 154,24  ;
      ON CHANGE {|| oCombo6_onChange( oCombo6:GETTEXT( ) ) }

   @ 840,297 SAY oLabel23 CAPTION "Limite de crédito"  SIZE 110,21
   @ 840,319 GET oEdit18 VAR MEMVAR->LIMCRE SIZE 154,24 ;
        STYLE ES_RIGHT +WS_DISABLED  PICTURE '@E 999,999,999.99' MAXLENGTH 14   
      
   @ 840,344 SAY oLabel18 CAPTION "Utilizado"  SIZE 60,21
   @ 840,366 GET oEdit12 VAR MEMVAR->TOTCRE SIZE 154,24 ;
        STYLE ES_RIGHT+WS_DISABLED  PICTURE '@E 999,999,999.99' MAXLENGTH 14

      
   @ 840,392 SAY oLabel19 CAPTION "Data Inclusão"  SIZE 91,21 ;

   @ 840,415 SAY oLabel24 CAPTION dtoc(MEMVAR->DATCAD)  SIZE 154,30 ;
      STYLE WS_BORDER+SS_CENTER ;
      COLOR 16777215  BACKCOLOR 255  ;
      FONT HFont():Add( '',0,-21,400,,,)

   @ 840,449 SAY oLabel20 CAPTION "Data ultima Alteração"  SIZE 141,21 ;

   @ 840,470 SAY oLabel25 CAPTION dtoc(MEMVAR->DATALT)  SIZE 154,30 ;
      STYLE WS_BORDER+SS_CENTER ;
      COLOR 16777215  BACKCOLOR 255  ;
      FONT HFont():Add( '',0,-21,400,,,) 
   
   IF MEMVAR->UF # "AC"
      oCombo2_onChange( oDlg, MEMVAR->UF )   
   ENDIF

   oCombo6:SetItem( Ascan(aVENBLO,MEMVAR->VENBLO ) )      
   oCombo1:SetItem( Ascan(aISENTO,MEMVAR->ISENTO ) )   
   oCombo4:SetItem( Ascan(aPAIS,RTRIM(MEMVAR->PAIS) ) )   
   oCombo2:SetItem( Ascan(aUF,RTRIM(MEMVAR->UF) ) )   
   oCombo3:SetItem( Ascan(aMunicipios,RTRIM(MEMVAR->CIDADE) ) )
   

   ACTIVATE DIALOG oDlg CENTER

RETURN NIL

************************************************
STATIC FUNCTION VERIFICA_NRAZ_SOC( oDlg, cAcao )
************************************************
IF cAcao = "CONSULTAR"
   RETURN .T.
ENDIF

IF MEMVAR->NRAZ_SOC = SPACE(60)
   oDlg:oOwnerbutton2:DISABLE()
   RETURN .F.
ELSE
   oDlg:oOwnerbutton2:ENABLE()   
   RETURN .T.
ENDIF

**************************************************
STATIC FUNCTION oCombo2_onChange( oDlg, mUF )
**************************************************
LOCAL oCIDADE
   DO WHILE .T.
   
      FOR nI = Len( aMunicipios ) TO 1 STEP -1
         hb_ADel( aMunicipios, nI, .T. )
      NEXT
//      FOR nI := 1 TO Len(aMunicipios)
//         hb_ADel( aMunicipios, nI, .T. )
//      NEXT
      IF Len(aMunicipios) <= 0
         EXIT
      ENDIF
   ENDDO
   FOR EACH oCIDADE IN SEFAZ_CIDADE
      IF oCIDADE[1] == mUF
         AAdd(aMunicipios,oCIDADE[3])
      ENDIF
   NEXT
   oDlg:oCombo3:SetItem( Ascan(aMunicipios,RTRIM(MEMVAR->CIDADE) ) )
//   nCombo3 := 1
RETURN( aMunicipios )
******************************************************
STATIC FUNCTION CADASTROCLIENTES_CONSULTA_CNPJ(  )
******************************************************
LOCAL oDlg,  oOwnerbutton2, oOwnerbutton3, oCNPJ, oLabel1, oLabel2, oBitmap1, oCombo1

Local  cCNPJ := mCPFCGC , nCombo1 := 1
   SELE CERTIFICADO
   IF !DBSEEK(rtrim(hwg_GetComputerName()))
      hwg_MsgInfo("Este Computador não possui CERTIFICADO DIGITAL instalado"+ HB_EOL()+"Pesquisa não poderá ser efetuada")
      SELE CLIENTES
      return .T.
   endif
   SELE CLIENTES

   INIT DIALOG oDlg TITLE "CONSULTA CNPJ"  ;
      ICON MEMVAR->SGC_ICON  ;
      AT 0, 0 SIZE 445,168 CLIPPER  NOEXIT 
      
    ThisCNPJ := oDlg

   hwg_SetColorinFocus( oDlg,, 13172680 )

   @ 24,35 BITMAP oBitmap1  SHOW 'searchonline' FROM RESOURCE  SIZE 62,62 
      
   @ 333,100 OWNERBUTTON oOwnerbutton2  SIZE 98,32  ;
        TEXT "Pesquisa"  ;
        COORDINATES 30, 0, 0, 0  ;
        BITMAP 'APPLYBMP' FROM RESOURCE TRANSPARENT;
        COORDINATES 5, 0, 0, 0;
      ON CLICK {|| CADASTROCLIENTES_PESQUISA_CNPJ(cCNPJ,aUF[nCombo1] ), oDlg:close() }      
        oOwnerbutton2:Anchor := 12
      
      
   @ 188,29 GET oCNPJ VAR cCNPJ SIZE 246,24  MAXLENGTH 14   
   @ 110,32 SAY oLabel1 CAPTION "CNPJ:"  SIZE 72,21 ;
        STYLE SS_RIGHT 
   @ 158,68 SAY oLabel2 CAPTION "UF:"  SIZE 24,21 
   @ 188,65 GET COMBOBOX oCombo1 VAR nCombo1 ;
        ITEMS aUF ;
        SIZE 63,24 DISPLAYCOUNT 5 

   ACTIVATE DIALOG oDlg CENTER

RETURN oDlg:lresult
***************************************************************
STATIC FUNCTION CADASTROCLIENTES_PESQUISA_CNPJ( cCNPJ,cUF)
***************************************************************
   DBSELECTAREA("CERTIFICADO")
   IF !DBSEEK(rtrim(hwg_GetComputerName()))
      hwg_MsgInfo("Computador sem certificado digital instalado"+ HB_EOL()+"A Operação não poderá ser efetuada")
      DBSELECTAREA("CLIENTES")
      RETURN NIL
   endif
   DBSELECTAREA("CLIENTES")
   IF LEN(RTRIM(cCNPJ)) < 14
      hwg_MsgInfo("CONSULTA AO CADASTRO DE CONTRIBUINTES SOMENTE POR CNPJ "+ HB_EOL()+ HB_EOL()+ "Clique no LINK para acesso ao SINTEGRA" )
      RETURN NIL
   ENDIF
   oSefaz:= SefazClass():New()
   oSefaz:cCertificado := TRIM(CERTIFICADO->NOMCERT)
//   hwg_MsgInfo("["+TRIM(cCnpj)+"]"+"["+cUF+"]")
   cRetorno:=oSefaz:NFeConsultaCadastro( TRIM(cCnpj), cUF, oSefaz:cCertificado, FLAG->n_tpAmb )

   if XmlNode(cRetorno, "cStat") $ "111,112"
      cStat       :=XmlNode(cRetorno, "cStat")
      xMotivo       :=XmlNode(cRetorno, "xMotivo")
      m->leitura  :=XmlNode(cRetorno, "infCad")
      mCPFCGC     :=cCNPJ
      mNRAZ_SOC    :=XmlNode(cRetorno, "xNome") + space(60-len(XmlNode(cRetorno, "xNome")))
      mNRAZ_FANT   :=XmlNode(cRetorno, "xFant") + space(60-len(XmlNode(cRetorno, "xFant")))
      mINSEST      :=XmlNode(cRetorno, "IE") + space(18-len(XmlNode(cRetorno, "IE")))
      mISENTO      :=XmlNode(cRetorno, "cSit")
      mCEP         :=SUBSTR(XmlNode(cRetorno, "CEP"),1,5)+"-"+SUBSTR(XmlNode(cRetorno, "CEP"),6,3)
      mNUMERO      :=val(XmlNode(cRetorno, "nro"))
      mBAIR        :=XmlNode(cRetorno, "xBairro")
      mCIDADE      :=XmlNode(cRetorno, "xMun")
      mUF          :=XmlNode(cRetorno, "UF")
      mENDER       :=XmlNode(cRetorno, "xLgr")
      IF cStat = "112"
         cRetorno := "ACESSE AO SINTEGRA: http://www.sintegra.gov.br"+ HB_EOL()+ "PARA CONSULTA DETALHADA"
      ENDIF
      IF LEN(cCNPJ) < 14
         mCPFCGC:=replicate("0",14-LEN(cCNPJ))+cCNPJ
      endif

//      hwg_MsgInfo(mCPFCGC)

      IF ! ValidIE( RTRIM(mINSEST), mUF )
         mINSEST:="0"+mINSEST
      ENDIF
      IF mISENTO = "0"
         mISENTO = "2"
         mINSEST:= SPACE(18)
      ENDIF
//      hwg_MsgInfo( ;
//                "STATUS: " + cStat + hb_Eol()+ ;
//                "MOTIVO: " + xMotivo + hb_Eol()+hb_Eol()+ ;
//                "CNPJ: " + cCNPJ + hb_Eol() + ;
//                "RAZAO SOCIAL: " + mNRAZ_SOC + hb_Eol() + ;
//                "NOME FANTASIA: " + mNRAZ_FANT + hb_Eol() + ;
//                "INSC.EST.: " + mINSEST + hb_Eol() + ;
//                "TIPO CONT.: " + mISENTO + hb_Eol() + ;
//                "CEP.: " + mCEP + hb_Eol() + ;
//                "ENDERECO: " + mENDER + hb_Eol() + ;
//                "NUMERO: " + XmlNode(m->leitura, "nro") + hb_Eol() + ;
//                "BAIRRO: " + mBAIR + hb_Eol() + ;
//                "CIDADE: " + mCIDADE + hb_Eol() + ;
//                "UF: " + mUF + hb_Eol() + hb_Eol() ,"CONSULTA CADASTRO DE CONTRIBUINTE")
   ELSE
      hwg_MsgInfo("STATUS: " + XmlNode(cRetorno, "cStat") + hb_Eol() + "MOTIVO: " + XmlNode(cRetorno, "xMotivo") + hb_Eol()+ hb_Eol() ,"CONSULTA CADASTRO DE CONTRIBUINTE")
      IF XmlNode(cRetorno, "cStat") $ "259"
         mISENTO   :="9"
      ENDIF
   ENDIF
   ThisCAD:oEdit2:REFRESH()
   ThisCAD:oEdit1:REFRESH()
   ThisCAD:oEdit3:REFRESH()
   ThisCAD:oEdit8:REFRESH()   
   ThisCAD:oEdit9:REFRESH()   
   ThisCAD:oEdit11:REFRESH()
   ThisCAD:oEdit13:REFRESH()
   ThisCAD:oCombo2:SetItem( Ascan(aUF,mUF ) )
   ThisCAD:oCombo2:REFRESH()   
   ThisCAD:oCombo3:SetItem( Ascan(aMunicipios,RTRIM(mCIDADE) ) )
   ThisCAD:oCombo3:REFRESH()
RETURN
   
***********************************************************
static FUNCTION CADASTROCLIENTES_CONSULTA_CEP( mCEP )
***********************************************************
LOCAL oHttp, cXML, cCep
LOCAL cRes, cResTxt, cUf, cCidade, cTipo, cEnde, cBairro

DO WHILE .T.
   IF mCEP = '     -   ' .OR. mCEP = SPACE(09)
      hwg_MsgInfo(  "o CEP esta em branco, verifique!" )
      RETURN .F.
   ENDIF

   oHttp:= TIpClientHttp():new( "http://www.jpatecnologia.com.br/cep.asp?cep="+substr(mCEP,1,5)+'-'+substr(mCEP,7,3)+"&clipper=1" )
   IF ! oHttp:open()
      hwg_MsgInfo(  "Erro na conecção: "+ oHttp:lastErrorMessage() )
      RETURN .T.
   ENDIF
   cXML := oHttp:readAll()
   oHttp:close()

   IF Empty(cXML)
**      hwg_MsgInfo( "Ocorreu um erro inesperado. Tente outro CEP...")
      return .t.
   ENDIF

   MEMVAR->Uf          := XmlNode(cXml, "uf")
   MEMVAR->CIDADE      := XmlNode(cXml, "cidade")
   MEMVAR->ENDER      := XmlNode(cXml, "logradouro")
   MEMVAR->BAIR      := XmlNode(cXml, "bairro")

   ThisCAD:oEdit8:REFRESH()
   ThisCAD:oEdit9:REFRESH()
   ThisCAD:oEdit11:REFRESH()
   ThisCAD:oEdit13:REFRESH()
   ThisCAD:oCombo2:SetItem( Ascan(aUF,MEMVAR->Uf ) )
   ThisCAD:oCombo2:REFRESH()   
   ThisCAD:oCombo3:SetItem( Ascan(aMunicipios,MEMVAR->CIDADE ) )
   ThisCAD:oCombo3:REFRESH()
   
   return .T.
   
ENDDO
*****************************************
STATIC FUNCTION oEdit10_onLostFocus( )
*****************************************
   IF LEN(RTRIM(MEMVAR->FONE)) = 0
       RETURN .T.
   ENDIF
   IF LEN(RTRIM(MEMVAR->FONE)) < 10
       hwg_MsgInfo("FORMATO DE NUMERO DE TELEFONE INVALIDO"+ HB_EOL()+ HB_EOL() + "DEVE CONTER NO MINIMO 10 DIGITOS")
       RETURN .F.
   ENDIF
RETURN .T.

*****************************************
STATIC FUNCTION oCombo6_onChange( valor )
*****************************************

   IF substr(valor,1,1) = "0"
       ThisCAD:oedit18:Enable()
       ThisCAD:oedit12:Enable()
   ELSE
       ThisCAD:oedit18:Disable()
       ThisCAD:oedit12:Disable()
   ENDIF

RETURN
********************************************
STATIC FUNCTION oEdit18_onInit( valor )
********************************************
   IF substr(valor,1,1) = "0"
             ThisCAD:oedit18:Enable()
             ThisCAD:oedit12:Enable()
         ELSE
             ThisCAD:oedit18:Disable()
             ThisCAD:oedit12:Disable()
         ENDIF
      RETURN
************************************************************       
STATIC FUNCTION VERIFICA_CPFCNPJ( oDlg, oServer )
************************************************************   
LOCAL cQuery;
   , oQuery_cpfcnpj;

   IF RTRIM(MEMVAR->CPFCGC) # RTRIM(MEMVAR->CPFCGC_ANT)
      IF LEN(RTRIM(MEMVAR->CPFCGC)) < 12
         IF !VDV2(MEMVAR->CPFCGC)
            RETURN .F.
         ENDIF
      ELSE
         IF !VCGC(MEMVAR->CPFCGC)
            RETURN .F.
         ENDIF
      ENDIF
      
      cQuery          := "SELECT CLIENTES_NRAZ_SOC, CLIENTES_CPFCGC FROM CLIENTES WHERE CLIENTES_CPFCGC = " + MEMVAR->CPFCGC
      oQuery_cpfcnpj    := oServer:Execute(cQuery)
      
      IF ! oQuery_cpfcnpj:Eof()
         hwg_MsgInfo("CPF/CNPJ já existe no cadastro" + HB_EOL() + oQuery_cpfcnpj:Fields( "CLIENTES_NRAZ_SOC" ):Value +HB_EOL() + "CNPJ/CPF: "+ oQuery_cpfcnpj:Fields( "CLIENTES_CPFCGC" ):Value, "Atenção !!!")
         IF PERG( "Continua a Fazer o Cadastro com CNPJ/CPF já cadastrado ?" ) = "N"
            oQuery_cpfcnpj:close()
            RETURN .F.
         ENDIF
      ENDIF
      oQuery_cpfcnpj:close()   
   ENDIF
   
RETURN .T.
********************************************
STATIC FUNCTION oEdit3_onLostFocus
********************************************
*   If mINSEST != Space(15)
*          If ! ValidIE( Rtrim(mINSEST), mUF )
*               hwg_MsgInfo("INSCRICAO ESTADUAL INVALIDA"+ HB_EOL() )
*               Return .F.
*           ENDIF
*       Endif
    Return .T.
   
****************************************************************************************
STATIC FUNCTION SALVA_CLIENTES( oServer, cClientes_Id, cAcao )
****************************************************************************************
LOCAL oPAIS, oUF, oCIDADE;
   , cQuery1;
   , cQuery2;

   IF cAcao = 'INCLUIR'
      cQuery1   :="INSERT INTO CLIENTES ( "
      cQuery2   :=" VALUES ("
      
      cQuery1 += "CLIENTES_TIPCLI, "
      cQuery2   += "'" + strzero(MEMVAR->TIPCLI,1,0) + "', "
      
      cQuery1 += "CLIENTES_NRAZ_SOC, "
      cQuery2   +="'" + rtrim(TIRACENTO(upper(MEMVAR->NRAZ_SOC))) + "', "
      
      cQuery1 += "CLIENTES_TIPDOC, "
      IF  LEN(RTRIM(MEMVAR->CPFCGC)) < 12   
         cQuery2   +="'1', "
      ELSE
         cQuery2   +="'2', "
      ENDIF

      
      IF ! EMPTY(MEMVAR->CPFCGC)
         cQuery1 += "CLIENTES_CPFCGC, "
         cQuery2   +="'" + rtrim(MEMVAR->CPFCGC) + "', "
      ENDIF
      
      
      IF ! EMPTY(MEMVAR->INSEST)
         cQuery1 += "CLIENTES_INSEST, "
         cQuery2   +="'" + rtrim(MEMVAR->INSEST) + "', "
      ENDIF
      
      
      IF ! EMPTY(MEMVAR->INSMUN)
         cQuery1 += "CLIENTES_INSMUN, "
         cQuery2   +="'" + rtrim(MEMVAR->INSMUN) + "', "
      ENDIF

      IF nCombo1 = 0
         nCombo1 := 1
      ENDIF      
      cQuery1 += "CLIENTES_ISENTO, "
      cQuery2   +="'" + SUBSTR(aISENTO[nCombo1],1,1) + "', "

      IF ! EMPTY(MEMVAR->SUFRAMA)
         cQuery1 += "CLIENTES_SUFRAMA, "
         cQuery2   +="'" + rtrim(MEMVAR->SUFRAMA) + "', "
      ENDIF

      IF ! EMPTY(MEMVAR->EMAIL)
         IF EMAIL_VALIDO(MEMVAR->EMAIL)
            cQuery1 += "CLIENTES_EMAIL, "
            cQuery2   +="'" + rtrim(MEMVAR->EMAIL) + "', "
         endif
      ENDIF   
      
      IF ! EMPTY(MEMVAR->ENDER)
         cQuery1 += "CLIENTES_ENDER, "
         cQuery2   +="'" + rtrim(MEMVAR->ENDER) + "', "
      ENDIF   

      cQuery1 += "CLIENTES_NUMERO, "
      cQuery2   +="'" + strzero(MEMVAR->NUMERO,9,0) + "', "
      
      IF ! EMPTY(MEMVAR->COMPLEM)
         cQuery1 += "CLIENTES_COMPLEM, "
         cQuery2   +="'" + rtrim(MEMVAR->COMPLEM) + "', "
      ENDIF

      
      IF ! EMPTY(MEMVAR->BAIR)
         cQuery1 += "CLIENTES_BAIR, "
         cQuery2   +="'" + rtrim(MEMVAR->BAIR) + "', "
      ENDIF

      
      IF ! EMPTY(MEMVAR->CEP)
         cQuery1 += "CLIENTES_CEP, "
         cQuery2   +="'" + rtrim(MEMVAR->CEP) + "', "
      ENDIF
      
      
      cQuery1 += "CLIENTES_PAIS, "
      cQuery2 += "'" + aPAIS[nCombo4] + "', "

      
      FOR EACH oPAIS IN SEFAZ_CIDADE
         IF oPAIS[3] == aPAIS[nCombo4]
            cQuery1 += "CLIENTES_CODPAIS, "
            cQuery2 += "'" + SUBSTR(oPAIS[2],3,4) + "', "
         ENDIF
      NEXT             
      
      cQuery1 += "CLIENTES_UF, "
      cQuery2 += "'"   + aUF[nCombo2] + "', " 

      cQuery1 += "CLIENTES_CIDADE, "
      cQuery2 += "'" + aMunicipios[nCombo3] + "', " 

      
      FOR EACH oCIDADE IN SEFAZ_CIDADE
         IF oCIDADE[1] == aUF[nCombo2] .AND. oCIDADE[3] == aMunicipios[nCombo3]
            cQuery1 += "CLIENTES_CODMUN, "
            cQuery2 += "'"   + oCIDADE[2] + "', "
         ENDIF
      NEXT

      cQuery1 += "CLIENTES_FONE, "
      cQuery2   +="'" + rtrim(MEMVAR->FONE) + "', "
      
      cQuery1 += "CLIENTES_CONTATO, "
      cQuery2   +="'" + rtrim(MEMVAR->CONTATO) + "', "
      
      cQuery1 += "CLIENTES_LIMCRE, "
      cQuery2   +="'" + strzero(MEMVAR->LIMCRE,14,2) + "', "
      
      cQuery1 += "CLIENTES_TOTCRE, "
      cQuery2   +="'" + strzero(MEMVAR->TOTCRE,14,2) + "', "
      
      cQuery1 += "CLIENTES_VENBLO, "
      cQuery2   +="'" + SUBSTR(aVENBLO[nCombo6],1,1) + "', "
      
      cQuery1 += "CLIENTES_DATCAD, "
      cQuery2   +="'" + strzero(year(MEMVAR->DATCAD),4,0) + "-" + strzero(month(MEMVAR->DATCAD),2,0) + "-" + strzero(day(MEMVAR->DATCAD),2,0) + "', "
      
      cQuery1 += "CLIENTES_DATALT, "
      cQuery2   +="'" + strzero(year(MEMVAR->DATALT),4,0) + "-" + strzero(month(MEMVAR->DATALT),2,0) + "-" + strzero(day(MEMVAR->DATALT),2,0) + "', "
      
      cQuery1 += "CLIENTES_USUALT, "
      cQuery2   +="'" + rtrim(MEMVAR->USUALT) + "', "
      
      cQuery1 += "CLIENTES_TAXCLI, "
      cQuery2   +="'" + strzero(MEMVAR->TAXCLI,5,2) + "', "
      
      cQuery1 += "CLIENTES_NUMPAR, "
      cQuery2   +="'" + strzero(MEMVAR->NUMPAR,2,0) + "', "
      
      cQuery1 += "CLIENTES_PERDES, "
      cQuery2   +="'" + strzero(MEMVAR->PERDES,5,2) + "', "
      
      cQuery1 += "CLIENTES_VALMIN, "
      cQuery2   +="'" + strzero(MEMVAR->VALMIN,5,0) + "', "
      
      cQuery1 += "CLIENTES_QUEM_BLOQ ) "
      cQuery2   +="'" + rtrim(M->OPERADOR)+"/"+rtrim(hwg_GetComputerName()+" ["+dtoc(M->DAT_HOJE)+" "+time()+"]") + "' )"
      
//      HB_GTINFO( HB_GTI_CLIPBOARDDATA, cQuery1+cQuery2)
      
      oQuery := oServer:Execute(cQuery1+cQuery2)
            
   ELSE
      cQuery1   :="UPDATE CLIENTES SET "
      cQuery1  +="CLIENTES_TIPCLI = '" + strzero(MEMVAR->TIPCLI,1,0) + "', "
            
      IF strzero(M->NIV_ACESSO,1,0)$"89"      
         cQuery1 += "CLIENTES_NRAZ_SOC = '"   + rtrim(TIRACENTO(upper(MEMVAR->NRAZ_SOC))) + "', "
      ENDIF
      
      IF  LEN(RTRIM(MEMVAR->CPFCGC)) < 12
         cQuery1 += "CLIENTES_TIPDOC ='1', "
      ELSE
         cQuery1 += "CLIENTES_TIPDOC ='2', "
      ENDIF
      
      IF ! EMPTY(MEMVAR->CPFCGC)
         cQuery1 += "CLIENTES_CPFCGC = '"   + rtrim(MEMVAR->CPFCGC) + "', "
      ENDIF
      IF ! EMPTY(MEMVAR->INSEST)
         cQuery1 += "CLIENTES_INSEST = '" + rtrim(MEMVAR->INSEST) + "', "
      ENDIF
      IF ! EMPTY(MEMVAR->INSMUN)
         cQuery1 += "CLIENTES_INSMUN = '" + rtrim(MEMVAR->INSMUN) + "', "
      ENDIF
            
      IF nCombo1 = 0
         nCombo1 := 1
      ENDIF      
      
      cQuery1 += "CLIENTES_ISENTO = '" + SUBSTR(aISENTO[nCombo1],1,1) + "', "

      IF ! EMPTY(MEMVAR->SUFRAMA)
         cQuery1 += "CLIENTES_SUFRAMA = '" + rtrim(MEMVAR->SUFRAMA) + "', "
      ENDIF
      
      IF ! EMPTY(MEMVAR->EMAIL)
         IF EMAIL_VALIDO(MEMVAR->EMAIL)
            cQuery1 += "CLIENTES_EMAIL = '" + rtrim(LOWER(MEMVAR->EMAIL)) + "', "
         endif
      ENDIF

      IF ! EMPTY(MEMVAR->ENDER)
         cQuery1 += "CLIENTES_ENDER = '" + rtrim(MEMVAR->ENDER) + "', "
      ENDIF
      
      cQuery1 += "CLIENTES_NUMERO = '" + strzero(MEMVAR->NUMERO,9,0) + "', "
      
      IF ! EMPTY(MEMVAR->COMPLEM)
         cQuery1 += "CLIENTES_COMPLEM = '" + rtrim(MEMVAR->COMPLEM) + "', "
      ENDIF
      
      IF ! EMPTY(MEMVAR->BAIR)
         cQuery1 += "CLIENTES_BAIR = '" + rtrim(MEMVAR->BAIR) + "', "
      ENDIF   

      cQuery1 += "CLIENTES_CEP = '" + MEMVAR->CEP + "', "
       cQuery1 += "CLIENTES_PAIS = '" + aPAIS[nCombo4] + "', "
      
      FOR EACH oPAIS IN SEFAZ_CIDADE
         IF oPAIS[3] == aPAIS[nCombo4]
            cQuery1 += "CLIENTES_CODPAIS = '" + SUBSTR(oPAIS[2],3,4) + "', "
         ENDIF
      NEXT             
            
      cQuery1 += "CLIENTES_UF = '"   + aUF[nCombo2] + "', " 
      
      FOR EACH oCIDADE IN SEFAZ_CIDADE
         IF oCIDADE[1] == aUF[nCombo2] .AND. oCIDADE[3] == aMunicipios[nCombo3]
            cQuery1 += "CLIENTES_CODMUN = '"   + oCIDADE[2] + "', "
         ENDIF
      NEXT   
   
      cQuery1 += "CLIENTES_CIDADE = '" + aMunicipios[nCombo3] + "', "
      cQuery1 += "CLIENTES_FONE = '" +  rtrim(MEMVAR->FONE) + "', "
      
      IF ! EMPTY(MEMVAR->CONTATO)
         cQuery1 += "CLIENTES_CONTATO = '" + rtrim(MEMVAR->CONTATO) + "', "
      endif
      
      cQuery1 += "CLIENTES_LIMCRE = '"   + strzero(MEMVAR->LIMCRE,14,2) + "', "
      cQuery1 += "CLIENTES_TOTCRE = '"   + strzero(MEMVAR->TOTCRE,14,2) + "', "
      cQuery1 += "CLIENTES_VENBLO = '"   + SUBSTR(aVENBLO[nCombo6],1,1) + "', "
      cQuery1 += "CLIENTES_DATCAD = '"   + strzero(year(MEMVAR->DATCAD),4,0) + "-" + strzero(month(MEMVAR->DATCAD),2,0) + "-" + strzero(day(MEMVAR->DATCAD),2,0) + "', "
      cQuery1 += "CLIENTES_DATALT = '"   + strzero(year(MEMVAR->DATALT),4,0) + "-" + strzero(month(MEMVAR->DATALT),2,0) + "-" + strzero(day(MEMVAR->DATALT),2,0) + "', "
      cQuery1 += "CLIENTES_USUALT = '"   + rtrim(MEMVAR->USUALT) + "', "
      cQuery1 += "CLIENTES_TAXCLI = '"   + strzero(MEMVAR->TAXCLI,5,2) + "', "
      cQuery1 += "CLIENTES_NUMPAR = '"   + strzero(MEMVAR->NUMPAR,2,0) + "', "
      cQuery1 += "CLIENTES_PERDES = '"   + strzero(MEMVAR->PERDES,5,2) + "', "
      cQuery1 += "CLIENTES_VALMIN = '"   + strzero(MEMVAR->VALMIN,5,0) + "', "
      cQuery1 += "CLIENTES_QUEM_BLOQ = '" + rtrim(M->OPERADOR)+"/"+rtrim(hwg_GetComputerName()+" ["+dtoc(M->DAT_HOJE)+" "+time()+"]") + "' "
      cQuery1 += "WHERE CLIENTES_Id = '" + cClientes_Id + "'"

      
      oQuery := oServer:Execute(cQuery1)
      
   ENDIF

return NIL

*****************************************
STATIC Function EMAIL_VALIDO(cmail)
*****************************************
Local cRegEx

cRegEx :="^[\w-\.]{1,}\@([\da-zA-Z-_]{1,}\.){1,}[\da-zA-Z-_]{2,3}$"

IF HB_REGEXLIKE( cRegEx, RTrim(cmail) )
      RETURN .T.
ELSE
      RETURN .F.
ENDIF

************************************************************
STATIC FUNCTION RELATORIO_CLIENTES( )
************************************************************
   oPDF := PDFClass()
   IF oPDF == NIL
      hwg_msginfo("Falha da criação do objeto PDF")
      RETURN .F.
   ENDIF
   oPDF:cFileName    := "C:\TEMP\CLIENTES"+strzero(HB_RandomInt(1, 99999999),8,0)+'.PDF'
   IF ! oPDF:PrintOptions(  ); RETURN NIL; ENDIF
   
   DBSELECTAREA("CLIENTES")
   Ordsetfocus(2)
   CLIENTES->( DBGOTOP() )
   
   
   IF  oPDF:nPrinterType ==  PDFCLASS_LANDSCAPE
      
      oPDF:Begin()

      nLinha   := 100
      nPagina := 1
      
      DO WHILE ! EOF()
         IF    nLinha   > 96
            oPDF:AddPage()
            
            nMaxCol := oPDF:MaxCol()
            nMaxRow := oPDF:MaxRow()

            oPDF:DrawBox( 0, 0, 9, 41, Nil, Nil, Nil )                 // box esquerdo
            oPDF:DrawImageSize( 0.5, 0.5, 8, 39, "logotipo.jpg" )             // logotipo

            oPDF:DrawBox( 0, 41, 9, 117, Nil, Nil, Nil )  // box centro
            oPDF:DrawText( 2.0, 42, RTRIM(FLAG->n_xNome), nil, 10, "Helvetica-Bold", Nil, Nil )
            oPDF:DrawText( 3.5, 42, RTRIM(FLAG->n_xLgr) + ', ' + RTRIM(FLAG->n_nro), Nil, 8, "Helvetica", Nil, Nil )
            oPDF:DrawText( 5.0, 42,'BAIRRO - ' + RTRIM(FLAG->n_xBairro), Nil, 8, "Helvetica", Nil, Nil )
            oPDF:DrawText( 6.4, 42, "CEP " +FLAG->n_CEP + ' - ' + RTRIM(FLAG->n_xMun) + ' - ' + FLAG->n_xUF + " - FONE: " +FLAG->n_fone, Nil, 8, "Helvetica", Nil, Nil )
            oPDF:DrawText( 8.0, 42, 'CNPJ-'+RTRIM(FLAG->n_CNPJ) + '   Insc.Est.-' + RTRIM(FLAG->n_IE) , Nil, 8, "Helvetica-Bold", Nil, Nil )

            oPDF:DrawBox( 0, nMaxCol, 9, 41, Nil, Nil, Nil )  // box direito
            oPDF:DrawText( 2, 120, "CAD.CLIENTES      " , Nil, 10, "Helvetica", Nil, Nil )
            oPDF:DrawText( 4, 120, "PAGINA Nr.: " + STRZERO(nPagina,4,0), Nil, 10, "Helvetica", Nil, Nil )
            oPDF:DrawText( 6, 120, "DATA: " + DTOC(DAT_HOJE), Nil, 10, "Helvetica", Nil, Nil )
            oPDF:DrawText( 8, 120, "HORA: " + TIME(), Nil, 10, "Helvetica", Nil, Nil )

            oPDF:DrawBox( 9, 0, 12, nMaxCol, Nil, Nil, Nil ) 

            nLinha := 11
            nPagina += 1
            nHightLin:=3

            nLenItem := 20
            nLenUnit := 22
            nLenVlrUni := 27
            nLenDescri := ( nMaxCol - ( nLenItem + nLenUnit +  nLenVlrUni ) )
            
            oPDF:DrawText( nLinha, 1, "CODIGO", Nil, 10, "Helvetica", Nil, Nil )
            oPDF:DrawText( nLinha, 16, "NOME/RAZAO SOCIAL", Nil, 10, "Helvetica", Nil, Nil )

            nLinha += 3

         ENDIF
         
         
         oPDF:DrawText( nLinha, 1, CLIENTES->UCLIENTE, Nil, 12, "Courier-Bold", Nil, Nil )
         oPDF:DrawText( nLinha, 16, CLIENTES->NRAZ_SOC, Nil, 10, "Helvetica", Nil, Nil )
         nLinha += 2
         DBSKIP()
      ENDDO   
      
      oPDF:DrawLine( nLinha, 0, nLinha, nMaxCol, 1 )
      
      oPDF:End(  )
      
   ELSE 
   
      DBSELECTAREA("CLIENTES")
      Ordsetfocus(2)
      CLIENTES->( DBGOTOP() )
   
      oPDF:nPrinterType :=  WIN_PRINTERGETDEFAULT()
      oPDF:SetType( PDFCLASS_ROLLS )
      oPDF:Begin()
      oPDF:nPageHeight := 841.89
      oPDF:AddPage()
      nMaxCol := oPDF:MaxCol()

      oPDF:DrawImageSize( 0, 0, 4, 19, "logotipo.jpg" )             // logotipo

      oPDF:DrawText( 5, 0, RTRIM(FLAG->n_xNome), nil, 10, "Helvetica-Bold", Nil, Nil )
      oPDF:DrawText( 6, 0, RTRIM(FLAG->n_xLgr) + ', ' + RTRIM(FLAG->n_nro), Nil, 8, "Helvetica", Nil, Nil )
      oPDF:DrawText( 7, 0,'BAIRRO - ' + RTRIM(FLAG->n_xBairro), Nil, 8, "Helvetica", Nil, Nil )
      oPDF:DrawText( 8, 0, "CEP " +FLAG->n_CEP + ' - ' + RTRIM(FLAG->n_xMun) + ' - ' + FLAG->n_xUF + " - FONE: " +FLAG->n_fone, Nil, 8, "Helvetica", Nil, Nil )
      oPDF:DrawText( 9, 0, 'CNPJ-'+RTRIM(FLAG->n_CNPJ) + '   Insc.Est.-' + RTRIM(FLAG->n_IE) , Nil, 8, "Helvetica-Bold", Nil, Nil )
      oPDF:DrawLine( 9.5, 0, 9.5, nMaxCol, 1 )
      oPDF:DrawText( 10.5, 0, "CADASTRO DE CLIENTES", Nil, 10, "Helvetica-Bold", Nil, Nil )   
      oPDF:DrawText( 11.5, 0, "CODIGO  NOME/RAZAO SOCIAL", Nil, 8, "Helvetica", Nil, Nil )   
      oPDF:DrawLine( 12, 0, 12, nMaxCol, 1 )
      
      
      nLinha     := 13
      nLenItem := 20
      nLenUnit := 7
      nLenVlrUni := 19
      nLenDescri := ( nMaxCol - ( nLenItem + nLenUnit +  nLenVlrUni ) )
         
      DO WHILE ! EOF()   
      
         IF    nLinha   > 70
            oPDF:AddPage()
            nLinha   := 0
         ENDIF
         
         oPDF:DrawText( nLinha, 0, CLIENTES->UCLIENTE, Nil, 08, "Helvetica", Nil, Nil )
         oPDF:DrawText( nLinha++, 7, CLIENTES->NRAZ_SOC, Nil, 08, "Helvetica", Nil, Nil )
         CLIENTES->(DBSKIP())
   
      ENDDO   

      oPDF:End(  )   

   ENDIF
   
   
   oPDF:PrintPreview(  )

RETURN NIL   



tela.jpg


tela.jpg

Browse com ADO

MensagemEnviado: 07 Abr 2020 14:39
por gilbertosilverio
Ola Amigos,

Baseado neste exemplo do Fernando, consegui entender e fazer alguns testes com SQL.

Depois de tentar por um bom tempo, vi que meu erro estava na conexão com o banco de dados, por mais que fizesse não conseguia conectar.

O meu maior erro, um erro de principiante e estar compilando com 32bits e estar tentando conectar com 64... kkkk

Mais agora estou com uma duvida:

Instalei em minha maquina o MariaDb e o driver mariaodbc 3.1, conforme o exemplo do Fernando, só que no meu servidor existem outros drivers ODBC, e e ai te enrosquei de novo.

Qual driver usar e onde consigo as configurações para a minha comunicação com o banco de dados funcionar.

No meu servidor um W2008 estão instalados estes drivers, qual devo usar ou posso simplesmente instalar o Mariaodbc 3.1, sendo que no server tem o SQL e o MYSQL, que são usados por outros aplicativos.

Vou precisar conectar com outro server linux usando ubuntu, onde esta instalado o MYSQL, da minha maquina consigo conectar com o OBDC do mariadb, posso instalar este drive la no meu w2008 e não vou derrubar os outros sistemas.

Encontrei aqui no forum diversas configurações, mais fiquei em duvida qual usar.

Ja pesquisei muito, encontrei muita coisa, e nada me ajudou a entender.

Agradeço a ajuda.

Browse com ADO

MensagemEnviado: 07 Abr 2020 17:43
por JoséQuintas
O interessante do driver do MariaDB 3.1, é que ele conecta com todos.

Quem precisa do ODBC é o aplicativo, não o servidor.
Só vai instalar no servidor se rodar o aplicativo nele.

ODBC 32 bits pra aplicativo 32 bits - APLICATIVO 32 BITS (não tem a ver com sistema operacional aqui).

Cada um é independente. Pode instalar todos esses, e ir removendo o que está fora de uso.
NÃO atrapalha ter vários, mas vai indicar no aplicativo qual está usando, e esse sim precisa estar instalado.
É PELO NOME, NÃO TEM substituição automática, vai ser usado exatamente o nome que colocar no aplicativo.

Browse com ADO

MensagemEnviado: 07 Abr 2020 19:12
por gilbertosilverio
Quintas,

Muito obrigado.

Instalei no w2008 o Odbc do Mariadb e funcionou perfeitamente, consegui me conectar com o outro servidor linux onde estão as bases de dados que necessito.

Browse com ADO

MensagemEnviado: 11 Abr 2020 15:19
por Itamar M. Lins Jr.
Ola!
90% dos meus browses não são editáveis.
Funciona dessa forma conforme exemplo do Fernando.
Acredito que usando SQLMIX, não vamos precisar de alguns códigos. Vamos diminuir consideravelmente. Eu quero usar acesso nativo com SQLMIX, mas está dando erro na hora de criar a lib no HB_3.4.

Saudações,
Itamar M. Lins Jr.

Browse com ADO

MensagemEnviado: 11 Abr 2020 15:26
por Itamar M. Lins Jr.
Ola!
Tem que criar o browse da mesma forma que fazemos com HTML.
Temos que usar a "flag" LIMITE no código SQL e no browse guardar a posição. Chamar 50 de cada vez, senão fica horrível, nem funciona, precisamos PAGINAR, as consultas SQL com mais de 10 mil registros por exemplo, não podemos chamar tudo de vez.
Esse são os detalhes, o pulo do gato que ainda não vi, e as consultas PAI->FILHO de milhares de NFe por exemplo.

Saudações,
Itamar M. Lins Jr.

Browse com ADO

MensagemEnviado: 11 Abr 2020 22:14
por Fernando queiroz
Itamar M. Lins Jr. escreveu:Ola!
Tem que criar o browse da mesma forma que fazemos com HTML.
Temos que usar a "flag" LIMITE no código SQL e no browse guardar a posição. Chamar 50 de cada vez, senão fica horrível, nem funciona, precisamos PAGINAR, as consultas SQL com mais de 10 mil registros por exemplo, não podemos chamar tudo de vez.
Esse são os detalhes, o pulo do gato que ainda não vi, e as consultas PAI->FILHO de milhares de NFe por exemplo.

Saudações,
Itamar M. Lins Jr.


Itamar tenho carregado no máximo 500 registro, deixando a consulta trazer os específicos, fiz teste de carga via internet e ficou com um tempo admissível , se a conexão estiver muito ruim podemos ate baixar a quantidade para 100 registros, no geral o cliente faz um filtro nas telas de consulta.

no caso de relatórios ou processos com todos os registro ainda nao testei

Browse com ADO

MensagemEnviado: 12 Abr 2020 11:41
por JoséQuintas
Itamar M. Lins Jr. escreveu:Tem que criar o browse da mesma forma que fazemos com HTML.
Temos que usar a "flag" LIMITE no código SQL e no browse guardar a posição.
Chamar 50 de cada vez, senão fica horrível, nem funciona, precisamos PAGINAR, as consultas SQL com mais de 10 mil registros por exemplo, não podemos chamar tudo de vez.Esse são os detalhes, o pulo do gato que ainda não vi, e as consultas PAI->FILHO de milhares de NFe por exemplo.


50 de cada vez? acho que tá brincando
Tenho limitado a 2.000, mas por causa de relacionamento entre campos numéricos/não numéricos.
pai e filho? do tipo pedido e produtos? só fazer o comando SQL.

No caso do ADO, o pulo do gato é fazer tudo com ADO, SEM CONVERSÃO.

Browse com ADO

MensagemEnviado: 12 Abr 2020 14:10
por Itamar M. Lins Jr.
Ola!
50 de cada vez? acho que tá brincando

Isso vai depender da quantidade de fields(campos) que tem nesses 50 registros. Mas mesmo assim, não quis dizer exatamente 50, pode ser mais...
Meu cadastro de clientes é enorme, tem fields para dar e vender...
do tipo pedido e produtos? só fazer o comando SQL.

É isso, mas tem gente que edita no browse. Ai depois que edita, tem que salvar. Com DBF não tem botão salvar, entendeu ?

Saudações,
Itamar M. Lins Jr.

Browse com ADO

MensagemEnviado: 13 Abr 2020 09:21
por JoséQuintas
Itamar M. Lins Jr. escreveu:Meu cadastro de clientes é enorme, tem fields para dar e vender...


Mas aí que está o ponto.
Porque o browse de todos os campos?
Porque essa mania antiga de editar limitado no próprio browse?
Normalmente browse é pra pesquisa, e não pra ficar alterando, salvo exceções.
O ganho de velocidade é justamente em trazer somente o que precisa, e nada mais, e é justamente aí que o DBF perde, porque trás sempre TUDO.

Browse com ADO

MensagemEnviado: 13 Abr 2020 09:44
por asimoes
Nas minhas Grids eu coloco os campos chaves da consulta e os demais eu coloco em uma janela dialog, fica ruim a visualização de muitas colunas na grid.

Exemplo: CPF, NOME, TELEFONE se o usuário der um duplo click abre uma janela modal com o restante do cadastro, aproveitando o mesmo resultset

Se precisar editar, a própria janela modal está habilitada para isso, nada de edição na grid

A grid que eu uso é com vetor, não uso BROWSE DBF

Browse com ADO

MensagemEnviado: 13 Abr 2020 10:26
por Itamar M. Lins Jr.
Ola!
, e é justamente aí que o DBF perde, porque trás sempre TUDO.

Não, no browse só traz o que cabe nas linhas do browse. Usando LetoDbf é assim.
Isso é um problema da rede mapeada, usando servidores de DBF, NetIO, LetoDbf, ADS, isso não "ecziste"
Como eu disse, normalmente eu não edito no browse. Mas existe essa possibilidade.

Saudações,
Itamar M. Lins Jr.

Browse com ADO

MensagemEnviado: 13 Abr 2020 21:04
por JoséQuintas
Uma coisa importante que esqueci na conexão do exemplo do browse, no início do post:

conexão.cursorlocation = 3 // adUseClient

Sem isso, não há navegação no resultado e dá erro no browse.
Se puder, vou editar, porque isso é de extrema importância.

Estava quebrando a cabeça pra ajudar um usuário fazer funcionar no XHarbour, e no final o problema era esse.

Browse com ADO

MensagemEnviado: 13 Abr 2020 21:21
por JoséQuintas
Itamar M. Lins Jr. escreveu:Isso é um problema da rede mapeada, usando servidores de DBF, NetIO, LetoDbf, ADS, isso não "ecziste"
Como eu disse, normalmente eu não edito no browse. Mas existe essa possibilidade.


Faz um teste, só de curiosidade usando o SQLMIX + ODBC.
Fica quase igual ADO direto, mas acho que a diferença é aceitável.
Acho que você é o que mais usa opções diferentes, então tem condições de avaliar.

A vantagem?
Por ODBC basta o que vém no Harbour.
Pelo menos quem está começando já vai direto, sem se perder com necessidades extras do Harbour.
Depois que "brincar" e gostar do troço, aí cada um decide se continua, ou se usa as opções extras.

Aqui achei ruim sobre a memória utilizada pelo Harbour no SQLMIX+ODBC.
Mas no ADO nem dá pra saber, porque fica fora do programa, fica por conta do Windows mesmo.

Browse com ADO

MensagemEnviado: 13 Abr 2020 21:48
por Fernando queiroz
tela.jpg


Antes de usar o SQL eu usava o BROWSE DATABASE e editava diretamente no BROWSE agora com array a coisa ficou meio estranha, ai fique pensando porque não colocar os dados na mesma tela em um campo editável e quando quiser modificar dar um clique na linha do browse e passar a editar no campo abaixo.
sei la sao ideias , o que voces acham????

Browse com ADO

MensagemEnviado: 13 Abr 2020 22:03
por JoséQuintas
Num ambiente de janelas... porque não abrir uma janela?

Vai apresentar tudo com muito mais detalhes.

Browse com ADO

MensagemEnviado: 13 Abr 2020 22:30
por Itamar M. Lins Jr.
Ola!
Quintas, o browse é fundamental para PDV, ponto de venda, O vendedor digita o código apenas e ou passa o leitor de códigos de barras. Nisso ele apenas muda a quantidade se for o caso, e pula para a próxima linha de baixo. Essa é um exemplo que até com SQL tem que jogar em ARRAY para depois salvar, no DBF já fica pronto.
Neste caso ninguém faz JANELA ou DIALOG, é sempre uma linha debaixo da outra, dbedit/browse editáveis.

Saudações,
Itamar M. Lins Jr.

Browse com ADO

MensagemEnviado: 11 Jul 2020 22:37
por cjp
Gostaria de saber se existe alguma forma de filtrar um campo no Tbrowse com ADO.

Com o dbedit eu fazia:

set filter to cPrd$produto


Mas no Tbrowse com ADO isso não funciona.

Poderiam me ajudar, por favor?

Browse com ADO

MensagemEnviado: 12 Jul 2020 02:31
por JoséQuintas
cjp escreveu:Gostaria de saber se existe alguma forma de filtrar um campo no Tbrowse com ADO.


oRs:Filter = "expressão SQL"

https://www.w3schools.com/asp/prop_rs_filter.asp

Browse com ADO

MensagemEnviado: 12 Jul 2020 18:17
por cjp
Eu tentei desta forma:

            prd=space(15)
            @ maxrow()-1,1 say "Produto:"get prd pict "@!"
          read
          oRs:Filter="upper(produto) like '%"+alltrim(prd)+"%'"


Mas não deu certo. Está dando o erro WINOLE/1006 Os argumentos sÒo incorretos, estÒo fora do intervalo aceitßvel ou estÒo em conflito. (0x800A0BB9): ADODB.Recordset.

Tem algo errado?

Browse com ADO

MensagemEnviado: 12 Jul 2020 19:55
por JoséQuintas
cjp escreveu:Tem algo errado?


A expressão tem que ser no formato ADO/SQL.
E Upper() não faz parte disso.

oRs:Filter = "produto like '%" + alltrim( prd ) + "%'"

Browse com ADO

MensagemEnviado: 12 Jul 2020 22:35
por cjp
Coloquei upper para pegar texto com maiúsculas ou minúsculas. Vi neste link: https://www.w3schools.com/sql/func_mysql_upper.asp.

De qualquer forma, testei agora sem o upper, e funcionou tanto com maiúsculas e minúsculas.

Muito obrigado.

Só mais uma dúvida, por favor: precisaria dar um "refresh" no tbrowse, ou algo que atualizasse a lista depois do filter, porque ele está filtrando, mas só está aparecendo os itens filtrados um a um, à medida que teclo as setas. Não tem como aparecer todos os itens filtrados?

Minha função está assim:


   DO WHILE .T.
      oTBrowse:forceStable()
      oTBrowse:refreshCurrent()
      nKey := Inkey(0)
    
     if upper(chr(nkey)) =="P" .and. procname(1)="BROWSECOMPRAS"
            prd=space(15)
            @ maxrow()-1,1 say "Produto:"get prd pict "@!"
          read
          oRs:Filter="produto like '%"+alltrim(prd)+"%'"
    
     elseif nkey == 27
        cSair="S"
       exit
     endif
      IF oTBrowse:applyKey( nKey ) == TBR_EXIT
        cSair="S"
         EXIT
      ENDIF
   ENDDO


Browse com ADO

MensagemEnviado: 03 Set 2020 11:04
por dbsh
SQL use
UpperCase(campo)

Browse com ADO

MensagemEnviado: 04 Set 2020 01:06
por cjp
Desculpe, mas não te entendi.

Browse com ADO

MensagemEnviado: 04 Set 2020 02:19
por Vlademiro
Substitua oTBrowse:refreshCurrent() por oTbrowse:refreshall()

Browse com ADO

MensagemEnviado: 04 Set 2020 10:45
por cjp
Deu certo. Muito obrigado.

Aproveitando, se puder me ajudar com mais uma questão: nesse browse, antes, aparecia o cursor normalmente. Em determinado momento, parou de aparecer o cursor. Não sei o que eu possa ter feito de errado pra isso acontecer. Já coloque set cursor on, mas não resolveu.

Saberia me dizer o que pode estar causando o sumiço do cursor neste caso?

Browse com ADO

MensagemEnviado: 04 Set 2020 10:59
por Vlademiro
Você precisa identificar que "determinado momento" é esse. E fazer a restauração do cursor quando esse momento terminar.

Um caso corriqueiro ocorre assim :


@ x,y SAY "tITULO" GET cVariavel
@ x+1,y SAY "TITULO 2" GET cVariavel2 VALID FUNCAODEPESQUISA()
SET CURSOR ON
READ
SET CURSOR OFF


Se dentro da FUNCAOPESQUISA você usar SET CURSOR OFF e não restaurar o cursor ao voltar, então ele vai sumir quando sair dela.

Outra coisa importante, é mais um conselho :
Evite SET CURSOR ON e SET CURSOR OFF
Prefira a função SetCursor() porque ela sempre retorna o estado anterior do cursor.

Por exemplo :
inicio da função de pesquisa
LOCAL nCursor := SetCursor(0) // Desativa o cursor e envia o estado anterior para nCursor

aqui suas rotinas

antes de retornar faça :
SetCursor( nCursor ) // Isso garante a volta ao estado anterior
RETURN

Browse com ADO

MensagemEnviado: 04 Set 2020 23:41
por cjp
O problema é que eu não uso set cursor off em nenhum momento. Então, não faço ideia do que possa estar causando o sumiço do cursor.

Testei com setcursor(nCursor), também não resolveu.

Browse com ADO

MensagemEnviado: 05 Set 2020 13:00
por Vlademiro
Nesse caso, a única coisa que me ocorreu é vc estar usando várias libs, tipo hmg, gtwvt, gtwvw, etc. Eu não conheço essas libs , só a hmg mas nunca misturei.

Eu acho que é isso, mas não tenho experiência, é só achismo mesmo.

Browse com ADO

MensagemEnviado: 05 Set 2020 22:26
por cjp
De fato uso várias libs:

-lxhb
-lhbwin
-lhbtip
-lhbct
-lhbHPdf
-lhbZebra
-lhbmisc
-llibmysql
rddsql.hbc
sddodbc.hbc
hbssl.hbc
hbtip.hbc


Nem sei se preciso de todas elas, vou acrescendo à medida que surge uma nova função que preciso, quase sempre por recomendação de alguém aqui do fórum.

Será que o problema poderia estar sendo causado por alguma dessas?

Browse com ADO

MensagemEnviado: 06 Set 2020 00:07
por Vlademiro
Eu me referi a libs gráficas, mas pelo visto vc não está usando...

Browse com ADO

MensagemEnviado: 06 Set 2020 09:24
por Vlademiro
Realizei um pequeno teste mas vi que o mesmo programa se comporta diferente no Clipper 5.2e e no Harbour 3.2

O teste :

Um programa simples que irá desativar o cursor de dentro do READ (dentro de uma função valid)

Eis o programa :


PROCEDURE MAIN

    LOCAL GetList := {}
    LOCAL cNome := SPACE(40)
    LOCAL cPessoa := SPACE(1)
    LOCAL cObs := cObs2 := SPACE(40)
   
   
    SET( _SET_CURSOR , 0 )
       
    #ifdef __PLATFORM__WINDOWS
        ? "Setmode : " , SetMode(50,150)
    #endif
    CLS
   
    @ 05,03 SAY "Nome       : " GET cNome VALID ( ALERT( "O CURSOR E " + str(SET( _SET_CURSOR) ) ) , .T. )
    @ 07,03 SAY "Pessoa     : " GET cPessoa VALID ( ALERT( "O CURSOR E " + str(SET( _SET_CURSOR) ) ) , .T. )
    @ 09,03 SAY "Observacao : " GET cObs VALID TESTCURSOR()
    @ 11,03 say "Outra obs  : " GET cObs2 VALID ( ALERT( "O CURSOR E " + str(SET( _SET_CURSOR) ) ) , .T. )
    SET( _SET_CURSOR , 1 )
    ALTD()   
    READ
    SET( _SET_CURSOR , 0 )

RETURN

FUNCTION TESTCURSOR

    ALERT("VOU APAGAR  CURSOR")
    SET( _SET_CURSOR , 0 )

    RETURN .T.


1. No Harbour ele não desativa o Cursor (harbour 3.2 32bits compilado com gcc 5.3)

001.png


2. No Clipper 5.2e ele desativa o cursor de dentro do Valid conforme o esperado.

Nota: eu compilei com o MS-DOS não virtualizado, dei o boot por um pendrive.
003.jpg


Conclusão: o comportamento de um cursor de dentro de um get funciona diferente no harbour. Será que é a versão do Harbour que eu compilei aqui ? Alguém poderia testar esse exemplo que eu coloquei só para confirmar ?

Browse com ADO

MensagemEnviado: 06 Set 2020 21:19
por cjp
Eu testei aqui, compilando com o Harbour. No próprio programa-teste não tirou o cursor, mas tirou o cursor do DOS depois de fechado. Era isso?

Browse com ADO

MensagemEnviado: 06 Set 2020 21:48
por Vlademiro
Não. No clipper ele tira o cursor dentro da própria aplicação. No Harbour ele não consegue tirar o cursor dentro da aplicação.

Browse com ADO

MensagemEnviado: 06 Set 2020 22:40
por JoséQuintas
Esqueça o SET CURSOR OFF
Talvez na função de usuário do tbrowse colocar SET CURSOR ON, apesar que procurei nos fontes do tbrowse e não achei nada sobre cursor.
Lembro que no Clipper o cursor era desligado no tbrowse, é possível que o Harbour faça igual.

Ou mais ainda:
O que fez de diferente nesse tbrowse? provavelmente tem a ver.
Se foi função de usuário.... é colocar o SET CURSOR ON lá.

Browse com ADO

MensagemEnviado: 06 Set 2020 23:02
por cjp
Não tenho função de usuário nesse tbrowse.
Mas tenho sim várias funções chamadas nele, usando if nkey==.
Mas em nenhuma delas eu uso set cursor off. Teria qualquer outra coisa que causaria o sumiço do cursor para eu procurar?

Browse com ADO

MensagemEnviado: 06 Set 2020 23:25
por Vlademiro
CJP, olha esse vídeo com o programa compilado em clipper 5.2e



Com Harbour não funciona. No Harbour o setcursor não funciona dentro de gets, testei no linux também. Agora quando saimos do programa o cursor do Console do windows "some".

Browse com ADO

MensagemEnviado: 06 Set 2020 23:28
por Vlademiro
cjp escreveu:Não tenho função de usuário nesse tbrowse.
Mas tenho sim várias funções chamadas nele, usando if nkey==.
Mas em nenhuma delas eu uso set cursor off. Teria qualquer outra coisa que causaria o sumiço do cursor para eu procurar?


Não conheço outra forma. Muito esquisito isso...

Browse com ADO

MensagemEnviado: 07 Set 2020 01:23
por cjp
Pois é, não sei o que fazer.

Browse com ADO

MensagemEnviado: 07 Set 2020 09:51
por JoséQuintas
cjp escreveu:Mas em nenhuma delas eu uso set cursor off. Teria qualquer outra coisa que causaria o sumiço do cursor para eu procurar?


Pense ao contrário: o tbrowse retira o cursor
Você É OBRIGADO a colocar SET CURSOR ON

Browse com ADO

MensagemEnviado: 07 Set 2020 11:58
por cjp
Mas veja que estou colocando o set cursor on (ou o setcursor(nCursor)) no início, e mesmo assim o cursor não está aparecendo logo de início, antes mesmo de teclar qualquer tecla no tbrowse (ou seja, antes mesmo de ele executar qualquer função chamada de dentro do tbrowse). Como pode isso?

Browse com ADO

MensagemEnviado: 07 Set 2020 14:38
por JoséQuintas
Aí complicou.
Lembra de alguma alteração recente?
Procure em todos os fontes se colocou pra teste "SET CURSOR"
De repente começou a colocar SET CURSOR ON e SET CURSOR OFF, e acabou deixando em algum lugar.
Ou wvt_SetGui() ou outra coisa.

Nota: pelo editor de textos, geralmente tem a opção de procurar em todos os fontes de uma vez.

Browse com ADO

MensagemEnviado: 07 Set 2020 14:47
por JoséQuintas
E não é que achei SET CURSOR OFF em fontes meus, fontes do Linux, e fontes de terceiros.
Aqui são meus fontes, não tem a ver com o problema do post, apenas mostrando que também tem nos meus fontes.

cursor.png


E no meu aplicativo, \INTEGRA\ onde mais tem é justamente no tbrowse.
Já aproveitei e retirei TODOS os SET CURSOR OFF

Browse com ADO

MensagemEnviado: 07 Set 2020 15:11
por JoséQuintas
No Harbour também, mas é no browse e não no tbrowse.

cursor.png


Só comentário:
O browse em meus fontes, é o mesmo do Harbour, são "originais de fábrica".

No final, o post serviu pra descobrir um fonte que virou lixo no meu aplicativo.
É que deixei de usar DBF, então tanto faz o original ou o alterado pra bloquear registro.

Só vou manter o fonte do tbrowse, porque o meu tem opção a mais, que enviei pro Harbour, e tá lá pendente pra merge há mais de 1 ano.

março/2019

https://github.com/harbour/core/pull/185

Só adicionaram o label de "melhoria", "enhancement", e está esperando o clique de alguém pra confirmar.

Browse com ADO

MensagemEnviado: 07 Set 2020 15:20
por Vlademiro
Existe a possibilidade de ir retirando as rotinas até o cursor aparecer ? Assim pelo menos dá pra saber onde está ocorrendo. Se vc isolar a função que está causando isso já é um bom começo. Depois é descobrir a causa mas em um contexto menor.

Esses erros seguem um padrão. Primeiro tem que descobrir onde ele ocorreu, depois descobrir a causa.

Browse com ADO

MensagemEnviado: 07 Set 2020 17:57
por JoséQuintas
Tem outra coisa que lembrei:
Já usou tbrowse em outros lugares do aplicativo.
Some em outros ou somente nesse?

Browse com ADO

MensagemEnviado: 07 Set 2020 18:09
por cjp
Já procurei em todos os fontes, não tem nenhum SET CURSOR OFF.
Também não uso essa GUI mencionada.
O que mais estranho é que o browse já está iniciando sem o cursor. Então, não deve ser nenhuma função chamada dentro dele.
Eu uso esse mesmo tbrowse para várias funções, e o problema ocorre em todas elas.
Vou tentar fazer um novo tbrowse para uma só função, só com o que precisa essa, vamos ver assim volta a exibir o cursor. Já posto o resultado.

Browse com ADO

MensagemEnviado: 07 Set 2020 18:11
por Vlademiro
Porque vc não vai testando a existência do cursor em vários pontos até ele sumir ?

Browse com ADO

MensagemEnviado: 07 Set 2020 18:39
por cjp
Fiz um novo tbrowse para apenas uma função.
Como esperado, funcionou o cursor.
Então, de fato, deve ter algum problema no meu tbrowse anterior impedindo o cursor. O problema é descobrir onde está o problema.

Browse com ADO

MensagemEnviado: 07 Set 2020 19:12
por cjp
Porque vc não vai testando a existência do cursor em vários pontos até ele sumir ?


Então, o problema é que o tbrowse já aparece sem o cursor. Ou seja, ele some logo no início, na maioria das vezes. Tem situações em que o cursor aparece, mas não tem um padrão, não dá pra saber quando aparece, quando não.

Outra coisa que notei: eventualmente, quando teclo setas pra cima ou pra baixo, o cursor aparece, mas logo some de novo.

Browse com ADO

MensagemEnviado: 07 Set 2020 19:40
por JoséQuintas
cjp escreveu:Então, o problema é que o tbrowse já aparece sem o cursor. Ou seja, ele some logo no início, na maioria das vezes. Tem situações em que o cursor aparece, mas não tem um padrão, não dá pra saber quando aparece, quando não.


Opa.
"ele some logo no início, na maioria das vezes"

Isso pode significar que ele some após determinada ação.

Vamos lá... não altere nada.
Entre no aplicativo e abra o browse, veja se o cursor está lá.
Esse é o primeiro ponto.
Repita até mais de uma vez.
Se ele sempre aparece, então é uma chamada a alguma coisa que faz sumir.

Uma coisa é abrir o browse ANTES do problema, e outra coisa é abrir depois do problema, que já vai estar sem cursor.

Browse com ADO

MensagemEnviado: 07 Set 2020 23:34
por cjp
Não te entendi bem. Como quer que eu abra o browse antes do problema? Eu disse que ele já está abrindo sem o cursor, na maioria das vezes. E eu não sei quando vai abrir com ou sem o cursor.

Browse com ADO

MensagemEnviado: 08 Set 2020 00:24
por JoséQuintas
Entrando no aplicativo do zero, indo até a rotina, aparece cursor ou não?
Ou até isso é só de vez em quando?

Browse com ADO

MensagemEnviado: 08 Set 2020 01:41
por cjp
Ah, sim. No meu aplicativo o cursor está normal. É só no tbrowse que o cursor some.

Browse com ADO

MensagemEnviado: 08 Set 2020 07:51
por JoséQuintas
cjp escreveu:Ah, sim. No meu aplicativo o cursor está normal. É só no tbrowse que o cursor some.


Eu quis dizer o seguinte:

você disse que tem horas que o cursor some do tbrowse
Se você entrar no aplicativo, do zero, e ir até o tbrowse, ao abrir o tbrowse pela primeira vez:

a) cursor sempre aparece
b) cursor sempre some
c) tem hora que sim e hora que não

Esse é o ponto de partida pra procurar problema, como ele aparece inicialmente.
E se antes era igual ou não.

Browse com ADO

MensagemEnviado: 08 Set 2020 09:11
por cjp
Ah, entendi.
Fiz o teste algumas vezes. Em todas, até agora, o cursor não apareceu, já na primeira tentativa. E foi só no tbrowse, pois fora dele o cursor apareceu normalmente.
Uma única exceção: em uma única função que chama o mesmo tbrowse, o cursor quase sempre aparece. Nos testes que fiz agora, ele apareceu sempre, mas somente nessa função.

Browse com ADO

MensagemEnviado: 08 Set 2020 21:46
por JoséQuintas
Pelo menos agora tem uma referência.

Uma chamada que quase sempre funciona, e outra que quase sempre não funciona.
O que elas tem de diferente?
Chamadas por SET KEY, ou num prompt, ou misturadas com tbrowse?

Lembro daquele fonte que precisou ajuda, onde misturava o tbrowse com rotina de menu.

Eu tenho dois tipos de tbrowse, que agora reduzi pra ... sei lá... um e meio...

Um deles é um tbrowse passando coordenadas, que só tem o tbrowse.
Esse é usado, por exemplo, em telas compostas, como em pedidos/produtos de pedido, onde pode sofrer alteração

O outro é pra pesquisas em geral, abre na tela inteira, coloca ícones, etc.
Este cuida apenas da tela, e chama o anterior.

Então, não tem comportamento diferente, é sempre igual.
O normal do tbrowse é passar função de usuário, e essa função de usuário é que desvia pra outras rotinas.
Desta forma o funcionamento fica sempre igual.

Até uma coisa interessante no Harbour é que o tbrowse tem um SetKey(), onde a gente pode programar teclas pra serem acionadas no tbrowse.
A idéia do tbrowse é justamente adicionar opções, sem ter que ficar criando várias e várias rotinas.
E com isso, vai ter o mesmo comportamento no aplicativo inteiro.

Outra coisa boa no Harbour é o tbrowse aceitar codeblock como função de usuário.
Isso permite criar uma função que pode ser STATIC, o que facilita pra não ter que ficar inventando nomes.

Acho que cheguei a criar um "esqueleto" pra isso naquela rotina do post que mencionei.
Algo como MeuBrowse( linha, coluna, linha, coluna, { || FuncaoDeUsuario() } )

Então, de um modo geral é chamar a rotina de tbrowse e passar a função.
Depois, na função, trata o que precisar.

STATIC FUNCTION FuncaoDeUsuario()

IF LastKey() == K_INS
   RotinaInclusao()
ELSEIF LastKey() == K_DEL
   RotinaExclusao()
ELSEIF LastKey() == K_ENTER
   RotinaSelecao()
ENDIF
RETURN NIL


Dessa forma, não precisa ficar mexendo na rotina de tbrowse, basta passar a função de usuário com adicionais.
E o mais importante: o comportamento do tbrowse vai ser sempre o mesmo.

Se começa a fazer rotinas de tbrowse variadas, cada uma com suas exceções/diferenças... com certeza vai acabar com comportamentos diferentes.
Na função de usuário acima, por exemplo, se chega em alguma rotina sem cursor, coloca nessa função de usuário o SET CURSOR ON.
Isso vai fazer com que qualquer rotina chamada tenha cursor.

Agora verifique as suas duas rotinas, e veja se consegue descobrir algum detalhe diferente, alguma mistura de tbrowse com outras coisas.

Browse com ADO

MensagemEnviado: 08 Set 2020 22:48
por cjp
O que elas tem de diferente?


Ao que me parece, nada de especial.

A primeira, que quase sempre funciona, é chamada assim:

consado("SELECT nrtarefa,assunto,prioridade,data,hora,tarefa FROM tarefas WHERE prioridade>0 AND soluc='N' AND (exibe='N' OR exibe='I') AND (now())>=hrexibe AND vinculo<>'MP' AND data>='"+dtsql(dtapart)+"' GROUP BY nrtarefa ORDER BY prioridade DESC,data,nrtarefa")


A segunda, que quase nunca funciona, está sendo chamada assim:

         consado("select * from compras where codprod>0")


Chamadas por SET KEY, ou num prompt, ou misturadas com tbrowse?


Nenhuma delas está sendo chamada por SET KEY, só por prompt.

Lembro daquele fonte que precisou ajuda, onde misturava o tbrowse com rotina de menu.


Não é neste fonte que está dando problema não. É em outro, que eu já tinha feito antes, com base neste post.

Algo como MeuBrowse( linha, coluna, linha, coluna, { || FuncaoDeUsuario() } )


Preciso entender como fazer isso. Estou fazendo uma nova rotina, para não ter mais problema com o cursor, queria fazer já da forma correta.

A nova rotina que fiz está assim:

function ADObrowse(sql)
         #include "tbrowse.ch"
         LOCAL oColumn, I, nLen, oTBrowse, oRs, nFieldLen
       local nKey :=99999   //precisa ser private para o respsql
       private conexao

        @ 22,25 say "Abrindo consulta..."
      
       do while .t.
          if !AdoConecta(nProvAtiv,5)
             ?"Não conseguiu conectar; tente novamente mais tarde"
            inkey(5)
            return .f.
           else
               oRS := Conexao:Execute( sql )
          endif
    
            if oRS:Eof()
              @ 22,25 say "Não há nenhum item   "
             inkey(11)
             inkey(11)
              return .f.
           endif

            cls

            oTBrowse := TBrowseDB():new( 03, 3, MaxRow() - 5, 30 )

            oTBrowse:goTopBlock    := { || oRs:moveFirst() }
            oTBrowse:goBottomBlock := { || oRs:moveLast() }
            oTBrowse:skipBlock     := { | n | ADORecordSetSkipper( oRs, n ) }
            oTBrowse:HeadSep       := Chr(196)
            oTBrowse:ColSep        := Chr(179)
            oTBrowse:FootSep       := ""
    
            nLen := oRs:fields():count() - 1
    
            FOR i := 0 TO nLen
                oColumn       := TBColumnNew( oRs:fields(i):name(), ADORecordSetFieldBlock( oRs, i ) )
      
             nFieldLen := 13
            
                oColumn:Width := Max( nFieldLen, Len( oRs:fields(i):name ) )
      
                oTBrowse:addColumn( oColumn )
      
            NEXT
         
         do while .t.
               oTBrowse:forceStable()
               oTBrowse:refreshCurrent()
    
               nKey := Inkey(0)

              set cursor on
    
              if nkey ==13 .and. procname(2)="CONSATIV" .and. ophrtar=5
                 ac1=oRs:Fields("acao"):Value
                exit
               endif
    
               IF oTBrowse:applyKey( nKey ) == TBR_EXIT
                  EXIT
               ENDIF
         enddo
         
         exit
         
         ENDDO

         oRs:Close()
         Conexao:Close()
return .t.


Por enquanto ela está servindo a apenas uma função, e está exibindo o cursor sem problema.

Vou precisar fazê-la para todas as demais funções. Qual é a melhor forma de fazer isso?

Browse com ADO

MensagemEnviado: 08 Set 2020 23:39
por JoséQuintas
Problemas que vejo:

- Tá correndo o risco de travar é tudo, exagerando em abrir conexão
- Tá esquecendo de fechar o recordset
- Tá com o risco de erros com ADO, genérico demais, sem controle eficiente do ADO
- Tá genérico demais, sem controle eficiente do que faz browse
- Tem uma exceção com variável que pode ou não existir

Vamos por partes

- Fica trocando de servidor dentro do aplicativo toda hora? ou trata-se de testar um servidor de cada vez?
- O comando SQL pode ser alterado? Durante o browse?
- Seria interessante usar uma classe pra tratar erros
- Talvez seja mais interessante deixar o comando SQL fora do tbrowse, junto com uma lista de campos, e só usar desse jeito em testes
- Se possível usar compilação -w3 -es2, "talvez" ela te ajude a organizar melhor o fonte, pra acrescentar opções.
- Nem sempre economizar fonte é melhor, muitas vezes mais fonte pode ajudar, principalmente organizado por "assunto".

E, vamos falar de novo, sobre coisas que já falamos.

Vamos passo a passo, mas primeiro responda as duas primeiras questões, sobre servidor e comando SQL.

Browse com ADO

MensagemEnviado: 08 Set 2020 23:55
por JoséQuintas
Qual a parte realmente genérica nisso tudo? o browse.
A rotina de browse separada do resto

   oTBrowse := TBrowseDB():new( 03, 3, MaxRow() - 5, 30 )
   oTBrowse:goTopBlock    := { || oRs:moveFirst() }
   oTBrowse:goBottomBlock := { || oRs:moveLast() }
   oTBrowse:skipBlock     := { | n | ADORecordSetSkipper( oRs, n ) }
   oTBrowse:HeadSep       := Chr(196)
   oTBrowse:ColSep        := Chr(179)
   oTBrowse:FootSep       := ""
   nFieldCount := oRs:Fields():Count()
   FOR nCont := 0 TO nFieldCount - 1
      oColumn       := TBColumnNew( oRs:Fields( nCont ):name(), ADORecordSetFieldBlock( oRs, nCont ) )
      nFieldLen     := 13
      oColumn:Width := Max( nFieldLen, Len( oRs:Fields( nCont ):name ) )
      oTBrowse:addColumn( oColumn )
   NEXT
   DO WHILE .T.
      oTBrowse:forceStable()
      oTBrowse:refreshCurrent()
      nKey := Inkey(0)
      IF oTBrowse:applyKey( nKey ) == TBR_EXIT
         EXIT
      ENDIF
   ENDDO


O que altera entre um browse e outro?
Posições: encima, embaixo, direita, esquerda
O recordset oRs

Browse com ADO

MensagemEnviado: 08 Set 2020 23:58
por JoséQuintas
Olhe que legal, um browse genérico.

FUNCTION BrowseADO( nTop, nLeft, nBottom, nRight, oRs )
   
   oTBrowse := TBrowseDB():new( nTop, nLeft, nBottom, nRight )
   oTBrowse:goTopBlock    := { || oRs:moveFirst() }
   oTBrowse:goBottomBlock := { || oRs:moveLast() }
   oTBrowse:skipBlock     := { | n | ADORecordSetSkipper( oRs, n ) }
   oTBrowse:HeadSep       := Chr(196)
   oTBrowse:ColSep        := Chr(179)
   oTBrowse:FootSep       := ""
   nFieldCount := oRs:Fields():Count()
   FOR nCont := 0 TO nFieldCount - 1
      oColumn       := TBColumnNew( oRs:Fields( nCont ):name(), ADORecordSetFieldBlock( oRs, nCont ) )
      nFieldLen     := 13
      oColumn:Width := Max( nFieldLen, Len( oRs:Fields( nCont ):name ) )
      oTBrowse:addColumn( oColumn )
   NEXT
   DO WHILE .T.
      oTBrowse:forceStable()
      oTBrowse:refreshCurrent()
      nKey := Inkey(0)
      IF oTBrowse:applyKey( nKey ) == TBR_EXIT
         EXIT
      ENDIF
   ENDDO
   
   RETURN NIL


Mas.... você pode querer opções extras... então... vamos adicionar a função de usuário.

Browse com ADO

MensagemEnviado: 09 Set 2020 00:00
por JoséQuintas
Olhe, agora pode acrescentar uma função pra fazer o que quiser.

FUNCTION BrowseADO( nTop, nLeft, nBottom, nRight, oRs, bFuncao )
   
   oTBrowse := TBrowseDB():new( nTop, nLeft, nBottom, nRight )
   oTBrowse:goTopBlock    := { || oRs:moveFirst() }
   oTBrowse:goBottomBlock := { || oRs:moveLast() }
   oTBrowse:skipBlock     := { | n | ADORecordSetSkipper( oRs, n ) }
   oTBrowse:HeadSep       := Chr(196)
   oTBrowse:ColSep        := Chr(179)
   oTBrowse:FootSep       := ""
   nFieldCount := oRs:Fields():Count()
   FOR nCont := 0 TO nFieldCount - 1
      oColumn       := TBColumnNew( oRs:Fields( nCont ):name(), ADORecordSetFieldBlock( oRs, nCont ) )
      nFieldLen     := 13
      oColumn:Width := Max( nFieldLen, Len( oRs:Fields( nCont ):name ) )
      oTBrowse:addColumn( oColumn )
   NEXT
   DO WHILE .T.
      oTBrowse:forceStable()
      oTBrowse:refreshCurrent()
      nKey := Inkey(0)
      IF bFuncao != NIL
         Eval( bFuncao, oRs, oTBrowse )
      ENDIF
      IF oTBrowse:applyKey( nKey ) == TBR_EXIT
         EXIT
      ENDIF
   ENDDO
   
   RETURN NIL

Browse com ADO

MensagemEnviado: 09 Set 2020 00:03
por JoséQuintas
Se o recordset estiver vazio... vai dar erro... então é interessante testar se existe o que navegar.
Isso interessa ao browse.
Agora com seu IF de teste, mas com o acréscimo de testar se existe algum retorno, não apenas o Eof()

FUNCTION BrowseADO( nTop, nLeft, nBottom, nRight, oRs, bFuncao )
   
   IF oRs == NIL .OR. oRS:Eof()
      @ 22,25 say "Não há nenhum item   "
      Inkey(11)
      RETURN .F.
   ENDIF
   oTBrowse := TBrowseDB():new( nTop, nLeft, nBottom, nRight )
   oTBrowse:goTopBlock    := { || oRs:moveFirst() }
   oTBrowse:goBottomBlock := { || oRs:moveLast() }
   oTBrowse:skipBlock     := { | n | ADORecordSetSkipper( oRs, n ) }
   oTBrowse:HeadSep       := Chr(196)
   oTBrowse:ColSep        := Chr(179)
   oTBrowse:FootSep       := ""
   nFieldCount := oRs:Fields():Count()
   FOR nCont := 0 TO nFieldCount - 1
      oColumn       := TBColumnNew( oRs:Fields( nCont ):name(), ADORecordSetFieldBlock( oRs, nCont ) )
      nFieldLen     := 13
      oColumn:Width := Max( nFieldLen, Len( oRs:Fields( nCont ):name ) )
      oTBrowse:addColumn( oColumn )
   NEXT
   DO WHILE .T.
      oTBrowse:forceStable()
      oTBrowse:refreshCurrent()
      nKey := Inkey(0)
      IF bFuncao != NIL
         Eval( bFuncao, oRs, oTBrowse )
      ENDIF
      IF oTBrowse:applyKey( nKey ) == TBR_EXIT
         EXIT
      ENDIF
   ENDDO
   
   RETURN NIL


encerrado o browse genérico.

Browse com ADO

MensagemEnviado: 09 Set 2020 00:11
por JoséQuintas
Uma última alteração: vamos passar nKey pra função, assim poderemos atribuit K_ESC pra sair.

      IF bFuncao != NIL
         Eval( bFuncao, oRs, oTBrowse, @nkey )
      ENDIF


E.... pra compilar com -w3 -es2, declarar as variáveis que são de uso local.

#include "tbrowse.ch"
#include "inkey.ch"

FUNCTION BrowseADO( nTop, nLeft, nBottom, nRight, oRs, bFuncao )
   
   LOCAL nKey, oTBrowse, nFieldCount, nCont, nFieldLen
   
   IF oRs == NIL .OR. oRS:Eof()
      @ 22,25 say "Não há nenhum item   "
      Inkey(11)
      RETURN .F.
   ENDIF
   oTBrowse := TBrowseDB():new( nTop, nLeft, nBottom, nRight )
   oTBrowse:goTopBlock    := { || oRs:moveFirst() }
   oTBrowse:goBottomBlock := { || oRs:moveLast() }
   oTBrowse:skipBlock     := { | n | ADORecordSetSkipper( oRs, n ) }
   oTBrowse:HeadSep       := Chr(196)
   oTBrowse:ColSep        := Chr(179)
   oTBrowse:FootSep       := ""
   nFieldCount := oRs:Fields():Count()
   FOR nCont := 0 TO nFieldCount - 1
      oColumn       := TBColumnNew( oRs:Fields( nCont ):name(), ADORecordSetFieldBlock( oRs, nCont ) )
      nFieldLen     := 13
      oColumn:Width := Max( nFieldLen, Len( oRs:Fields( nCont ):name ) )
      oTBrowse:addColumn( oColumn )
   NEXT
   DO WHILE .T.
      oTBrowse:forceStable()
      oTBrowse:refreshCurrent()
      nKey := Inkey(0)
      IF bFuncao != NIL
         Eval( bFuncao, oRs, oTBrowse, @nkey )
      ENDIF
      IF oTBrowse:applyKey( nKey ) == TBR_EXIT
         EXIT
      ENDIF
   ENDDO
   
   RETURN NIL


Agora sim, parece que ficou bom.

Browse com ADO

MensagemEnviado: 09 Set 2020 00:18
por JoséQuintas
Agora a rotina geral, mas falta dizer sobre a conexão e sobre o comando SQL.

#include "inkey.ch"

FUNCTION ADObrowse( SQL )

   LOCAL oColumn, I, nLen, oTBrowse, oRs, nFieldLen
   LOCAL nKey := 99999   //precisa ser private para o respsql
   PRIVATE conexao

   @ 22,25 SAY "Abrindo consulta..."

   DO WHILE .T.
      IF ! AdoConecta( nProvAtiv, 5 )
         ?"Não conseguiu conectar; tente novamente mais tarde"
         Inkey(5)
         RETURN .f.
      ELSE
         oRS := Conexao:Execute( sql )
      ENDIF
      CLS
      BrowseADO( 3, 3, MaxRow() - 5, 30, oRs, { || RotinaDaqui() } )
      EXIT

   ENDDO

   oRs:Close()
   Conexao:Close()

   RETURN .t.

STATIC FUNCTION RotinaDaqui( oRs, oTBrowse, nKey )

   IF nkey == K_ENTER .AND. ProcName(2) = "CONSATIV" .AND. ophrtar == 5
      ac1 = oRs:Fields( "acao" ):Value
      nKey := K_ESC
   ENDIF

   RETURN NIL

Browse com ADO

MensagemEnviado: 09 Set 2020 00:28
por JoséQuintas
Supondo que seja sempre a mesma conexão, a rotina principal fica assim:

FUNCTION ADObrowse( SQL )

   LOCAL oColumn, I, nLen, oTBrowse, oRs, nFieldLen
   LOCAL nKey := 99999   //precisa ser private para o respsql
   PRIVATE conexao

   @ 22,25 SAY "Abrindo consulta..."
   IF ! ADOConecta( nProvAtiv, 5 )
      ? "Não conseguiu conectar; tente novamente mais tarde"
      Inkey(5)
      RETURN .f.
   ENDIF   

   DO WHILE .T.
      CLS
      oRS := Conexao:Execute( sql )
      BrowseADO( 3, 3, MaxRow() - 5, 30, oRs, { || RotinaDaqui() } )
      oRs:Close()
      EXIT
   ENDDO

   Conexao:Close()

   RETURN .T.


Não conectou... sai fora, pronto resolvida a questão.

pegou o recordset.... depois que não precisa mais pode fechar, pra jogar fora.

Abrir conexão no início e fechar no final... ainda é muito, mas tudo bem.
Ficar abrindo e fechando no Windows, pode travar placa de rede, internet, etc. , o ideal é reduzir ao máximo o abre/fecha de conexão.
Aqui abro a conexão quando o aplicativo abre, e fecho quando o aplicativo fecha.
Por enquanto não tenho uso via internet... e por enquanto desse jeito resolve.

Resultado:
- um browse genérico
- Uma rotina que executa o comando SQL e chama o browse

Talvez fosse melhor essa rotina receber o codeblock/função de usuário, já que a RotinaDaqui() parece não ter a ver com o restante.
Mas pra isso precisaria do tbrowse também..... aí precisaria de mais ajustes.
Aliás... é sair do browse com ENTER.... era só sair, nem precisava da função de usuário.

Browse com ADO

MensagemEnviado: 09 Set 2020 00:56
por JoséQuintas
Meu browse genérico tem mais opções, mas é bem parecido com esse.
Uma parte dele.

FUNCTION BrowseADORC( nTop, nLeft, nBottom, nRight, cnSQL, oTBrowse, cFilterKey, bKeyboard, bUserFunction, nFixToCol, cAddFilter )

   LOCAL nKey := 0, oBrowse, bAction, nMRow, nMCol, cTimeLimit
   LOCAL cFilter := "", lAddFilter := .F.

   hb_Default( @cAddFilter, "" )
   IF ! Empty( cAddFilter )
      lAddFilter := .T.
      ADOFilter( cnSQL, cFilterkey, cFilter, cAddFilter )
   ENDIF
   oBrowse := TBrowseDb():New( nTop, nLeft, nBottom, nRight )
   oBrowse:HeadSep       := Chr(196)
   oBrowse:ColSep        := Chr(179)
   oBrowse:FootSep       := ""
   oBrowse:FrameColor    := "2/1"
   oBrowse:HeaderColor   := "7/8"
   oBrowse:GoTopBlock    := { || cnSQL:MoveFirst() }
   oBrowse:GoBottomBlock := { || cnSQL:MoveLast() }
   oBrowse:SkipBlock     := { | n | cnSQLBrowseSkipper( cnSQL, n ) }
   IF nFixToCol != NIL
      oBrowse:freeze := nFixToCol
   ENDIF


esse acima é pra casos como este, de pedidos

browse1.png


Já o outro, não tem tbrowse, usa o acima, apenas ele coloca visual e usa a tela completa.

FUNCTION BrowseADO( cnSQL, oTBrowse, cFilterKey, bKeyboard, bUserFunction, nFixToCol, cAddFilter )

   LOCAL nTop := 5, nLeft := 0, nBottom := MaxRow() - 3, nRight := MaxCol(), cColorAnt := SetColor()
   LOCAL oFrm

   hb_Default( @cAddFilter, "" )
   IF cnSQL == NIL
      MsgStop( "Não há informações para serem mostradas" )
      RETURN NIL
   ENDIF
   SetColor( SetColorBox() )
   IF Len( appForms() ) > 0
      Atail( AppForms()):GuiHide()
   ENDIF
   oFrm := frmGuiClass():New()
   oFrm:lNavigate := .F.
   oFrm:cOptions  := "C"
   AAdd( oFrm:acMenuOptions, "<Ctrl-PgUp>Primeiro" )
   AAdd( oFrm:acMenuOptions, "<PgUp>Pág.Ant" )
   Aadd( oFrm:acMenuOptions, "<Up>Sobe" )
   AAdd( oFrm:acMenuOptions, "<Down>Desce" )
   AAdd( oFrm:acMenuOptions, "<PgDn>Pág.Seg" )
   AAdd( oFrm:acMenuOptions, "<Ctrl-PgDn>Último" )


browse2.png


O mesmo tbrowse atende os dois casos.
É o único tbrowse pra ADO do aplicativo inteiro.
Tenho outro, mas é pra DBF, se é que não é o que retirei a imagem acima... é que o resultado é o mesmo.

Browse com ADO

MensagemEnviado: 09 Set 2020 23:07
por cjp
Testei o teu modelo, mas o Enter não funcionou, não sai do browse.

Respondendo às tuas perguntas:

- Fica trocando de servidor dentro do aplicativo toda hora? ou trata-se de testar um servidor de cada vez?


Não é teste. Uso dois servidores ao mesmo tempo. Então, cada função chama um servidor diferente.

- O comando SQL pode ser alterado? Durante o browse?


Durante o browse não. O comando SQL é o mesmo para cada edição do browse. De um browse pra outro, aí sim, o comando SQL muda.

O que altera entre um browse e outro?


Se vc está falando entre uma função e outra que chama o browse, a mudança no browse é nas funções de usuário. Para uma função, a tecla Enter faz uma coisa; para outra, faz outra coisa. Para uma função, uso apenas o Enter e o Esc; para outra, uso várias teclas. E assim por diante.

Browse com ADO

MensagemEnviado: 10 Set 2020 00:35
por JoséQuintas
cjp escreveu:Se vc está falando entre uma função e outra que chama o browse, a mudança no browse é nas funções de usuário. Para uma função, a tecla Enter faz uma coisa; para outra, faz outra coisa. Para uma função, uso apenas o Enter e o Esc; para outra, uso várias teclas. E assim por diante.


Tá, mas.... sempre que aperta a tecla, abandona o browse?
Porque se não for assim, é colocar na função de usuário.
Não precisa sair do browse pra executar outras coisas, a não ser que o browse realmente não interesse mais.

Browse com ADO

MensagemEnviado: 10 Set 2020 01:36
por cjp
No caso desta função que estou testando, o browse não interessa mais. Só quero pegar o valor do campo acao para ac1.
Em outras funções será diferente.

Browse com ADO

MensagemEnviado: 10 Set 2020 21:43
por JoséQuintas
test.prg
(2.98 KiB) Baixado 65 vezes


Salve exatamente como está aí.

Detalhes importantes dos parâmetros:

nTop, nLeft, nBottom, nRight - são as coordenadas linha/coluna
oADO - é o recordset, a consulta
oTBrowse - isso vai ser novidade (pra você), pode achar mais trabalhoso, mas vai facilitar muita coisa
bKeyboard - se quiser que a rotina faça KEYBOARD da chave ao teclar ENTER
bUserFunction - função de usuário pra adicionar recursos

De um modo geral, não é nada diferente do tbrowse normal, apenas fica mais "padrão".
Usando ADO diretamente isso NÃO serve pra consulta vazia.

Exemplo de uso, atenção à ordem, NÃO dá pra criar o tbrowse sem ter o objecto Recordset primeiro

oRs := conexao:Execute( "SELECT * FROM CLIENTES" )
oTbrowse := { ;
   { "CODIGO", { || Str( Rs:Fields( "CODIGO" ):Value, 5 ) } }, ;
   { "NOME",    { || Pad( Rs:Fields( "NOME" ):Value, 30 ) } }, ;
   { "ENDERECO", { || Pad( Rs:Fields( "ENDERECO" ):Value, 30 ) } } }
BrowseADO( 1, 1, 20, 78, oRs, oTBrowse )
oRs:Close()


Dá mais trabalho não ser automático? sim, mas tem controle total sobre as colunas.
Pode buscar mais campos do que mostra na tela, bom pra ter informação sem mostrar para o usuário.
Bom... esse é o primeiro, ESC ou ENTER sai fora.

Quer que o browse digite automaticamente alguma coisa.
Passe pra ele o codeblock que ele vai digitar.

{ || Ltrim( Str( rs:Fields( "CODIGO" ):Value ) ) }

BrowseADO( 1, 1, 20, 78, oRs, oTBrowse, { || Ltrim( Str( rs:Fields( "CODIGO" ):Value ) ) } )


Quer que ele faça outras coisas, não apenas o normal: passe pra ele o codeblock da função

BrowseADO( 1, 1, 20, 78, oRs, oTBrowse, , { || MinhaRotina() } )


A rotina vai receber o recordset, otbrowse e nkey - a tecla

FUNCTION MinhaRotina( oRs, oTBrowse, nKey )


Nessa rotina, coloque o que quiser, vai estar com tudo na mão.

FUNCTION MinhaRotina( oRs, oTBrowse, nKey )

DO CASE
CASE nKey == K_ENTER
   // mostra outra janela
CASE nKey == K_INS
   // inclui
CASE nKey == K_DEL
   IF MsgYesNo( "Quer excluir mesmo?" )
      Excluir( oRs:Fields( "CODIGO" ):Value )
   ENDIF
ENDCASE
RETURN NIL


Com o ADO diretamente vai ficar limitado.

Aqui tenho uma classe que junta tudo: conexao e recordset e até o comando usado pra retornar o recordset.
No caso de exclusão, por exemplo, eu refaço a pesquisa.
E acaba ficando disponível conexão e recordset ao mesmo tempo.
Posso fazer oADO:ExecuteCmd( "DELETE FROM ...." ) ou qualquer outra coisa.

No seu caso, vai ficar sem esse recurso, e só vai ter se sair do browse e reabrir.

Até poderia passar também a conexão por parâmetro, fazer nova consulta, trocar o recordset e invalidar o tbrowse, pra ele se remontar sozinho, também seria uma opção.

Então... basicamente esse é somente pra consulta.

Faltou:
Quer o tbrowse pra pegar um valor?
Mesmo inicial, apenas consulte o resultado, já que o recordset vai estar posicionado aonde teclaram ENTER.

BrowseADO( 1, 1, 20, 78, oRs, oTBrowse )

IF LastKey() == K_ENTER
   nValor := oRs:Fields( "CODIGO" ):Value
ENDIF

Browse com ADO

MensagemEnviado: 10 Set 2020 21:54
por JoséQuintas
O que comentei é colocar algo do tipo:

IF oTBrowse == NIL
   nLen := oRs:fields():count() - 1
   FOR nCont := 0 TO nLen
      oColumn       := TBColumnNew( oRs:fields(i):name(), ADORecordSetFieldBlock( oRs, i ) )
   nFieldLen := 13
   oColumn:Width := Max( nFieldLen, Len( oRs:fields(i):name ) )
   oTBrowse:addColumn( oColumn )   
   NEXT
ELSE
   FOR EACH oElement IN oTBrowse
      oThisColumn := tbColumnNew( oElement[ 1 ], oElement[ 2 ] )
      IF Len( oElement ) > 2
         oThisColumn:ColorBlock := oElement[ 3 ]
      ENDIF
      oBrowse:AddColumn( oThisColumn )
   NEXT
ENDIF


Desse jeito vai poder usar passando ou não aquele array pra tbrowse.
Volta a ter sua opção automática, além da opção "nova".

Browse com ADO

MensagemEnviado: 12 Set 2020 11:48
por JoséQuintas
Só um acréscimo:
A vantagem de usar uma lista, por exemplo:

oTBrowse := { ;
   { "DATA", { || rs:FIelds( "DATA" ):Value } }, ;
   { "DIAS", { || rs:Fields( "DIAS" ):Value } }, ;
   { "NOVA", { || rs:Fields( "DATA" ):Value + Rs:Fields( "DIAS" ):Value } }, ;
   { "OUTRO", { || Rotina3() } } }


Talvez leve um tempo pra acostumar com essa separação.
É um array {}
E dentro outro array { a, b }
primeiro elemento é o título
segundo elemento é um codeblock { || conteudo }
justamente no conteúdo coloca o que quiser, não está preso a existir na consulta.
Então NÃO precisa incluir tudo da consulta, e pode acrescentar mais coisas ainda.

Isso mostra que automático é bom, mas colocar lista é muito melhor.