Criar totalizador numa tela com FWMarkBrowse

Nesse artigo vamos demonstrar em como criar um totalizador conforme os registros são marcados numa tela com MarkBrowse.

 

Recentemente nos perguntaram, como seria possível criar um label, que é atualizado conforme é marcado os registros em um MarkBrowse.

 

Pensando nisso, montamos esse exemplo, onde é exibido informações da SE1 (Títulos a Receber) e ao marcar um registro é atualizado a informação em um TSay no rodapé.

 

A lógica efetuada para isso, foi a seguinte:

  1. O primeiro passo é declarar as variáveis oSayLog e cSayLog como Private
  2. O segundo passo, na criação do FWMarkBrowse, vamos usar o método SetAfterMark acionando uma função para contar os registros (função fAposMarcar)
  3. O terceiro passo, vai ser antes de criar a tela, criar o TSay abaixo do grid
  4. Na função fAposMarcar, vamos percorrer todos os dados da tela, e onde tiver marcado vamos incrementar variáveis (nTotSaldo e nTotMarc)
  5. Por fim, será atualizado a variável cSayLog e dado um refresh no objeto oSayLog

 

Abaixo um gif de como ficou a tela:

Exemplo de Totalizador

Exemplo de Totalizador

 

E abaixo o código fonte desenvolvido:

//Bibliotecas
#Include "Totvs.ch"
#Include "FWMVCDef.ch"

/*/{Protheus.doc} User Function zTstMk
Teste MarkBrowse
@author Atilio
@since 05/02/2025
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/

User Function zTstMk()
	Local aArea := FWGetArea()
	Local aPergs   := {}
	Local dDataDe := FirstDate(Date())
	Local dDataAte := LastDate(dDataDe)
	
	//Adicionando os parametros do ParamBox
	aAdd(aPergs, {1, "Vencimento De", dDataDe,  "", ".T.", "", ".T.", 80,  .T.})
	aAdd(aPergs, {1, "Vencimento Até", dDataAte,  "", ".T.", "", ".T.", 80,  .T.})
	
	//Se a pergunta for confirma, chama a tela
	If ParamBox(aPergs, 'Informe os parâmetros', /*aRet*/, /*bOk*/, /*aButtons*/, /*lCentered*/, /*nPosx*/, /*nPosy*/, /*oDlgWizard*/, /*cLoad*/, .F., .F.)
		fMontaTela()
	EndIf
	
	FWRestArea(aArea)
Return

