No artigo de hoje, vou demonstrar como criar linhas em uma tabela num modelo dot via AdvPL.
Há muito tempo, aproximadamente em 2013, eu precisei fazer esse processo de criar linhas dinamicamente em uma tabela via integração com modelo dot. Na época, os programadores na consultoria tinham me ajudado a chegar na solução.
Porém com o tempo, acabei perdendo o script da macro do Word, eis que recentemente, estava conversando com meu amigo Bruno Vinícius ( LinkedIn ), e com a ajuda dele, consegui montar novamente a macro, e esse exemplo que segue abaixo.
Antes de começar o tutorial, se você não conhece a integração com modelos dot, recomendo a leitura do artigo Gerando um arquivo do Word pelo AdvPL usando integração com Modelos DOT.
- Abra o Word, insira as variáveis (conforme link explicado no artigo acima), e depois clique em Inserir > Tabela, coloque o número de colunas desejada e pelo menos 2 linhas
- Posicione o cursor do mouse, na segunda linha, e na primeira coluna, conforme print abaixo
- Vá em Inserir > Links > Indicador (em inglês Bookmark)
- Dê um nome para o indicador, no nosso exemplo, iremos chamar de tabItens
- Agora vá em Exibir > Macros > Exibir Macros
- Digite um nome para a Macro, iremos repetir o nome usado no passo 4, e então clique no botão Criar
- Cole o comando abaixo na tela de código da Macro (esse código que irá criar as linhas na tabela, juntamente com a criação de DocVariables dentro das células da tabela)
Sub tabItens() ' Cria as variáveis Dim Line As Integer Dim QtdeLines As Integer Dim Campo1 As String Dim Campo2 As String Dim Campo3 As String ' Posiciona no BookMark Selection.GoTo What:=wdGoToBookmark, Name:="tabItens" Selection.Find.ClearFormatting With Selection.Find .Text = "" .Replacement.Text = "" .Forward = True .Wrap = wdFindContinue .Format = False .MatchCase = False .MatchWholeWord = False .MatchWildcards = False .MatchSoundsLike = False .MatchAllWordForms = False End With ' Busca a quantidade de linhas definida em QtdePro QtdeLines = Val(ActiveDocument.Variables.Item("QtdePro").Value) ' Percorre de 1 até o número de linhas definida For Line = 1 To QtdeLines ' Se for a coluna 1, preenche o valor com uma docvariable e pula para a coluna da direita Campo1 = "DOCVARIABLE ITEM1" & Trim(Str(Line)) Selection.Fields.Add Range:=Selection.Range, Type:=wdFieldEmpty, Text:=Campo1, PreserveFormatting:=True Selection.MoveRight Unit:=wdCell ' Se for a coluna 2, preenche o valor com uma docvariable e pula para a coluna da direita Campo2 = "DOCVARIABLE ITEM2" & Trim(Str(Line)) Selection.Fields.Add Range:=Selection.Range, Type:=wdFieldEmpty, Text:=Campo2, PreserveFormatting:=True Selection.MoveRight Unit:=wdCell ' Se for a coluna 3, preenche o valor com uma docvariable Campo3 = "DOCVARIABLE ITEM3" & Trim(Str(Line)) Selection.Fields.Add Range:=Selection.Range, Type:=wdFieldEmpty, Text:=Campo3, PreserveFormatting:=True ' Se a linha atual for menor que a última linha, pula para a direita (irá incluir uma nova linha) If Line < QtdeLines Then Selection.MoveRight Unit:=wdCell End If Next End Sub
- A tela irá ficar com os comandos, conforme print abaixo
- Clique no botão salvar na macro
- Agora, no Word, clique em Salvar Como, escolha uma pasta, e coloque o tipo como Modelo do Word. Esse arquivo, copie para dentro da Protheus Data, no nosso caso, iremos chamar de modelo.dotx e irá ficar dentro da pasta \x_dots\
- Compile a função abaixo em AdvPL, e faça o teste acionando ela, note que ela irá popular as variáveis e depois irá executar a macro para criar as linhas
//Bibliotecas #Include "TOTVS.ch" #Include "TopConn.ch" /*/{Protheus.doc} User Function zTstDot Função de teste, para mostrar como inserir linhas dinamicamente em um modelo dot @type Function @author Atilio @since 29/05/2021 /*/ User Function zTstDot(param_name) Local aArea := GetArea() Local cArquivo := "modelo.dotx" Local cArqSrv := "\x_dots\" + cArquivo Local cDirTmp := GetTempPath() Local nHandWord Local nItens := 0 Local cQuery := "" //Copia o arquivo da protheus data para o pc do usuário CpyS2T(cArqSrv, cDirTmp) //Cria um ponteiro e já chama o arquivo nHandWord := OLE_CreateLink() OLE_NewFile(nHandWord, cDirTmp + cArquivo) //Setando o conteúdo das DocVariables OLE_SetDocumentVar(nHandWord, "DataHoje", dToC(Date())) OLE_SetDocumentVar(nHandWord, "HoraHoje", Time()) OLE_SetDocumentVar(nHandWord, "Autor", UsrRetName(RetCodUsr())) //Busca 10 produtos que sejam do tipo PA e que não estejam bloqueados cQuery += " SELECT TOP 10 " + CRLF cQuery += " B1_COD, " + CRLF cQuery += " B1_DESC, " + CRLF cQuery += " B1_UM " + CRLF cQuery += " FROM " + CRLF cQuery += " " + RetSQLName("SB1") + " SB1 " + CRLF cQuery += " WHERE " + CRLF cQuery += " B1_FILIAL = '" + FWxFilial('SB1') + "' " + CRLF cQuery += " AND B1_MSBLQL != '1' " + CRLF cQuery += " AND B1_TIPO = 'PA' " + CRLF cQuery += " AND SB1.D_E_L_E_T_ = ' ' " + CRLF cQuery += " ORDER BY " + CRLF cQuery += " B1_COD " + CRLF TCQuery cQuery New Alias "QRY_SB1" //Enquanto houver dados na query While ! QRY_SB1->(EOF()) //Incrementa o total de itens nItens++ //Define as variaveis das celulas 1, 2, 3 da linha atual no documento OLE_SetDocumentVar(nHandWord, 'ITEM1' + cValToChar(nItens), QRY_SB1->B1_COD ) OLE_SetDocumentVar(nHandWord, 'ITEM2' + cValToChar(nItens), QRY_SB1->B1_DESC ) OLE_SetDocumentVar(nHandWord, 'ITEM3' + cValToChar(nItens), QRY_SB1->B1_UM ) QRY_SB1->(dbSkip()) EndDo QRY_SB1->(DbCloseArea()) //Define a quantidade de produtos e executa a macro para criar as linhas OLE_SetDocumentVar(nHandWord, 'QtdePro', cValToChar(nItens)) OLE_ExecuteMacro(nHandWord, "tabItens") //Atualizando campos OLE_UpdateFields(nHandWord) //Monstrando um alerta MsgAlert('O arquivo gerado foi <b>Salvo</b>?<br>Ao clicar em OK o Microsoft Word será <b>fechado</b>!','Atenção') //Fechando o arquivo e o link OLE_CloseFile(nHandWord) OLE_CloseLink(nHandWord) RestArea(aArea) Return
- Abaixo um print do resultado do word
Bom pessoal, por hoje é só.
Abraços e até a próxima.
Srs., boa tarde, tudo bem?
Srs., baseando neste modelo eu fiz minha integração com o office, mas quando eu executo, ela para no word, com a seguinte linha: Selection.MoveRight Unit:=wdCell, e não sei como resolver.
Poderia me dar um luz de como consigo resolver?
Obrigado
Boa tarde xará, tudo sim graças a Deus e você?
Esse comando, indica que o Word deve ir para a próxima célula a direita.
Então as duas principais coisas que podem ser, são:
+ Número de colunas não bate entre a macro e a tabela no Word
+ O indicador não foi colocado na primeira célula a preencher dados no Word
Dan Atilio, tudo ótimo.
Em primeiro lugar obrigado pelo retorno.
Em segundo lugar, o numero das colunas estão correto. Mas agora não entendi o que vc se referente o Indicar não foi colocado?
Opa, não precisa agradecer.
Sobre o indicador seria os passos 2, 3 e 4 do tutorial e a linha 10 do código da Macro.
Dan, muito obrigado.
Achei meu erro.
Abraços e obrigado pela orientação.
Opa, eu que agradeço pelo feedback xará.
Um grande abraço.
Boa tarde,
A minha tabela imprime até determinada linha e as linhas abaixo não sai a informação, descrevendo somente “Nenhuma variável de documento foi fornecida”. Mas a linha anteriores estão com os dados corretos. Já pegou algum erro semelhante?
Bom dia James.
Ou o script está inválido, e não consegue popular as variáveis. Ou o seu dot não utiliza tabela dinâmica, e quem fez já deixou as variáveis todas criadas.
Para ver se é o segundo caso, selecione todo o texto do documento do Word, clique com o botão direito e vá em Alternar Código de Campos (exemplo https://terminaldeinformacao.com/2019/01/02/gerando-um-arquivo-word-pelo-advpl-usando-integracao-modelos-dot/ ). Se aparecer o nome das variáveis, você deve fornece-las via AdvPL.
Daniel, a tempos tenho pego clientes onde o windows tem bloqueado esse tipo de integração
“O Microsoft Office identificou um possivel problema de segurança”
“A Microsoft bloqueou a execução de macros porque a origem deste arquivo nao é confiavel”..
Já fiz todo tipo de liberação no windows mas no momento de gerar o arquivo word ocorre essa mensagem e o script da macro nao é executado.
Tem ideia do que pode ser feito pra contornar esse problema?
Bom dia Ari, tudo joia?
Então, de uns tempos pra cá, eu venho orientando os clientes a migrarem da integração com o Word para ficar nativo no AdvPL através da classe FWMSPrinter.
Ai dessa forma, às vezes eu utilizo o Autumn Code Maker para gerar a base do relatório e ganhar um tempo (igual nesse link https://terminaldeinformacao.com/2022/09/22/como-criar-um-relatorio-com-fwmsprinter-em-poucos-passos/ ).
Um grande abraço.