Montando lógica para página de e até via código fonte | Ti Responde 0235

No vídeo de hoje, vamos demonstrar em como montar a lógica para fazer o “página x de y” em um FWMSPrinter.

A dúvida de hoje, nos perguntaram, como poderíamos imprimir no rodapé de um relatório em FWMSPrinter, o número da página atual e o total de páginas.

 

Pensando nisso, montamos um exemplo, onde vai ser demonstrado a contagem dos registros, e fazendo a conta utilizando Ceiling para forçar o arredondamento.

 

Segue abaixo o vídeo exemplificando:

E abaixo o fonte desenvolvido:

//Bibliotecas
#Include "tlpp-core.th"
#Include "TOTVS.ch" //por causa da RGB()
#Include "TopConn.ch"
#Include "RPTDef.ch"
#Include "FWPrintSetup.ch"

//Declaração da namespace
Namespace custom.terminal.youtube

//Constantes
#Define CRLF Chr(13) + Chr(10) //Carriage Return Line Feed

//Alinhamentos
#Define PAD_LEFT    0
#Define PAD_RIGHT   1
#Define PAD_CENTER  2
#Define PAD_JUSTIFY 3 //Opção disponível somente a partir da versão 1.6.2 da TOTVS Printer

//Cor(es)
Static nColorGray := RGB(110, 110, 110) As Numeric
Static nBackgroundColor := RGB(213, 255, 208) As Numeric

/*/{Protheus.doc} video0235
Listagem de Cidades
@author Atilio
@since 14/02/2026
@version 1.0
@type User Function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
@example custom.terminal.youtube.u_video0235()
/*/

User Function video0235()
	Local aArea := FWGetArea() As Array
	Local aParameters   := {} As Array
	Local cInitState := Space(2) As Character
	Local cLastState := StrTran(cInitState, " ", "Z") As Character
	
	//Adicionando os parametros do ParamBox
	aAdd(aParameters, {1, "Estado De", cInitState,  "", ".T.", "12", ".T.", 80,  .F.})
	aAdd(aParameters, {1, "Estado Até", cLastState,  "", ".T.", "12", ".T.", 80,  .T.})
	
	//Se a pergunta for confirma, cria o relatorio
	If ParamBox(aParameters, 'Informe os parâmetros', /*aRet*/, /*bOk*/, /*aButtons*/, /*lCentered*/, /*nPosx*/, /*nPosy*/, /*oDlgWizard*/, /*cLoad*/, .F., .F.)
		Processa({|| createReport()})
	EndIf
	
	FWRestArea(aArea)
Return