/*/{Protheus.doc} fMontaTela
Monta a tela com a marcação de dados
@author Atilio
@since 05/02/2025
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/

Static Function fMontaTela()
    Local aArea         := GetArea()
    Local aCampos := {}
    Local aColunas := {}
    Local cFontPad    := 'Tahoma'
    Local oFontGrid   := TFont():New(cFontPad, /*uPar2*/, -14)
    Local oFontLog    := TFont():New(cFontPad, , -14)
    Private oTempTable := Nil
    //Log que vai ter o total
    Private oSayLog
    Private cSayLog := "..."
    //Janela e componentes
    Private oDlgMark
    Private oPanGrid
    Private oMarkBrowse
    Private cAliasTmp := GetNextAlias()
    Private aRotina   := MenuDef()
    //Tamanho da janela
    Private aTamanho := MsAdvSize()
    Private nJanLarg := aTamanho[5]
    Private nJanAltu := aTamanho[6]
     
    //Adiciona as colunas que serão criadas na temporária
    aAdd(aCampos, { 'OK'        , 'C', 2,                       0                      }) //Flag para marcação
    aAdd(aCampos, { 'E1_NUM'    , 'C', TamSX3('E1_NUM'    )[1], 0                      }) //Título
    aAdd(aCampos, { 'E1_PREFIXO', 'C', TamSX3('E1_PREFIXO')[1], 0                      }) //Prefixo
    aAdd(aCampos, { 'E1_PARCELA', 'C', TamSX3('E1_PARCELA')[1], 0                      }) //Parcela
    aAdd(aCampos, { 'E1_EMISSAO', 'D', TamSX3('E1_EMISSAO')[1], 0                      }) //Emissão
    aAdd(aCampos, { 'E1_VENCREA', 'D', TamSX3('E1_VENCREA')[1], 0                      }) //Venc. Real
    aAdd(aCampos, { 'E1_SALDO'  , 'N', TamSX3('E1_SALDO'  )[1], TamSX3('E1_SALDO'  )[2]}) //Saldo
    aAdd(aCampos, { 'E1_CLIENTE', 'C', TamSX3('E1_CLIENTE')[1], 0                      }) //Cliente
    aAdd(aCampos, { 'E1_NOMCLI' , 'C', TamSX3('E1_NOMCLI' )[1], 0                      }) //Nome
    aAdd(aCampos, { 'E1_HIST'   , 'C', TamSX3('E1_HIST'   )[1], 0                      }) //Histórico

    //Cria a tabela temporária
    oTempTable:= FWTemporaryTable():New(cAliasTmp)
    oTempTable:SetFields( aCampos )
    oTempTable:Create()  

    //Popula a tabela temporária
    Processa({|| fPopula()}, 'Processando...')

    //Adiciona as colunas que serão exibidas no FWMarkBrowse
    aColunas := fCriaCols()
     
    //Criando a janela
    DEFINE MSDIALOG oDlgMark TITLE 'Tela para Marcação de dados - Autumn Code Maker' FROM 000, 000  TO nJanAltu, nJanLarg COLORS 0, 16777215 PIXEL
        //Dados
        oPanGrid := tPanel():New(001, 001, '', oDlgMark, /*oFont*/, /*lCentered*/, /*uParam7*/, RGB(000,000,000), RGB(254,254,254), (nJanLarg/2) - 1, (nJanAltu/2) - 20)
        oMarkBrowse := FWMarkBrowse():New()
        oMarkBrowse:SetAlias(cAliasTmp)                
        oMarkBrowse:SetDescription('Teste MarkBrowse')
        oMarkBrowse:DisableFilter()
        oMarkBrowse:DisableConfig()
        oMarkBrowse:DisableSeek()
        oMarkBrowse:DisableSaveConfig()
        oMarkBrowse:SetFontBrowse(oFontGrid)
        oMarkBrowse:SetFieldMark('OK')
        oMarkBrowse:SetTemporary(.T.)
        oMarkBrowse:SetColumns(aColunas)
        //oMarkBrowse:AllMark() 
        oMarkBrowse:SetOwner(oPanGrid)
        oMarkBrowse:SetAfterMark({|| fAposMarcar()})
        oMarkBrowse:Activate()

        //Cria um TSay no fim da tela que conterá o totalizador
        nLinObj := (nJanAltu/2) - 15
        oSayLog := TSay():New(nLinObj, 003, {|| cSayLog}, oDlgMark, "", oFontLog, , , , .T., , , (nJanLarg/2) - 6, 10, , , , , , .F., , )
    ACTIVATE MsDialog oDlgMark CENTERED
    
    //Deleta a temporária e desativa a tela de marcação
    oTempTable:Delete()
    oMarkBrowse:DeActivate()
    
    RestArea(aArea)
Return

/*/{Protheus.doc} MenuDef
Botões usados no Browse
@author Atilio
@since 05/02/2025
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/

Static Function MenuDef()
    Local aRotina := {}
     
    //Criação das opções
    ADD OPTION aRotina TITLE 'Continuar'  ACTION 'u_zTstMkO'     OPERATION 2 ACCESS 0
Return aRotina

/*/{Protheus.doc} fPopula
Executa a query SQL e popula essa informação na tabela temporária usada no browse
@author Atilio
@since 05/02/2025
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/

