DevSecOps

20 fev, 2009

Criar colunas dinamicamente na DataGrid

Publicidade

O título pode até não ser chamativo, visto que o Adobe Flex cria automaticamente colunas com base em seu dataProvider como no exemplo abaixo.

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()">
<mx:Script>
	<![CDATA[
		[Bindable]
		private var dp:Array = [
			{ symbol: "ADBE", name: "Adobe Systems Inc.", price1: 49.95, price2: 49.95, price3: 49.95, price4: 49.95, price5: 49.95 },
			{ symbol: "MACR", name: "Macromedia Inc.", price1: 49.95, price2: 49.95, price3: 49.95, price4: 49.95, price5: 49.95 },
			{ symbol: "MSFT", name: "Microsoft Corp.", price1: 49.95, price2: 49.95, price3: 49.95, price4: 49.95, price5: 49.95 },
			{ symbol: "IBM", name: "IBM Corp.", price1: 49.95, price2: 49.95, price3: 49.95, price4: 49.95, price5: 49.95 },
			{ symbol: "ADBE", name: "Adobe Systems Inc.", price1: 49.95, price2: 49.95, price3: 49.95, price4: 49.95, price5: 49.95 },
			{ symbol: "MACR", name: "Macromedia Inc.", price1: 49.95, price2: 49.95, price3: 49.95, price4: 49.95, price5: 49.95 }
			];
 
		private function init():void
		{
			dgDado.dataProvider = dp;
		}
	]]>
</mx:Script>
<mx:DataGrid id="dgDado" />
</mx:Application>

Ou seja, de uma maneira bem simples, temos uma DataGrid com as colunas criadas automaticamente em tempo de execução com o seguinte resultado:

Mas perceba que o resultado obtido não é dos melhores, pois todas as colunas estão com o mesmo tamanho, as células com valores não possuem formatação, em fim, não tem qualquer personalização.

O meu propósito com esse post é compartilhar com você, como criar colunas de uma DataGrid de forma dinâmica com base no DataProvider.

Essa funcionalidade se aplica muito bem em relatórios onde o retorno do Banco de Dados é gerado dinâmicamente através de Stored Procedures, ou seja, as colunas retornadas da base dados são desconhecidas.

Então para isso iremos criar uma função que receberá um objeto, que retornou do banco, e através da função ObjectUtil.getClassInfo serão capturadas as propriedades de objeto. Cada propriedade, será uma coluna da DataGrid.

Após capturar as propriedades, é preciso somente dar um loop em torno de todas elas e criar uma coluna específica para cada propriedade. Assim, é possível personalizar cada coluna com base em seu nome, como por exemplo:

  • A coluna “name” deixaremos com a largura de 200 pixel, as outras colunas ficarão com 80 pixel de largura;
  • Caso o nome da coluna comece com “price“, será aplicada a formatação de moeda através do CurrencyFormatter.

Com isso, nosso resultado final será como a figura abaixo:

Um pouco melhor que a configuração padrão do Flex, não acha?

Então mãos a obra.

Crie as funções criaColuna e formataNumero com base no código.

import mx.controls.dataGridClasses.DataGridColumn;
import mx.utils.ObjectUtil;
 
private function criaColuna(objTemp:Object):void
{
    //Cria um vetor de colunas
    var colunas:Array = new Array();
 
    //Retorna as propriedades do objeto objTemp[0] para o Objeto properties
    var properties:Object = ObjectUtil.getClassInfo(objTemp[0]);	
 
    //Da um loop para cada propriedade do objeto properties
    for each (var property:Object in properties.properties)
    {
	//Cria uma nova DataGridColumn						
	var coluna:DataGridColumn  = new DataGridColumn();
 
	coluna.headerText = property.toString();	    		
	coluna.width = (property.toString() == 'name') ? 200 : 80;
	coluna.resizable = false;
	coluna.dataField = property.toString();
	if (property.toString().substr(0,5) == 'price')
		coluna.labelFunction = formataNumero;
	colunas.push(coluna); //Inclui a nova coluna ao vetor de colunas
    }
	dgDado.columns = colunas;
}
 
private function formataNumero(item:Object, column:DataGridColumn):String {	
	return formataMoeda.format(item[column.dataField]);
}

Agora declare o CurrencyFormatter, antes da declaração da DataGrid.

<mx:CurrencyFormatter id="formataMoeda" precision="2" currencySymbol="R$ " decimalSeparatorTo="," thousandsSeparatorTo="." useNegativeSign="true" useThousandsSeparator="true" alignSymbol="left"/>

E para finalizar, na função init(), chame a função criaColuna passando o vetor dp como parâmetro.

private function init():void
{
	criaColuna(dp);
	dgDado.dataProvider = dp;
}

Pronto, sua DataGrid criará as colunas dinamicamente de forma customizada.

Veja o código completo abaixo.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()">
<mx:Script>
	<![CDATA[
		import mx.controls.dataGridClasses.DataGridColumn;
		import mx.utils.ObjectUtil;
 
		[Bindable]
		private var dp:Array = [
			{ symbol: "ADBE", name: "Adobe Systems Inc.", price1: 49.95, price2: 49.95, price3: 49.95, price4: 49.95, price5: 49.95 },
			{ symbol: "MACR", name: "Macromedia Inc.", price1: 49.95, price2: 49.95, price3: 49.95, price4: 49.95, price5: 49.95 },
			{ symbol: "MSFT", name: "Microsoft Corp.", price1: 49.95, price2: 49.95, price3: 49.95, price4: 49.95, price5: 49.95 },
			{ symbol: "IBM", name: "IBM Corp.", price1: 49.95, price2: 49.95, price3: 49.95, price4: 49.95, price5: 49.95 },
			{ symbol: "ADBE", name: "Adobe Systems Inc.", price1: 49.95, price2: 49.95, price3: 49.95, price4: 49.95, price5: 49.95 },
			{ symbol: "MACR", name: "Macromedia Inc.", price1: 49.95, price2: 49.95, price3: 49.95, price4: 49.95, price5: 49.95 }
			];
 
		private function init():void
		{
			criaColuna(dp);
			dgDado.dataProvider = dp;
		}
 
		private function criaColuna(objTemp:Object):void
		{
			//Cria um vetor de colunas
			var colunas:Array = new Array();
 
			//Retorna as propriedades do objeto objTemp[0] para o Objeto properties
		    var properties:Object = ObjectUtil.getClassInfo(objTemp[0]);	
 
			//Da um loop para cada propriedade do objeto properties
		    for each (var property:Object in properties.properties)
		    {
				//Cria uma nova DataGridColumn						
				var coluna:DataGridColumn  = new DataGridColumn();
 
	    		coluna.headerText = property.toString();	    		
	    		coluna.width = (property.toString() == 'name') ? 200 : 80;
	    		coluna.resizable = false;
	    		coluna.dataField = property.toString();
	    		if (property.toString().substr(0,5) == 'price')
	    			coluna.labelFunction = formataNumero;
				colunas.push(coluna); //Inclui a nova coluna ao vetor de colunas
		    }
			dgDado.columns = colunas;
		}
 
		private function formataNumero(item:Object, column:DataGridColumn):String {	
			return formataMoeda.format(item[column.dataField]);
		}
 
	]]>
</mx:Script>
<mx:CurrencyFormatter id="formataMoeda" precision="2" currencySymbol="R$ " decimalSeparatorTo="," thousandsSeparatorTo="." useNegativeSign="true" useThousandsSeparator="true" alignSymbol="left"/>
<mx:DataGrid id="dgDado" />
</mx:Application>

Divirta-se!

Postado originalmente em Igor Musardo