/*/{Protheus.doc} createReport
Faz a impressão do relatório video0235
@author Atilio
@since 14/02/2026
@version 1.0
@type Static Function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/

Static Function createReport()
    Local aArea          := FWGetArea() As Array
    Local nTotal         := 0 As Numeric
    Local nCurrent       := 0 As Numeric
    Local cQuery         := '' As Character
    Local cFileName      := 'video0235'+RetCodUsr()+'_' + dToS(Date()) + '_' + StrTran(Time(), ':', '-') + '.pdf' As Character
    Private oPrintReport As Object
    Private oBrushLin  := TBrush():New(/*uParam1*/, nBackgroundColor) As Object
    Private cTimeReport    := Time() As Character
    Private nPageCurrent   := 1 As Numeric
    Private cCompanyLogo   := searchLogo() As Character
    //Linhas e colunas
    Private nReportLine    := 0 As Numeric
    Private nFooterLimit   := 800 As Numeric
    Private nLeftMargin    := 010 As Numeric
    Private nRightLimit    := 580 As Numeric
    Private nMiddleCol   := (nRightLimit - nLeftMargin) / 2 As Numeric
    //Colunas dos relatorio
    Private nColData1    := nLeftMargin As Numeric
    Private nColData2    := nLeftMargin + 40 As Numeric
    Private nColData3    := nLeftMargin + 100 As Numeric
    Private nColData4    := nLeftMargin + 300 As Numeric
    //Declarando as fontes
    Private cFont                := 'Arial' As Character
    Private oFontDetails         := TFont():New(cFont, /*uPar2*/, -11, /*uPar4*/, .F., /*uPar6*/, /*uPar7*/, /*uPar8*/, /*uPar9*/, .F.) As Object
    Private oFontDetailsBold     := TFont():New(cFont, /*uPar2*/, -13, /*uPar4*/, .T., /*uPar6*/, /*uPar7*/, /*uPar8*/, /*uPar9*/, .F.) As Object
    Private oFontFooter          := TFont():New(cFont, /*uPar2*/, -8,  /*uPar4*/, .F., /*uPar6*/, /*uPar7*/, /*uPar8*/, /*uPar9*/, .F.) As Object
    Private oFontHeaderColumns   := TFont():New(cFont, /*uPar2*/, -7,  /*uPar4*/, .F., /*uPar6*/, /*uPar7*/, /*uPar8*/, /*uPar9*/, .F.) As Object
    Private oFontTitle           := TFont():New(cFont, /*uPar2*/, -15, /*uPar4*/, .T., /*uPar6*/, /*uPar7*/, /*uPar8*/, /*uPar9*/, .F.) As Object
    //Controle de Páginas
    Private nLinesPerPage        := 49
    Private nPagesTotal          := 0
     
    //Monta a consulta de dados
    cQuery += "SELECT "		+ CRLF
    cQuery += " CC2_EST, "		+ CRLF
    cQuery += " CC2_CODMUN, "		+ CRLF
    cQuery += " CC2_Mun "		+ CRLF
    cQuery += "FROM "		+ CRLF
    cQuery += " " + RetSQLName("CC2") + " CC2 "		+ CRLF
    cQuery += "WHERE "		+ CRLF
    cQuery += " CC2_FILIAL = '" + FWxFilial('CC2') + "' "		+ CRLF
    cQuery += " AND CC2_EST >= '" + MV_PAR01 + "' "		+ CRLF
    cQuery += " AND CC2_EST <= '" + MV_PAR02 + "' "		+ CRLF
    cQuery += " AND CC2.D_E_L_E_T_ = ' ' "		+ CRLF
    cQuery += "ORDER BY "		+ CRLF
    cQuery += " CC2_EST, "		+ CRLF
    cQuery += " CC2_MUN"		+ CRLF
	 If '--' $ cQuery .Or. 'WITH' $ Upper(cQuery) .Or. 'NOLOCK' $ Upper(cQuery)
		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(cQuery, 'QRY_AUX')
 
    //Define o tamanho da régua
    DbSelectArea('QRY_AUX')
    QRY_AUX->(DbGoTop())
    Count to nTotal
    ProcRegua(nTotal)
    QRY_AUX->(DbGoTop())

    //Vamos fazer a conta agora, pegando o total de registros, e dividindo pela quantidade que cabe na página
    //  E depois vamos usar o Ceiling() para forçar o arredondamento para cima, por exemplo
    //  50 registros, cabem 40 por página: 50 / 40 = 1,25 . Ai com o Ceiling 1,25 => 2. Total de 2 páginas
    nPagesTotal := nTotal / nLinesPerPage
    nPagesTotal := Ceiling(nPagesTotal)

    //Somente se tiver dados
    If ! QRY_AUX->(EoF())
        //Criando o objeto de impressao
        oPrintReport := FWMSPrinter():New(;
        	cFileName,;      // cFilePrinter
        	IMP_PDF,;        // nDevice
        	.F.,;            // lAdjustToLegacy
        	,;               // cPathInServer
        	.T.,;            // lDisabeSetup
        	,;               // lTReport
        	@oPrintReport,;  // oPrintSetup
        	,;               // cPrinter
        	,;               // lServer
        	,;               // lParam10
        	,;               // lRaw
        	.T.;             // lViewPDF
        )
        oPrintReport:cPathPDF := GetTempPath()
        oPrintReport:SetResolution(72)
        oPrintReport:SetPortrait()
        oPrintReport:SetPaperSize(DMPAPER_A4)
        oPrintReport:SetMargin(0, 0, 0, 0)
 
        //Imprime os dados
        printHeader()
        While ! QRY_AUX->(EoF())
            nCurrent++
            IncProc('Imprimindo registro ' + cValToChar(nCurrent) + ' de ' + cValToChar(nTotal) + '...')
 
            //Se atingiu o limite, quebra de pagina
            validPageBreak()
             
            //Faz o zebrado ao fundo
            If nCurrent % 2 == 0
                oPrintReport:FillRect({nReportLine - 2, nLeftMargin, nReportLine + 12, nRightLimit}, oBrushLin)
            EndIf
 
            //Imprime a linha atual
            oPrintReport:SayAlign(nReportLine, nColData1, Alltrim(QRY_AUX->CC2_EST), oFontDetails, 40, 10, /*nClrText*/, PAD_LEFT, /*nAlignVert*/)
            oPrintReport:SayAlign(nReportLine, nColData2, Alltrim(QRY_AUX->CC2_CODMUN), oFontDetails, 60, 10, /*nClrText*/, PAD_LEFT, /*nAlignVert*/)
            oPrintReport:SayAlign(nReportLine, nColData3, Alltrim(QRY_AUX->CC2_MUN), oFontDetails, 200, 10, /*nClrText*/, PAD_LEFT, /*nAlignVert*/)
 
            nReportLine += 15
            oPrintReport:Line(nReportLine-3, nLeftMargin, nReportLine-3, nRightLimit, nColorGray)
 
            //Se atingiu o limite, quebra de pagina
            validPageBreak()
             
            QRY_AUX->(DbSkip())
        EndDo
        
        //Imprime o último rodapé
        printFooter()
         
        oPrintReport:Preview()
    Else
        FWAlertError('Não foi encontrado informações com os parâmetros informados!', 'Atenção')
    EndIf
    QRY_AUX->(DbCloseArea())
     
    FWRestArea(aArea)