Static Function fPopula()
    Local cQryDados := ''
    Local nTotal := 0
    Local nAtual := 0

    //Monta a consulta
    cQryDados += "SELECT "		+ CRLF
    cQryDados += " E1_NUM, "		+ CRLF
    cQryDados += " E1_PREFIXO, "		+ CRLF
    cQryDados += " E1_PARCELA, "		+ CRLF
    cQryDados += " E1_EMISSAO, "		+ CRLF
    cQryDados += " E1_VENCREA, "		+ CRLF
    cQryDados += " E1_SALDO, "		+ CRLF
    cQryDados += " E1_CLIENTE, "		+ CRLF
    cQryDados += " E1_NOMCLI, "		+ CRLF
    cQryDados += " E1_HIST "		+ CRLF
    cQryDados += "FROM "		+ CRLF
    cQryDados += " " + RetSQLName("SE1") + " SE1 "		+ CRLF
    cQryDados += "WHERE "		+ CRLF
    cQryDados += " E1_FILIAL = '" + FWxFilial("SE1") + "' "		+ CRLF
    cQryDados += " AND E1_VENCREA >= '" + dToS(MV_PAR01) + "' "		+ CRLF
    cQryDados += " AND E1_VENCREA <= '" + dToS(MV_PAR02) + "' "		+ CRLF
    cQryDados += " AND E1_BAIXA = '' "		+ CRLF
    cQryDados += " AND SE1.D_E_L_E_T_ = ' '"		+ CRLF
	If '--' $ cQryDados .Or. 'WITH' $ Upper(cQryDados) .Or. 'NOLOCK' $ Upper(cQryDados)
		FWAlertInfo('Alguns comandos (como --, WITH e NOLOCK), não são executados pela PLSQuery devido ao ChangeQuery. Tente migrar da PLSQuery para TCQuery.', 'Atenção')
	EndIf 
    PLSQuery(cQryDados, 'QRYDADTMP')

    //Definindo o tamanho da régua
    DbSelectArea('QRYDADTMP')
    Count to nTotal
    ProcRegua(nTotal)
    QRYDADTMP->(DbGoTop())

    //Enquanto houver registros, adiciona na temporária
    While ! QRYDADTMP->(EoF())
        nAtual++
        IncProc('Analisando registro ' + cValToChar(nAtual) + ' de ' + cValToChar(nTotal) + '...')

        RecLock(cAliasTmp, .T.)
            (cAliasTmp)->OK         := Space(2)
            (cAliasTmp)->E1_NUM     := QRYDADTMP->E1_NUM
            (cAliasTmp)->E1_PREFIXO := QRYDADTMP->E1_PREFIXO
            (cAliasTmp)->E1_PARCELA := QRYDADTMP->E1_PARCELA
            (cAliasTmp)->E1_EMISSAO := QRYDADTMP->E1_EMISSAO
            (cAliasTmp)->E1_VENCREA := QRYDADTMP->E1_VENCREA
            (cAliasTmp)->E1_SALDO   := QRYDADTMP->E1_SALDO
            (cAliasTmp)->E1_CLIENTE := QRYDADTMP->E1_CLIENTE
            (cAliasTmp)->E1_NOMCLI  := QRYDADTMP->E1_NOMCLI
            (cAliasTmp)->E1_HIST    := QRYDADTMP->E1_HIST
        (cAliasTmp)->(MsUnlock())

        QRYDADTMP->(DbSkip())
    EndDo
    QRYDADTMP->(DbCloseArea())
    (cAliasTmp)->(DbGoTop())
Return

/*/{Protheus.doc} fCriaCols
Função que gera as colunas usadas no browse (similar ao antigo aHeader)
@author Atilio
@since 05/02/2025
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/

Static Function fCriaCols()
    Local nAtual       := 0 
    Local aColunas := {}
    Local aEstrut  := {}
    Local oColumn
    
    //Adicionando campos que serão mostrados na tela
    //[1] - Campo da Temporaria
    //[2] - Titulo
    //[3] - Tipo
    //[4] - Tamanho
    //[5] - Decimais
    //[6] - Máscara
    aAdd(aEstrut, { 'E1_NUM'    , 'Título'    , 'C', TamSX3('E1_NUM'    )[1], 0,                       ''})
    aAdd(aEstrut, { 'E1_PREFIXO', 'Prefixo'   , 'C', TamSX3('E1_PREFIXO')[1], 0,                       ''})
    aAdd(aEstrut, { 'E1_PARCELA', 'Parcela'   , 'C', TamSX3('E1_PARCELA')[1], 0,                       ''})
    aAdd(aEstrut, { 'E1_EMISSAO', 'Emissão'   , 'D', TamSX3('E1_EMISSAO')[1], 0,                       ''})
    aAdd(aEstrut, { 'E1_VENCREA', 'Venc. Real', 'D', TamSX3('E1_VENCREA')[1], 0,                       ''})
    aAdd(aEstrut, { 'E1_SALDO'  , 'Saldo'     , 'N', TamSX3('E1_SALDO'  )[1], TamSX3('E1_SALDO'  )[2], PesqPict('SE1', 'E1_SALDO')})
    aAdd(aEstrut, { 'E1_CLIENTE', 'Cliente'   , 'C', TamSX3('E1_CLIENTE')[1], 0,                       ''})
    aAdd(aEstrut, { 'E1_NOMCLI' , 'Nome'      , 'C', TamSX3('E1_NOMCLI' )[1], 0,                       ''})
    aAdd(aEstrut, { 'E1_HIST'   , 'Histórico' , 'C', TamSX3('E1_HIST'   )[1], 0,                       ''})

    //Percorrendo todos os campos da estrutura
    For nAtual := 1 To Len(aEstrut)
        //Cria a coluna
        oColumn := FWBrwColumn():New()
        oColumn:SetData(&('{|| ' + cAliasTmp + '->' + aEstrut[nAtual][1] +'}'))
        oColumn:SetTitle(aEstrut[nAtual][2])
        oColumn:SetType(aEstrut[nAtual][3])
        oColumn:SetSize(aEstrut[nAtual][4])
        oColumn:SetDecimal(aEstrut[nAtual][5])
        oColumn:SetPicture(aEstrut[nAtual][6])

        //Muda o alinhamento conforme o tipo, Data será Centralizado
        If aEstrut[nAtual][3] == 'D'
        	oColumn:nAlign := 0
        
        //Numérico, direita
        ElseIf aEstrut[nAtual][3] == 'N'
        	oColumn:nAlign := 2
        
        //Senão, esquerda (caractere)
        Else
        	oColumn:nAlign := 1
        EndIf

        //Adiciona a coluna
        aAdd(aColunas, oColumn)
    Next
Return aColunas

/*/{Protheus.doc} User Function zTstMkO
Função acionada pelo botão continuar da rotina
@author Atilio
@since 05/02/2025
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/

