Tutorial: Criando um gráfico com dados em XML no Flex 2.0
Este é um interessante tutorial em que criaremos uma pequena aplicação em Flex 2.0 com um gráfico que mostrará informações originadas de um arquivo XML. Adicionalmente, conceitos importantes de container e comunicação são mostrados.É pressuposto que o o Flex 2 já esteja instalado e que sejam possuidos conhecimentos básicos sobre o funcionamento do Flex Builder, já que todo o tutorial será feito a partir de código MXML e ActionScript (ou seja, sem utilizar o design view do Flex Builder.
Atenção: A versão utilizada foi o Flex Builder 2.0 Beta 1, de modo que divergências podem ocorrer.
Após o tutorial, nosso aplicação ficará assim:

Resultado final deste tutorial
Criando a “Aplicação”
Muito do layout dos componentes do Flex é feito a partir de containers, que são classes que contém a lógica de scroll, instâncias de componente, posicionamento, etc. Application é o container principal de uma aplicação em Flex e aplicações acessadas diretamente requerem o uso do mesmo. Isso não quer dizer que todo arquivo MXML precisa começar com essa tag; ele pode começar com outras caso ele já esteja “dentro” de um Application.
1 2 3 | <mx:Application> </mx:Application> |
Na tag raiz de um arquivo MXML define-se os namespaces a serem utilizados no arquivo. Namespace é uma características de arquivos XML e tem por objetivo identificar elementos duplicados e atributos. É prática identificar os componentes utilizados no Flex com o namespace mx, como faremos em nosso Application:
Desse modo, os componentes do Flex estarão acessíveis através do namespace mx, tal como a nossa chamada do próprio componente Application!
1 2 3 4 | <mx:Application xmlns:mx="http://www.macromedia.com/2005/mxml"> </mx:Application> |
Dados
Os dados que utilizaremos para essa aplicação de exemplo é um simples arquivo XML, que descreve valores previstos e realizados de portos:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <portos> <porto> <nome>Santos</nome> <prev>50000</prev> <real>45500</real> <dif>4500</dif> </porto> <porto> <nome>Rio de Janeiro</nome> <prev>49800</prev> <real>32000</real> <dif>17800</dif> </porto> <porto> <nome>Rio Grande</nome> <prev>25000</prev> <real>12000</real> <dif>13000</dif> </porto> </portos> |
Visualizar os dados
Um Panel é um container que contém uma barra de título, uma borda e uma área de conteúdo para seus componentes “filhos”. Ele é dessa maneira para identificar nível ou módulos em nossa aplicação.
Vamos construir um Panel que ocupará todo o tamanho disponível em nossa tela, ou seja, configurando sua altura (height) e largura (width) para 100% do espaço disponível de seu container pai – o Application, bem como fornecer um título a ele:
1 2 3 | <mx:Panel title="Análise" width="100%" height="100%"> </mx:Panel> |
O código está até esse momento portanto, da seguinte maneira:
1 2 3 4 5 6 7 | <mx:Application xmlns:mx="http://www.macromedia.com/2005/mxml"> <mx:Panel title="Análise" width="100%" height="100%"> </mx:Panel> </mx:Application> |
E temos como resultado a seguinte imagem:
Panel criado
Dentro de nosso painel, como primeira forma de visualização de nossos dados, utilizaremos um DataGrid, um componente que oferece uma visualização de uma tabela. Igualmente ao nosso Panel, vamos utilizar todo o espaço disponível, configurando a altura e largura para 100%. Essa questão do tamanho dos componentes é importante pois caso contrário o componente ocuparia apenas o espaço necessário para mostrar seu conteúdo. Há outras formas de posicionar e dimensionar os componentes, que serão vistos em artigos futuros.
1 2 3 | <mx:DataGrid width="100%" height="100%"> </mx:DataGrid> |
O DataGrid contudo ainda não está completo. Uma das propriedades do datagrid é columns, e que como pode ser visto na documentação é um Array (uma matriz, um conjunto ordenado de) objetos DataGridColumn. Assim vamos definir nossa propriedade columns com um cojunto de tags DataGridColumn, dentro do DataGrid.
1 2 3 4 5 6 | <mx:columns> <mx:DataGridColumn columnName="nome" headerText="Porto" /> <mx:DataGridColumn columnName="prev" headerText="Previsto" /> <mx:DataGridColumn columnName="real" headerText="Realizado" /> <mx:DataGridColumn columnName="dif" headerText="Diferença" /> </mx:columns> |
Notem que columns não começa com a letra maiúscula como as outras tags que utilizamos aqui! A letra inicial maíscula indica que o componente é oriundo de uma classe do ActionScript, e a tag (depois do namespace) começando com a letra minúscula indica que é uma propriedade de sua tag pai (ou seja, columns é uma propriedade do Panel). Para cada uma de nossas colunas identificamos outros dois atributos: columnName, referente ao nome da coluna de nosso objeto de dados (as tags filhas da tag “porto” em nosso arquivo XML), e headerText, referente ao título daquela coluna em nossa tabela.
Acessando os dados do Flex
Agora que a base da aplicação, um módulo de análise e uma tabela estão construídos, o Flex pode importar os dados. Como nosso arquivo é do tipo XML, a melhor maneira de carrega-lo dinamicamente é utilizando o componente HTTPService, que realiza uma chamada HTTP. Logo após a tag Application, colocaremos o seguinte código:
1 2 3 4 | <mx:HTTPService id="service" url="dados.xml" /> |
A propriedade id literalmente identifica o nosso componente para que posteriormente possamos invocá-lo, já que simplesmente declará-lo não implica nele ser executado (nem o arquivo dados.xml acessado). Nesse exemplo estamos considerando que o arquivo dados.xml está no mesmo diretório em que compilaremos nossa aplicação em Flex.
Pois bem, como o serviço HTTP ainda não foi executado criaremos uma função que o fará. Acima desse componente, e abaixo do Application definiremos a função initApp:
1 2 3 4 5 | <mx:Script> private function initApp():void { service.send(); } </mx:Script> |
Esse nosso método é privado (só pode ser acessada desse componente), seu nome é initApp, não aceita argumentos (parenteses vazio), e não retorna nada (void). Mas quando ele for executada dirá para o HTTPService enviar a requisição.
Para que essa função seja disparada, diremos que quando a aplicação terminar de ser construída, esse método deverá ser chamado, utilizando a propriedade creationComplete da tag Application.
1 | creationComplete="initApp();" |
Nosso código até o momento está o seguinte:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | <mx:Application xmlns:mx="http://www.macromedia.com/2005/mxml" creationComplete="initApp();" > <mx:Script> private function initApp():void { service.send(); } </mx:Script> <mx:HTTPService id="service" url="dados.xml" /> <mx:Panel title="Análise" width="100%" height="100%"> <mx:DataGrid width="100%" height="100%"> <mx:columns> <mx:DataGridColumn columnName="nome" headerText="Porto" /> <mx:DataGridColumn columnName="prev" headerText="Previsto" /> <mx:DataGridColumn columnName="real" headerText="Realizado" /> <mx:DataGridColumn columnName="dif" headerText="Diferença" /> </mx:columns> </mx:DataGrid> </mx:Panel> </mx:Application> |
Mas ao executar esse código, teremos a impressão de que nada acontece. Na verdade o arquivo XML está sendo baixado para a aplicação, mas a tag HTTPService não sabe o que fazer com ele!
Então nós vamos dizer para esse componente o que fazer quando os resultados chegarem: executar o método resultHandler passando o evento que está acontecendo como argumento. Notem que “event” aqui denota o event que aconteceu, e não o nome do objeto.
1 | result="resultHandler(event)" |
Vamos criar esse método dentro de nosso bloco de ActionScript, e junto com ela importaremos os eventos da classe correspondente do evento que estamos passando.
1 2 3 4 5 | import mx.rpc.events.*; private function resultHandler(event:ResultEvent):void { } |
Nesse método estamos esperando portanto uma variável de nome “event”, e do tipo ResultEvent. Como importamos o “package” mx.rpc.events.*, podemos utilizar os eventos do pacote RPC (Remote Procedure Calls, responsáveis pelas formas de conexão do Flex com sistema legados), e em nosso caso o evento de resultado de algo.
Populando o DataGrid
Outra questão importante é criar em nossa aplicação uma variável que ficará disponível para toda a aplicação e que conterá os dados resultantes dessa conexão com o XML. Essa variável será do tipo ArrayCollection, um tipo especial de array que o Flex utiliza como fonte de dados para muitos dos componentes, como nosso DataGrid.
1 2 3 4 | import mx.collections.ArrayCollection; [Bindable] public var dadosInput:ArrayCollection; |
Importamos somente classe (não utilizamos o asterísco como da outra vez, ou seja, não importamos o pacote collections inteiro), criamos nossa variável privada (disponível apenas para nosso arquivo MXML), nomeamos-a como dadosInput e dizemos que ela é do tipo ArrayCollection. Note a ponte vírgula indicando que nossa declaração acabou. Outro ponto importante é indicar, através do meta-dado [Bindable] que nossa variável logo abaixo do mesmo poderá ser utilizada com binding para que seu valor seja atribuida automaticamente em tempo de execução para outros componentes.
Agora que temos a variável que guardará nossos dados podemos dentro do método resultHandler especificar que o resultado oriundo da requisição do HTTPService será guardado nesta variável.
1 | dadosInput = new ArrayCollection(event.result.portos.porto); |
Uma das propriedades do evento do tipo ResultEvent é o result, e ele contém o resultado da requisição feita (event.result, portanto). E nosso arquivo XML (o nosso event.result) contém a propriedade portos, e dentro de portos temos um “Array” de . A partir desse elemento nós vamos utilizar a classe ArrayCollection para construir um objeto do tipo ArrayCollection (a variável dadosInput, que criamos anteriormente).
Por fim, vamos dizer para nosso DataGrid que a propriedade dataProvider (o elemento que contém os dados a serem mostrados) é a nossa variável dadosInput, utilizando a característica de databinding, identificada por chaves:
1 | dataProvider="{dadosInput}" |
Nosso código portanto está o seguinte:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | <mx:Application xmlns:mx="http://www.macromedia.com/2005/mxml" creationComplete="initApp();" > <mx:Script> import mx.collections.ArrayCollection; import mx.rpc.events.*; [Bindable] public var dadosInput:ArrayCollection; private function initApp():void { service.send(); } private function resultHandler(event:ResultEvent):void { dadosInput = new ArrayCollection(event.result.portos.porto); } </mx:Script> <mx:HTTPService id="service" url="dados.xml" result="resultHandler(event)" /> <mx:Panel title="Análise" width="100%" height="100%"> <mx:DataGrid dataProvider="{dadosInput}" width="100%" height="100%"> <mx:columns> <mx:DataGridColumn columnName="nome" headerText="Porto" /> <mx:DataGridColumn columnName="prev" headerText="Previsto" /> <mx:DataGridColumn columnName="real" headerText="Realizado" /> <mx:DataGridColumn columnName="dif" headerText="Diferença" /> </mx:columns> </mx:DataGrid> </mx:Panel> </mx:Application> |
E executando teremos o seguinte resultado, com os dados sendo lidos corretamento do arquivo XML, e populando os dados no DataGrid automáticamente via binding.

DataGrid populado com dados do XML, dentro de um Panel
Adicionando o espaço para o gráfico
Em nosso exemplo há um conjunto de botões que define qual o modo de visualização atual: gráfico ou em tabela, ou seja, ambos nunca aparecerão ao mesmo tempo. O Flex oferece um componente chamado de ViewStack para empilhamento de telas, de modo que possamos escolher qual das telas da pilha nós queremos mostrar naquele momento. Em nosso caso, o gráfico ou a tabela.
Dentro do Panel criaremos um ViewStack, ocupando o máximo espaço disponível e identificando, para que futuramente possamos alternar entre as telas.
1 2 3 | <mx:ViewStack id="vsAnalise" width="100%" height="100%"> </mx:ViewStack> |
Aqui há um ponto bem importante: o DataGrid por si só não é um Container, e sim um Controle (na documentação fica evidente pelo pacote ActionScript que o contém, o mx.controls, não o mx.containers), e o ViewStack apenas aceita containers como tags filhas, de modo que teremos que envolver nosso DataGrid em um container:
1 2 3 4 5 6 7 8 9 | <mx:ViewStack id="vsAnalise" width="100%" height="100%"> <mx:VBox label="Tabela" width="100%" height="100%"> <mx:DataGrid......> </mx:VBox> </mx:ViewStack> |
VBox é um container simples, cujos componentes internos estarão alinhados verticalmente, um sob o outro. Notem que eu identifiquei o container que contém o DataGrid com um label. Este será útil posteriormente. Igualmente o componente de gráfico também não é um container, então vamos criar o container que o conterá. O código abaixo o que está dentro do Panel.
1 2 3 4 5 6 7 8 9 10 11 12 13 | <mx:ViewStack id="vsAnalise" width="100%" height="100%"> <mx:VBox label="Gráfico" width="100%" height="100%"> </mx:VBox> <mx:VBox label="Tabela" width="100%" height="100%"> <mx:DataGrid......> </mx:VBox> </mx:ViewStack> |
Agora vamos criar um conjunto de botões que nos permita alternar entre o “stack” gráfico ou o stack “tabela” (de nosso ViewStack chamado vsAnalise).
Logo antes de fechar o Panel, vamos adicionar o seguinte código:
1 2 3 | <mx:ControlBar> <mx:ToggleButtonBar dataProvider="{vsAnalise}" /> </mx:ControlBar> |
O ControlBar é um container que funciona como um rodapé do Panel, e dentro dele nós criarmos um ToogleButtonBar, um componente que de botões alternados: se um está pressionado (e ativo), os depois estarão em seu estado normal. Notem que a propriedade dataProvider – a fonte de dados desse componente – está setada via binding para nosso ViewStack! O componente automaticamente identifica quantos e quais os filhos do vsAnalise para gerar tantos botões quanto necessário, identificando-os através da propriedade label, configurada anteriormente, nos VBox.
Teremos portanto dois botões no rodapé de nosso painel, que serão úteis para alternar as visões entre o gráfico e a tabela.
Adicionando o gráfico de pizza
Vamos criar um gráfico de colunas, utilizando o componente ColumnChart. Notem que, assim como no DataGrid, em que a propriedade (iniciada com letra minúscula) columns era um conjunto de DataGridColumns, o ColumnChart contém a propriedade series que é um conjunto de ColumnSeries.
Nós passamos para o ColumnChart qual a origem dos dados a serem visualizados, e novamente configuramos seu tamanho para o máximo disponível.
1 2 3 4 5 6 7 | <mx:ColumnChart dataProvider="{dadosInput}" width="100%" height="100%"> <mx:series> <mx:ColumnSeries yField="prev" displayName="Previsto"/> <mx:ColumnSeries yField="real" displayName="Realizado"/> <mx:ColumnSeries yField="dif" displayName="Diferença"/> </mx:series> </mx:ColumnChart> |
Nós aqui adicionamos três séries – três colunas portanto, e especificamos a coluna que representará os valores do eixo y (através da propriedade yField), que é o mesmo que nosso columnName no DataGrid, bem como demos um nome para esta série.
Se esse código for executado, será fácil perceber que o gráfico não está completo. Afinal, não está claro o quê cada conjunto que aparecerá de três séries representa, já que não específicamos o que temos em nosso eixo x, nosso eixo horizontal. Dentro do gráfico vamos adicionar o seguinte:
1 2 3 | <mx:horizontalAxis> <mx:CategoryAxis dataProvider="{dadosInput}" categoryField="nome"/> </mx:horizontalAxis> |
Dessa forma indicamos ao gráfico como é formado o eixo horizontal, com uma fonte de dados, normalmente a mesma do gráfico em si (como em nosso exemplo), e indicando o campo que contém os nomes desse eixo.
Executando agora temos nosso exemplo completo:

O código completo é:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.macromedia.com/2005/mxml" creationComplete="initApp();" > <mx:Script> import mx.collections.ArrayCollection; import mx.rpc.events.*; [Bindable] public var dadosInput:ArrayCollection; private function initApp():void { service.send(); } private function resultHandler(event:ResultEvent):void { dadosInput = new ArrayCollection(event.result.portos.porto); } </mx:Script> <mx:HTTPService id="service" url="dados.xml" result="resultHandler(event)" /> <mx:Panel title="Análise" width="100%" height="100%"> <mx:ViewStack id="vsAnalise" width="100%" height="100%"> <mx:VBox label="Gráfico" width="100%" height="100%"> <mx:ColumnChart dataProvider="{dadosInput}" width="100%" height="100%" showDataTips="true"> <mx:horizontalAxis> <mx:CategoryAxis dataProvider="{dadosInput}" categoryField="nome"/> </mx:horizontalAxis> <mx:series> <mx:ColumnSeries yField="prev" displayName="Previsto"/> <mx:ColumnSeries yField="real" displayName="Realizado"/> <mx:ColumnSeries yField="dif" displayName="Diferença"/> </mx:series> </mx:ColumnChart> </mx:VBox> <mx:VBox label="Tabela" width="100%" height="100%"> <mx:DataGrid dataProvider="{dadosInput}" width="100%" height="100%"> <mx:columns> <mx:DataGridColumn columnName="nome" headerText="Porto" /> <mx:DataGridColumn columnName="prev" headerText="Previsto" /> <mx:DataGridColumn columnName="real" headerText="Realizado" /> <mx:DataGridColumn columnName="dif" headerText="Diferença" /> </mx:columns> </mx:DataGrid> </mx:VBox> </mx:ViewStack> <mx:ControlBar> <mx:ToggleButtonBar dataProvider="{vsAnalise}" /> </mx:ControlBar> </mx:Panel> </mx:Application> |
Conclusão
A construção dessa simples aplicação é um bom ponto de partida para o aprendizado no desenvolvimento em Flex, bem como demonstra algumas sutis mudanças em relação ao Flex 1.5, para desenvolvedores mais experientes.
Essa aplicação, contudo, não deve ser considerada fonte de boas práticas, já que seu maior objetivo é introduzir o desenvolvimento de aplicações em Flex, e é simplista a seu modo para atingir esse objetivo.
Igualmente, não pretende esgotar o assuntos do que foi abordado. Há uma boa documentação da tecnologia e de suas API, que devem ser encaradas como referência obrigatória no desenvolvimento dessas aplicações.

4 comentários
Acabo de entrar aqui e fiquei (positivamente) surpreso com que vi!
Não vejo a hora de arregassar as mangas e botar a mão na massa!!!!
Parabens Fabio, otimo tutorial, tb tenho acompanhado a otimo contribuição que vc tem tem feito para a lista de Flex.
ate mais
Leonardo França
Ola, muito bom o tutorial para aspirantes developer Flex.
Obrigado
[ ]s
Primeiramente, quero parabenizar o Fabio Terracini, pois o tutorial está muito bem elaborado tanto na parte do ensinamento técnico – FLEX, quanto no cuidado em escrever este artigo.
Continue assim.
Abraços
Deixe Seu Comentário