Return

/*/{Protheus.doc} searchLogo
Função que retorna o logo da empresa conforme configuração da DANFE
@author Atilio
@since 14/02/2026
@version 1.0
@type Static Function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/

Static Function searchLogo()
    Local cLogo       := '\x_imagens\logo.png' As Character
Return cLogo

/*/{Protheus.doc} printHeader
Função que imprime o cabeçalho do relatório
@author Atilio
@since 14/02/2026
@version 1.0
@type Static Function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/

Static Function printHeader()
    Local cText        := '' As Character
    Local nHeaderLine  := 015 As Numeric
     
    //Iniciando Pagina
    oPrintReport:StartPage()
    
    //Imprime o logo
    If File(cCompanyLogo)
        oPrintReport:SayBitmap(005, nLeftMargin, cCompanyLogo, 030, 030)
    EndIf
     
    //Cabecalho
    cText := 'Listagem de Cidades'
    oPrintReport:SayAlign(nHeaderLine, nMiddleCol-200, cText, oFontTitle, 400, 20, /*nClrText*/, PAD_CENTER, /*nAlignVert*/)
     
    //Linha Separatoria
    nHeaderLine += 020
    oPrintReport:Line(nHeaderLine,   nLeftMargin, nHeaderLine,   nRightLimit)
     
    //Atualizando a linha inicial do relatorio
    nReportLine := nHeaderLine + 5
    
    oPrintReport:SayAlign(nReportLine, nColData1, 'Estado', oFontHeaderColumns, 40, 10, /*nClrText*/, PAD_LEFT, /*nAlignVert*/)
    oPrintReport:SayAlign(nReportLine, nColData2, 'Cod. Cidade', oFontHeaderColumns, 60, 10, /*nClrText*/, PAD_LEFT, /*nAlignVert*/)
    oPrintReport:SayAlign(nReportLine, nColData3, 'Cidade', oFontHeaderColumns, 200, 10, /*nClrText*/, PAD_LEFT, /*nAlignVert*/)
    nReportLine += 15
Return

/*/{Protheus.doc} printFooter
Função que imprime o rodapé e encerra a página
@author Atilio
@since 14/02/2026
@version 1.0
@type Static Function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/

Static Function printFooter()
    Local nFooterLine := nFooterLimit As Numeric
    Local cText       := '' As Character
 
    //Linha Separatoria
    oPrintReport:Line(nFooterLine,   nLeftMargin, nFooterLine,   nRightLimit)
    nFooterLine += 3
     
    //Dados da Esquerda
    cText := dToC(dDataBase) + '     ' + cTimeReport + '     ' + FunName() + ' (video0235)     ' + UsrRetName(RetCodUsr())
    oPrintReport:SayAlign(nFooterLine, nLeftMargin, cText, oFontFooter, 500, 10, /*nClrText*/, PAD_LEFT, /*nAlignVert*/)
     
    //Direita
    cText := 'Pagina '+cValToChar(nPageCurrent) +  " de " + cValToChar(nPagesTotal)
    oPrintReport:SayAlign(nFooterLine, nRightLimit-200, cText, oFontFooter, 200, 10, /*nClrText*/, PAD_RIGHT, /*nAlignVert*/)
     
    //Finalizando a pagina e somando mais um
    oPrintReport:EndPage()
    nPageCurrent++
Return

/*/{Protheus.doc} validPageBreak
Função que valida se a linha esta próxima do final, se sim quebra a página
@author Atilio
@since 14/02/2026
@version 1.0
@type Static Function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/

Static Function validPageBreak()
    If nReportLine >= nFooterLimit - 10
        printFooter()
        printHeader()
    EndIf
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