User Function zTstMkO()
    Processa({|| fProcessa()}, 'Processando...')
Return

/*/{Protheus.doc} fProcessa
Função que percorre os registros da tela
@author Atilio
@since 05/02/2025
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/

Static Function fProcessa()
    Local aArea     := FWGetArea()
    Local cMarca    := oMarkBrowse:Mark()
    Local nAtual    := 0
    Local nTotal    := 0
    Local nTotMarc := 0
    
    //Define o tamanho da régua
    DbSelectArea(cAliasTmp)
    (cAliasTmp)->(DbGoTop())
    Count To nTotal
    ProcRegua(nTotal)
    
    //Percorrendo os registros
    (cAliasTmp)->(DbGoTop())
    While ! (cAliasTmp)->(EoF())
        nAtual++
        IncProc('Analisando registro ' + cValToChar(nAtual) + ' de ' + cValToChar(nTotal) + '...')
    
        //Caso esteja marcado
        If oMarkBrowse:IsMark(cMarca)
            nTotMarc++
            
            /*
            //Aqui dentro você pode fazer o seu processamento
            FWAlertInfo((cAliasTmp)->E1_NUM, "Mensagem de teste")
            */
        EndIf
         
        (cAliasTmp)->(DbSkip())
    EndDo
    
    //Mostra a mensagem de término e caso queria fechar a dialog, basta usar o método End()
    FWAlertInfo('Dos [' + cValToChar(nTotal) + '] registros, foram processados [' + cValToChar(nTotMarc) + '] registros', 'Atenção')
    //oDlgMark:End()

    FWRestArea(aArea)
Return

Static Function fAposMarcar()
    Local aArea     := FWGetArea()
    Local cMarca    := oMarkBrowse:Mark()
    Local nTotal    := 0
    Local nTotMarc  := 0
    Local nTotSaldo := 0
    
    //Define o tamanho da régua
    DbSelectArea(cAliasTmp)
    (cAliasTmp)->(DbGoTop())
    Count To nTotal
    
    //Percorrendo os registros
    (cAliasTmp)->(DbGoTop())
    While ! (cAliasTmp)->(EoF())
    
        //Caso esteja marcado
        If oMarkBrowse:IsMark(cMarca)
            nTotMarc++
            nTotSaldo += (cAliasTmp)->E1_SALDO
        EndIf
         
        (cAliasTmp)->(DbSkip())
    EndDo

    //Atualiza o log em baixo do browse
    cSayLog := ""
    cSayLog += "Dos [" + cValToChar(nTotal) + "] registros, "
    cSayLog += "foram marcados [" + cValToChar(nTotMarc) + "] registros, "
    cSayLog += "totalizando o valor [" + cValToChar(nTotSaldo) + "] de saldo dos títulos a receber."
    oSayLog:Refresh()

    FWRestArea(aArea)
Return

Bom pessoal, por hoje é só.

Abraços e até a próxima.

Dan (Daniel Atilio)
Cristão de ramificação protestante. Especialista em Engenharia de Software pela FIB, graduado em Banco de Dados pela FATEC Bauru e técnico em informática pelo CTI da Unesp. Entusiasta de soluções Open Source e blogueiro nas horas vagas. Autor e mantenedor do portal Terminal de Informação.

Deixe uma resposta

Terminal de Informação