No vídeo de hoje, vamos demonstrar em como criar um relatório com vários quadrados via FWMSPrinter.
A dúvida de hoje, nos perguntaram, se seria possível imprimir informações em um FWMSPrinter mas ao invés de ser linha em baixo de outra linha, ser por blocos, como se fossem por colunas.
Pensando nisso, montamos esse exemplo, onde vamos demonstrar em como fazer essa lógica de quebra por blocos e colunas.
Segue abaixo o vídeo exemplificando:
E abaixo o código fonte desenvolvido:
//Bibliotecas #Include "Totvs.ch" #Include "TopConn.ch" #Include "RPTDef.ch" #Include "FWPrintSetup.ch" //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 nCorCinza := RGB(110, 110, 110) Static nCorLinha := RGB(165, 255, 203) /*/{Protheus.doc} User Function zVid0131 Lista de Produtos @author Atilio @since 20/03/2024 @version 1.0 @type function @obs Codigo gerado automaticamente pelo Autumn Code Maker @see http://autumncodemaker.com /*/ User Function zVid0131() Local aArea := FWGetArea() Local aPergs := {} Local xPar0 := Space(15) Local xPar1 := StrTran(xPar0, " ", "Z") //Adicionando os parametros do ParamBox aAdd(aPergs, {1, "Produto De", xPar0, "", ".T.", "SB1", ".T.", 80, .F.}) aAdd(aPergs, {1, "Produto Até", xPar1, "", ".T.", "SB1", ".T.", 80, .T.}) //Se a pergunta for confirma, cria o relatorio If ParamBox(aPergs, 'Informe os parâmetros', /*aRet*/, /*bOk*/, /*aButtons*/, /*lCentered*/, /*nPosx*/, /*nPosy*/, /*oDlgWizard*/, /*cLoad*/, .F., .F.) Processa({|| fImprime()}) EndIf FWRestArea(aArea) Return /*/{Protheus.doc} fImprime Faz a impressão do relatório zVid0138 @author Atilio @since 20/03/2024 @version 1.0 @type function @obs Codigo gerado automaticamente pelo Autumn Code Maker @see http://autumncodemaker.com /*/ Static Function fImprime() Local aArea := FWGetArea() Local nTotAux := 0 Local nAtuAux := 0 Local cQryAux := '' Local cArquivo := 'zVid0138'+RetCodUsr()+'_' + dToS(Date()) + '_' + StrTran(Time(), ':', '-') + '.pdf' Private oPrintPvt Private oBrushLin := TBrush():New(,nCorLinha) Private cHoraEx := Time() Private nPagAtu := 1 Private cLogoEmp := fLogoEmp() //Linhas e colunas Private nLinAtu := 0 Private nLinFin := 800 Private nColIni := 010 Private nColFin := 580 Private nColMeio := (nColFin-nColIni)/2 Private nAlturLin := 15 Private nColAtual := 0 Private nColLargu := ((nColFin - nColIni) / 3) - 10 //Declarando as fontes Private cNomeFont := 'Arial' Private oFontDet := TFont():New(cNomeFont, /*uPar2*/, -11, /*uPar4*/, .F., /*uPar6*/, /*uPar7*/, /*uPar8*/, /*uPar9*/, .F.) Private oFontDetN := TFont():New(cNomeFont, /*uPar2*/, -13, /*uPar4*/, .T., /*uPar6*/, /*uPar7*/, /*uPar8*/, /*uPar9*/, .F.) Private oFontRod := TFont():New(cNomeFont, /*uPar2*/, -8, /*uPar4*/, .F., /*uPar6*/, /*uPar7*/, /*uPar8*/, /*uPar9*/, .F.) Private oFontMin := TFont():New(cNomeFont, /*uPar2*/, -7, /*uPar4*/, .F., /*uPar6*/, /*uPar7*/, /*uPar8*/, /*uPar9*/, .F.) Private oFontTit := TFont():New(cNomeFont, /*uPar2*/, -15, /*uPar4*/, .T., /*uPar6*/, /*uPar7*/, /*uPar8*/, /*uPar9*/, .F.) //Monta a consulta de dados cQryAux += "SELECT B1_COD, B1_DESC, B1_UM, B1_TIPO " + CRLF cQryAux += "FROM SB1990 SB1 " + CRLF cQryAux += "WHERE B1_FILIAL = '' " + CRLF cQryAux += "AND B1_MSBLQL != '1' " + CRLF cQryAux += "AND B1_COD >= '" + MV_PAR01 + "' " + CRLF cQryAux += "AND B1_COD <= '" + MV_PAR02 + "' " + CRLF cQryAux += "AND SB1.D_E_L_E_T_ = ' ' " + CRLF cQryAux += "ORDER BY B1_COD" + CRLF PLSQuery(cQryAux, 'QRY_AUX') //Define o tamanho da régua DbSelectArea('QRY_AUX') QRY_AUX->(DbGoTop()) Count to nTotAux ProcRegua(nTotAux) QRY_AUX->(DbGoTop()) //Somente se tiver dados If ! QRY_AUX->(EoF()) //Criando o objeto de impressao oPrintPvt := FWMSPrinter():New(; cArquivo,; // cFilePrinter IMP_PDF,; // nDevice .F.,; // lAdjustToLegacy ,; // cPathInServer .T.,; // lDisabeSetup ,; // lTReport @oPrintPvt,; // oPrintSetup ,; // cPrinter ,; // lServer ,; // lParam10 ,; // lRaw .T.; // lViewPDF ) oPrintPvt:cPathPDF := GetTempPath() oPrintPvt:SetResolution(72) oPrintPvt:SetPortrait() oPrintPvt:SetPaperSize(DMPAPER_A4) oPrintPvt:SetMargin(0, 0, 0, 0) //Imprime os dados fImpCab() While ! QRY_AUX->(EoF()) nAtuAux++ IncProc('Imprimindo registro ' + cValToChar(nAtuAux) + ' de ' + cValToChar(nTotAux) + '...') //Se atingiu o limite, quebra de pagina fQuebra() //Se a coluna atingiu 3 If nColAtual == 3 //Volta pra coluna 1 nColAtual := 1 //Incrementa as 5 linhas (produto, descrição, tipo e u.m.) nLinAtu += (nAlturLin * 5) //Senão, incrementa a coluna Else nColAtual++ EndIf //Define a coluna inicial da impressão e a coluna final nColTxtIni := nColIni + ((nColAtual-1) * nColLargu) + 10 //Faz um quadro envolvendo todas as 5 linhas oPrintPvt:Box(nLinAtu, nColTxtIni, nLinAtu + (nAlturLin * 4), nColTxtIni + nColLargu) //Faz o zebrado ao fundo (nos pares) If nAtuAux % 2 == 0 oPrintPvt:FillRect({nLinAtu + 2, nColTxtIni + 2, nLinAtu + (nAlturLin * 4) - 2, nColTxtIni + nColLargu - 2}, oBrushLin) EndIf //Imprime os textos dentro do quadro oPrintPvt:SayAlign(nLinAtu + (nAlturLin * 0), nColTxtIni + 3, 'Cód.:', oFontMin, 30, 10, nCorCinza, PAD_LEFT, /*nAlignVert*/) oPrintPvt:SayAlign(nLinAtu + (nAlturLin * 1), nColTxtIni + 3, 'Des.:', oFontMin, 30, 10, nCorCinza, PAD_LEFT, /*nAlignVert*/) oPrintPvt:SayAlign(nLinAtu + (nAlturLin * 2), nColTxtIni + 3, 'U.M.:', oFontMin, 30, 10, nCorCinza, PAD_LEFT, /*nAlignVert*/) oPrintPvt:SayAlign(nLinAtu + (nAlturLin * 3), nColTxtIni + 3, 'Tipo:', oFontMin, 30, 10, nCorCinza, PAD_LEFT, /*nAlignVert*/) oPrintPvt:SayAlign(nLinAtu + (nAlturLin * 0), nColTxtIni + 23, Alltrim(QRY_AUX->B1_COD), oFontDetN, 60, 10, /*nClrText*/, PAD_LEFT, /*nAlignVert*/) oPrintPvt:SayAlign(nLinAtu + (nAlturLin * 1), nColTxtIni + 23, Alltrim(QRY_AUX->B1_DESC), oFontDet, 120, 10, /*nClrText*/, PAD_LEFT, /*nAlignVert*/) oPrintPvt:SayAlign(nLinAtu + (nAlturLin * 2), nColTxtIni + 23, Alltrim(QRY_AUX->B1_UM), oFontDet, 60, 10, /*nClrText*/, PAD_LEFT, /*nAlignVert*/) oPrintPvt:SayAlign(nLinAtu + (nAlturLin * 3), nColTxtIni + 23, Alltrim(QRY_AUX->B1_TIPO), oFontDet, 60, 10, /*nClrText*/, PAD_LEFT, /*nAlignVert*/) //Se atingiu o limite, quebra de pagina fQuebra() QRY_AUX->(DbSkip()) EndDo //Imprime o último rodapé fImpRod() oPrintPvt: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} fLogoEmp Função que retorna o logo da empresa conforme configuração da DANFE @author Atilio @since 20/03/2024 @version 1.0 @type function @obs Codigo gerado automaticamente pelo Autumn Code Maker @see http://autumncodemaker.com /*/ Static Function fLogoEmp() Local cLogo := '\x_imagens\logo.png' Return cLogo /*/{Protheus.doc} fImpCab Função que imprime o cabeçalho do relatório @author Atilio @since 20/03/2024 @version 1.0 @type function @obs Codigo gerado automaticamente pelo Autumn Code Maker @see http://autumncodemaker.com /*/ Static Function fImpCab() Local cTexto := '' Local nLinCab := 015 //Iniciando Pagina oPrintPvt:StartPage() //Imprime o logo If File(cLogoEmp) oPrintPvt:SayBitmap(005, nColIni, cLogoEmp, 030, 030) EndIf //Cabecalho cTexto := 'Lista Produtos' oPrintPvt:SayAlign(nLinCab, nColMeio-200, cTexto, oFontTit, 400, 20, /*nClrText*/, PAD_CENTER, /*nAlignVert*/) //Linha Separatoria nLinCab += 020 oPrintPvt:Line(nLinCab, nColIni, nLinCab, nColFin) //Atualizando a linha inicial do relatorio nLinAtu := nLinCab + 5 If nPagAtu == 1 //Imprimindo os parâmetros cTexto := MV_PAR01 oPrintPvt:SayAlign(nLinAtu, nColIni, 'Produto De', oFontDetN, 200, 10, /*nClrText*/, PAD_LEFT, /*nAlignVert*/) oPrintPvt:SayAlign(nLinAtu, nColIni+200, cTexto, oFontDet, 200, 10, /*nClrText*/, PAD_LEFT, /*nAlignVert*/) nLinAtu += 15 cTexto := MV_PAR02 oPrintPvt:SayAlign(nLinAtu, nColIni, 'Produto Até', oFontDetN, 200, 10, /*nClrText*/, PAD_LEFT, /*nAlignVert*/) oPrintPvt:SayAlign(nLinAtu, nColIni+200, cTexto, oFontDet, 200, 10, /*nClrText*/, PAD_LEFT, /*nAlignVert*/) nLinAtu += 15 oPrintPvt:Line(nLinAtu-3, nColIni, nLinAtu-3, nColFin, nCorCinza) nLinAtu += 5 EndIf Return /*/{Protheus.doc} fImpRod Função que imprime o rodapé e encerra a página @author Atilio @since 20/03/2024 @version 1.0 @type function @obs Codigo gerado automaticamente pelo Autumn Code Maker @see http://autumncodemaker.com /*/ Static Function fImpRod() Local nLinRod:= nLinFin Local cTexto := '' //Linha Separatoria oPrintPvt:Line(nLinRod, nColIni, nLinRod, nColFin) nLinRod += 3 //Dados da Esquerda cTexto := dToC(dDataBase) + ' ' + cHoraEx + ' ' + FunName() + ' (zVid0138) ' + UsrRetName(RetCodUsr()) oPrintPvt:SayAlign(nLinRod, nColIni, cTexto, oFontRod, 500, 10, /*nClrText*/, PAD_LEFT, /*nAlignVert*/) //Direita cTexto := 'Pagina '+cValToChar(nPagAtu) oPrintPvt:SayAlign(nLinRod, nColFin-40, cTexto, oFontRod, 040, 10, /*nClrText*/, PAD_RIGHT, /*nAlignVert*/) //Finalizando a pagina e somando mais um oPrintPvt:EndPage() nPagAtu++ Return /*/{Protheus.doc} fQuebra Função que valida se a linha esta próxima do final, se sim quebra a página @author Atilio @since 20/03/2024 @version 1.0 @type function @obs Codigo gerado automaticamente pelo Autumn Code Maker @see http://autumncodemaker.com /*/ Static Function fQuebra() //Linha atual + 5 linhas (produto, descrição, unid medida, tipo e linha vazia) for estourar a página, ai faz a quebra If nLinAtu + (nAlturLin * 5) >= nLinFin-10 fImpRod() fImpCab() EndIf Return
Bom pessoal, por hoje é só.
Abraços e até a próxima.