Olá pessoal…
Hoje vou mostrar um exemplo simples de como criar gráfico de barra em AdvPL, utilizando a classe FWChartBar.
Foram criadas novas classes para geração de gráficos substituindo a antiga TMSGraphic, abaixo uma lista das classes novas com o link para o TDN (todas herdam da FwChartFactory):
– FWChartBar – Gráficos de Barra
– FWChartBarComp – Gráficos de Barra (Comparação)
– FWChartLine – Gráficos de Linha
– FWChartPie – Gráficos de Pizza
E abaixo um exemplo simples de FWChartBar (do print acima):
//Bibliotecas #Include "Protheus.ch" /*/{Protheus.doc} zTstChart Função de teste da classe FWChartBar @type function @author Atilio @since 01/12/2015 @version 1.0 @example u_zTstChart() @see http://tdn.totvs.com/display/public/mp/FWChartBar /*/ User Function zTstChart() Local oChart Local oDlg Local aRand := {} //Cria a Janela DEFINE MSDIALOG oDlg PIXEL FROM 0,0 TO 400,600 //Instância a classe oChart := FWChartBar():New() //Inicializa pertencendo a janela oChart:Init(oDlg, .T., .T. ) //Seta o título do gráfico oChart:SetTitle("Título", CONTROL_ALIGN_CENTER) //Adiciona as séries, com as descrições e valores oChart:addSerie("Ano 2011", 20044453.50) oChart:addSerie("Ano 2012", 21044453.35) oChart:addSerie("Ano 2013", 22044453.15) oChart:addSerie("Ano 2014", 23044453.10) oChart:addSerie("Ano 2015", 25544453.01) //Define que a legenda será mostrada na esquerda oChart:setLegend( CONTROL_ALIGN_LEFT ) //Seta a máscara mostrada na régua oChart:cPicture := "@E 999,999,999,999,999.99" //Define as cores que serão utilizadas no gráfico aAdd(aRand, {"084,120,164", "007,013,017"}) aAdd(aRand, {"171,225,108", "017,019,010"}) aAdd(aRand, {"207,136,077", "020,020,006"}) aAdd(aRand, {"166,085,082", "017,007,007"}) aAdd(aRand, {"130,130,130", "008,008,008"}) //Seta as cores utilizadas oChart:oFWChartColor:aRandom := aRand oChart:oFWChartColor:SetColor("Random") //Constrói o gráfico oChart:Build() ACTIVATE MSDIALOG oDlg CENTERED Return
Atualização em 18/02/2017:
Consegui achar uma referência com algumas possíveis cores para utilização:
aAdd(aRand, {"199,199,070", "022,022,008"}) //Amarelo Escuro aAdd(aRand, {"084,120,164", "007,013,017"}) //Azul Claro aAdd(aRand, {"054,090,134", "007,013,017"}) //Azul Escuro aAdd(aRand, {"175,175,175", "011,011,011"}) //Cinza Claro aAdd(aRand, {"130,130,130", "008,008,008"}) //Cinza Médio aAdd(aRand, {"100,100,100", "008,008,008"}) //Cinza Escuro aAdd(aRand, {"207,136,077", "020,020,006"}) //Laranja Claro aAdd(aRand, {"177,106,047", "020,020,006"}) //Laranja Escuro aAdd(aRand, {"001,001,001", "001,001,001"}) //Preto aAdd(aRand, {"141,225,078", "017,019,010"}) //Verde Claro aAdd(aRand, {"171,225,108", "017,019,010"}) //Verde Escuro aAdd(aRand, {"166,085,082", "017,007,007"}) //Vermelho Claro aAdd(aRand, {"136,055,052", "017,007,007"}) //Vermelho Escuro
Atualização em 20/09/2017:
Conforme muitos pediam, montei um exemplo de como gerar o gráfico e já inserir ele em um relatório. Para fazer isso, é só ao iniciar a tela do relatório, gerar um png, e fechar a tela em seguida. Depois com essa imagem você consegue imprimir em um TMSPrinter ou FWMSPrinter.
Abaixo um print do resultado:
E abaixo o código fonte completo desenvolvido:
//Bibliotecas #Include "Protheus.ch" #Include "TopConn.ch" #Include "RPTDef.ch" #Include "FWPrintSetup.ch" #Define PAD_LEFT 0 #Define PAD_RIGHT 1 #Define PAD_CENTER 2 /*/{Protheus.doc} zTeste Função de teste para gerar o gráfico em um relatório @author Atilio @since 20/09/2017 @version undefined @type function /*/ User Function zTeste() Local aArea := GetArea() Local cNomeRel := "rel_teste_"+dToS(Date())+StrTran(Time(), ':', '-') Local cDiretorio := GetTempPath() Local nLinCab := 025 Local nAltur := 250 Local nLargur := 1050 Local aRand := {} Private cHoraEx := Time() Private nPagAtu := 1 Private oPrintPvt //Fontes Private cNomeFont := "Arial" Private oFontRod := TFont():New(cNomeFont, , -06, , .F.) Private oFontTit := TFont():New(cNomeFont, , -20, , .T.) Private oFontSubN := TFont():New(cNomeFont, , -17, , .T.) //Linhas e colunas Private nLinAtu := 0 Private nLinFin := 820 Private nColIni := 010 Private nColFin := 550 Private nColMeio := (nColFin-nColIni)/2 //Criando o objeto de impressão oPrintPvt := FWMSPrinter():New(cNomeRel, IMP_PDF, .F., /*cStartPath*/, .T., , @oPrintPvt, , , , , .T.) oPrintPvt:cPathPDF := GetTempPath() oPrintPvt:SetResolution(72) oPrintPvt:SetPortrait() oPrintPvt:SetPaperSize(DMPAPER_A4) oPrintPvt:SetMargin(60, 60, 60, 60) oPrintPvt:StartPage() //Cabeçalho oPrintPvt:SayAlign(nLinCab, nColMeio-150, "Relatório Teste de Gráfico", oFontTit, 300, 20, RGB(0,0,255), PAD_CENTER, 0) nLinCab += 35 nLinAtu := nLinCab //Se o arquivo existir, exclui ele If File(cDiretorio+"_grafico.png") FErase(cDiretorio+"_grafico.png") EndIf //Cria a Janela DEFINE MSDIALOG oDlgChar PIXEL FROM 0,0 TO nAltur,nLargur //Instância a classe oChart := FWChartBar():New() //Inicializa pertencendo a janela oChart:Init(oDlgChar, .T., .T. ) //Seta o título do gráfico oChart:SetTitle("Título", CONTROL_ALIGN_CENTER) //Adiciona as séries, com as descrições e valores oChart:addSerie("Ano 2011", 20044453.50) oChart:addSerie("Ano 2012", 21044453.35) oChart:addSerie("Ano 2013", 22044453.15) oChart:addSerie("Ano 2014", 23044453.10) oChart:addSerie("Ano 2015", 25544453.01) //Define que a legenda será mostrada na esquerda oChart:setLegend( CONTROL_ALIGN_LEFT ) //Seta a máscara mostrada na régua oChart:cPicture := "@E 999,999,999,999,999.99" //Define as cores que serão utilizadas no gráfico aAdd(aRand, {"084,120,164", "007,013,017"}) aAdd(aRand, {"171,225,108", "017,019,010"}) aAdd(aRand, {"207,136,077", "020,020,006"}) aAdd(aRand, {"166,085,082", "017,007,007"}) aAdd(aRand, {"130,130,130", "008,008,008"}) //Seta as cores utilizadas oChart:oFWChartColor:aRandom := aRand oChart:oFWChartColor:SetColor("Random") //Constrói o gráfico oChart:Build() ACTIVATE MSDIALOG oDlgChar CENTERED ON INIT (oChart:SaveToPng(0, 0, nLargur, nAltur, cDiretorio+"_grafico.png"), oDlgChar:End()) oPrintPvt:SayBitmap(nLinAtu, nColIni, cDiretorio+"_grafico.png", nLargur/2, nAltur/1.6) nLinAtu += nAltur/1.6 + 3 oPrintPvt:SayAlign(nLinAtu, nColIni+020, "Teste FWMSPrinter", oFontSubN, 100, 07, , PAD_LEFT, ) //Impressão do Rodapé fImpRod() //Gera o pdf para visualização oPrintPvt:Preview() RestArea(aArea) Return /*---------------------------------------------------------------------* | Func: fImpRod | | Desc: Função para impressão do rodapé | *---------------------------------------------------------------------*/ Static Function fImpRod() Local nLinRod := nLinFin + 10 Local cTexto := "" //Linha Separatória oPrintPvt:Line(nLinRod, nColIni, nLinRod, nColFin, RGB(200, 200, 200)) nLinRod += 3 //Dados da Esquerda cTexto := "Relatório Teste | "+dToC(dDataBase)+" "+cHoraEx+" "+FunName()+" "+cUserName oPrintPvt:SayAlign(nLinRod, nColIni, cTexto, oFontRod, 250, 07, , PAD_LEFT, ) //Direita cTexto := "Página "+cValToChar(nPagAtu) oPrintPvt:SayAlign(nLinRod, nColFin-40, cTexto, oFontRod, 040, 07, , PAD_RIGHT, ) //Finalizando a página e somando mais um oPrintPvt:EndPage() nPagAtu++ Return
Bom pessoal, por hoje é só.
Abraços e até a próxima.
No meu caso funcionou tudo, menos a questão de cores. Ele não está deixando escolher as cores que quero, independente se coloco random ou se seto uma cor fixa. Ele só fica cor padrão.
Boa noite Mário, tudo bem?
Realizei um teste aqui, realmente são só algumas cores que ele aceita, irei verificar se encontro alguma referência.
Abraços.
Inclusive to fazendo o gráfico do tipo pizza e também não consigo alterar as cores… Liguei no suporte da Totvs e eles me falaram que não tem como alterar as cores… Que vai pegar sempre as cores padrões…
Boa noite Mario, tudo bem?
Então, cacei aqui nas minhas referências, e ele realmente deixa a cor padrão (azulada), mas é possível definir algumas cores (poucas), no caso desse exemplo mesmo eu uso laranja, vermelho, cinza, etc).
Infelizmente não achei nenhuma documentação sobre as cores aceitas.
Obrigado!
Se um dia descobrir algo sobre mudança de cores, eu me interesso.
Eu que agradeço Mário.
Entrarei em contato sim.
Abraços.
Consegue-se desenhar o FWChartBar num panel, restrigindo as dimensões do próprio FWChartBar ?
Fala Thiago, tudo bem?
É possível sim, geralmente é o que eu faço, onde meu Painel (oPanelTst), vai pertencer a minha Dialog (oDialogTst) e o gráfico estará no Painel (oChartTst), por exemplo:
Espero ter ajudado.
Um grande abraço.
Eu não to conseguindo fazer mostrar os valores das séries, existe alguma forma de mostrar o valor? Aqui só mostra se eu posicionar o cursor, queria que aparecesse junto a série.
Boa noite João, tudo bem?
Eu também não consegui achar uma forma, então como paliativo, eu coloco como título da série, por exemplo:
Espero ter ajudado.
Abraços.
Boa tarde amigo!
Há a possibilidade de definir a escala do gráfico? Tentei utilizar SetMinY e SetMinX, porém os dois métodos parecem não funcionar.
Boa noite Murilo, tudo bem?
Rapaz, não sei te dizer, eu nunca precisei mudar a escala.
E quando eu fiz, lembro de ter dividido os valores para ficar menor o gráfico.
Acho que cabe um chamado nessa questão.
Um grande abraço.
como posso imprimir o grafico???
Boa noite Jose, tudo bem?
Você teria que ao abrir a tela com o gráfico, gerar um png dele, e esse png você imprime em um TMSPrinter ou FWMSPrinter.
Eu atualizei a postagem com um exemplo completo, espero que ajude.
Abraços.
Pergunta cabulosa #1, consigo gerar estes graficos num job, e enviar por email, via scheduler ? ? ?
Obrigado. MAterial muito bom !
Boa noite.
Sim, você deve usar o método SaveToPng, http://tdn.totvs.com/pages/releaseview.action?pageId=111182092
Depois disso, você consegue manipular a imagem conforme você deseja.
Para gerar o png, ao iniciar a janela, você deve dar um End, e já gerar em seguida, por exemplo:
Depois do arquivo gerado, ai você pode mandar por email, colocar em relatórios, etc…
Qualquer dúvida, fico à disposição.
Abraços.
Boa tarde.
Há algum método para limpar as series do grafico.
Estou utilizando um grid que toda vez que clico preenche um grafico com os dados.
Quando clico pela segundavez no grid ele acumula os valores preenchidos anteriormente e adiciona os novos.
Obriago,
Eduardo
Boa noite Eduardo, tudo bem?
Rapaz, desconheço se existe algum método assim, talvez será necessário abrir um chamado e perguntar, mas talvez pode ser difícil que respondam algo tão técnico.
Um grande abraço man.
Boa Tarde Dan Atilio.
Consegui o efeito desejado, instanciando novamente o objeto toda vez antes de inserir os itens da série.
o comando é: oChartTst := FWChartBar():New()
O suporte da Totvs ainda não respondeu se está é a solução definitiva…u
Entendi Eduardo, ai sim hein.
Se eles responderem por favor, entre em contato com a resposta.
Um grande abraço.
Falaram para utilizar desta forma mesmo. Acho que nunca tiveram esta necessidade ou não esta previsto este tipo de uso.
Abraços,
Entendi Eduardo.
Obrigado pela contribuição.
Um grande abraço.
Boa tarde, teria algum jeito de, ao colocar um conteúdo muito grande como por exemplo 50 descrições ele gerar uma nova página com a continuação dos dados, tipo 25 pra cada página?
Acho que não entendi muito bem Polti.
Poderia detalhar em algum pdf e me mandar por e-Mail?
Obrigado.
Estou desenvolvendo uma customização com esse recurso, mas somente tenho conseguido salvar o arquivo local no client, como faço para salvar no servidor?
Boa noite Carlos, tudo bem? Desconheço como salvar direto no Servidor, o que você pode fazer, é gerar localmente, e usar CpyT2S para copiar para dentro da Protheus Data. Um grande abraço.
Boa tarde Dan!
Tenho o fonte abaixo onde é realizado um cadastro simples e tenho seu fonte em uma static function grafic onde é criado o grafico!
A pergunta é como que coloco esse gráfico na parte inferior do browser?
#Include ‘Protheus.ch’
#Include ‘FWMVCDef.ch’
#INCLUDE “JURA039.CH”
//Variáveis Estáticas
Static cTitulo := “teste”
//——————————————————————-
/*/{Protheus.doc} INFJ0020
@since 27/01/2021
@version 1.0
/*/
//——————————————————————-
User Function TST0020()
Local aArea := GetArea()
Local oBrowse
//Instânciando FWMBrowse – Somente com dicionário de dados
oBrowse := FWMBrowse():New()
//Setando a tabela de cadastro de Autor/Interprete
oBrowse:SetAlias(“ZZF”)
//Setando a descrição da rotina
oBrowse:SetDescription(cTitulo)
//Legendas
oBrowse:AddLegend( “ZZF->ZZF_ATIVO == ‘2’”, “GREEN”, “Ativo” )
oBrowse:AddLegend( “ZZF->ZZF_ATIVO == ‘1’”, “RED”, “Encerrado” )
//Ativa a Browse
oBrowse:Activate()
RestArea(aArea)
Return Nil
//——————————————————————-
/*/{Protheus.doc} MenuDef
Menu Funcional
@return aRotina – Estrutura
[n,1] Nome a aparecer no cabecalho
[n,2] Nome da Rotina associada
[n,3] Reservado
[n,4] Tipo de Transação a ser efetuada:
1 – Pesquisa e Posiciona em um Banco de Dados
2 – Simplesmente Mostra os Campos
3 – Inclui registros no Bancos de Dados
4 – Altera o registro corrente
5 – Remove o registro corrente do Banco de Dados
6 – Alteração sem inclusão de registros
7 – Cópia
8 – Imprimir
[n,5] Nivel de acesso
[n,6] Habilita Menu Funcional
@since 27/01/2021
@version 1.0
/*/
//——————————————————————-
Static Function MenuDef()
Local aRotina := {}
aAdd( aRotina, { STR0001, “PesqBrw” , 0, 1, 0, .T. } ) // “Pesquisar”
aAdd( aRotina, { STR0002, “VIEWDEF.INFJ0020”, 0, 2, 0, NIL } ) // “Visualizar”
aAdd( aRotina, { STR0003, “VIEWDEF.INFJ0020”, 0, 3, 0, NIL } ) // “Incluir”
aAdd( aRotina, { STR0004, “VIEWDEF.INFJ0020”, 0, 4, 0, NIL } ) // “Alterar”
aAdd( aRotina, { STR0005, “VIEWDEF.INFJ0020”, 0, 5, 0, NIL } ) // “Excluir”
aAdd( aRotina, { STR0006, “VIEWDEF.INFJ0020”, 0, 8, 0, NIL } ) // “Imprimir”
Return aRotina
//——————————————————————-
/*/{Protheus.doc} ModelDef
Modelo de dados do Business Plan
@since 27/01/2021
@version 1.0
/*/
//——————————————————————-
Static Function ModelDef()
Local oModel := Nil
Local oStructZZF := FWFormStruct(1, ‘ZZF’)
Local usuario := UsrRetName(RetCodUsr())
//Criando o modelo e os relacionamentos
oModel := MPFormModel():New(‘INFJ20’)
oModel:AddFields(‘ZZFMASTER’,/*cOwner*/,oStructZZF)
oModel:SetPrimaryKey({})
//Setando as descrições
oModel:SetDescription(“teste”)
oModel:GetModel(‘ZZFMASTER’):SetDescription(‘teste’)
Return oModel
//——————————————————————-
/*/{Protheus.doc} ViewDef
@since 27/01/2021
@version 1.0
/*/
//——————————————————————-
Static Function ViewDef()
Local oView := Nil
Local oModel := FWLoadModel(‘TST0020’)
Local oStructZZF := FWFormStruct(2, ‘ZZF’)
//Criando a View
oView := FWFormView():New()
oView:SetModel(oModel)
//Adicionando os campos do cabeçalho e o grid dos filhos
oView:AddField(‘VIEW_ZZF’,oStructZZF,’ZZFMASTER’)
//Setando o dimensionamento de tamanho
oView:CreateHorizontalBox(‘CABEC’,100)
//Amarrando a view com as box
oView:SetOwnerView(‘VIEW_ZZF’,’CABEC’)
Return oView
//——————————————————————-
/*/{Protheus.doc} ViewDef
@since 27/01/2021
@version 1.0
/*/
//——————————————————————-
user Function UALT0020()
Local cUsuario := UsrRetName(RetCodUsr())
if M->ZZF_ATIVO == ‘1’
ZZF->ZZF_DTENC := DATE()
ZZF->ZZF_USRENC := usuario
endif
Return cUsuario
//——————————————————————-
/*/{Protheus.doc} ViewDef
@since 27/01/2021
@version 1.0
/*/
//——————————————————————-
User Function GRAFIC()
Local oChart
Local oDlg
Local aRand := {}
//Instância a classe
oChart := FWChartBar():New()
//Inicializa pertencendo a janela
oChart:Init(oDlg, .T., .T. )
//Seta o título do gráfico
oChart:SetTitle(“Título”, CONTROL_ALIGN_CENTER)
//Adiciona as séries, com as descrições e valores
oChart:addSerie(“Ano 2011”, 20044453.50)
oChart:addSerie(“Ano 2011”, 15044453.50)
oChart:addSerie(“Ano 2012”, 21044453.35)
oChart:addSerie(“Ano 2012”, 12044453.35)
oChart:addSerie(“Ano 2013”, 22044453.15)
oChart:addSerie(“Ano 2013”, 18044453.15)
oChart:addSerie(“Ano 2014”, 23044453.10)
oChart:addSerie(“Ano 2014”, 9044453.10)
oChart:addSerie(“Ano 2015”, 25544453.01)
oChart:addSerie(“Ano 2015”, 20544453.01)
//Define que a legenda será mostrada na esquerda
oChart:setLegend( CONTROL_ALIGN_LEFT )
//Seta a máscara mostrada na régua
oChart:cPicture := “@E 999,999,999,999,999.99”
//Define as cores que serão utilizadas no gráfico
aAdd(aRand, {“084,120,164”, “007,013,017”})
aAdd(aRand, {“171,225,108”, “017,019,010”})
aAdd(aRand, {“084,120,164”, “007,013,017”})
aAdd(aRand, {“171,225,108”, “017,019,010”})
aAdd(aRand, {“084,120,164”, “007,013,017”})
aAdd(aRand, {“171,225,108”, “017,019,010”})
aAdd(aRand, {“084,120,164”, “007,013,017”})
aAdd(aRand, {“171,225,108”, “017,019,010”})
//Seta as cores utilizadas
oChart:oFWChartColor:aRandom := aRand
oChart:oFWChartColor:SetColor(“Random”)
//Constrói o gráfico
oChart:Build()
Return
Consegue me ajudar?
Abraços!
Bom dia Vagner, tudo bem?
Eu nunca precisei adicionar um gráfico em um FWmBrowse, mas comecei a procurar por alguns exemplos, não encontrei muita coisa, apenas a menção à um método chamado SetChartsDefault, tente talvez utilizá-lo.
Se conseguir algo me avise também.
Grande abraço.
Boa tarde. Consegui cirar o grafico perfeitamente com o explicado. Obrigado!
A minha duvida é se seria possivel adicionar rotulos a cada serie do grafico, tal como é possivel realizar em excel.
Algo como o exemplo do link abaixo:https://support.content.office.net/pt-br/media/f28cf4e3-05f2-41af-9208-0bffd461770e.jpg
Obrigado!
Bom dia.
Você diz, conforme o lado esquerdo nessa imagem – https://terminaldeinformacao.com/wp-content/uploads/2016/08/grafico.png ?
Que tem o ano de 2011 a 2015. Se sim, no próprio addSerie, você já passa a informação.
Bom dia Atilio.
Não, eu gostaria de mostrar as procentagens em cada pedaço da pizza no exemplo que eu mandei.
Obrigado!
Ah, agora entendi.
Certo, eu desconheço se existe algum método especificamente para adicionar um texto de label em cada pedaço na pizza.
O que você pode fazer como paliativo, seria criar um TSay em cada pedaço, mas acho que seria complicado calcular os pontos da tela em que irá exibir.
Como hoje, já existe a possibilidade de você posicionar o mouse em cima, e ele mostrar um tooltip, tente também abrir um chamado na TOTVS perguntando se na FwChartFactory, tem a opção de já exibir esse texto do tooltip em cada pedaço.
Um grande abraço.
Ola Atilio, tudo bem?
Primeiramente obrigado, aprendia programar advpl vendo seus fontes, muito mais que a TDN rsrsrs,
Gostaria de saber se e possível eu fazer um gráfico que atualiza de tempos em tempos, tipo usando o TTIME(),
O novato aqui não esta conseguindo fazer dar certo para atualizar o gráfico a cada 5 minutos.
Boa tarde, tudo sim graças a Deus e você?
Primeiramente obrigado pela gentileza e feedback.
Na verdade, mais ou menos, o que você pode fazer é instanciar um TTimer (aula 21 do nosso curso de orientação a objetos) que rode a cada 5 minutos.
Ai nesse temporizador, você cria um novo gráfico por cima do antigo, pois até então (pode ser que tenham atualizado as classes), não existia no passado um método só para atualizar, então caso quisesse teria que ficar criando um por cima do outro.
Claro que com o tempo, essa thread vai ficando grande, então você tem que só se atentar a isso.
Um grande abraço.