ClientDataSet - dececando aggregates

Top  Previous  Next

// power ClientDataSet <--- despido, desvendado, aniquilado

 

// para todos os exemplo crie este programa:

 

1 ClientDataSet (Tb)

1 DataSource    (Ds)

1 DBGrid        (Grid)

 

object Form1: TForm1

  object Grid: TDBGrid

    DataSource = Ds

  end

  object Tb: TClientDataSet

    Active = True

    FieldDefs = <

      item

        Name = 'Cidade'

        DataType = ftString

        Size = 20

      end

      item

        Name = 'Nome'

        DataType = ftString

        Size = 20

      end

      item

        Name = 'Vendas'

        DataType = ftFloat

      end>

    IndexDefs = <

      item

        Name = 'ICidade'

        Fields = 'Cidade; Nome'

      end>

    IndexName = 'ICidade'

    object TbCidade: TStringField

      FieldName = 'Cidade'

    end

    object TbNome: TStringField

      FieldName = 'Nome'

    end

    object TbVendas: TFloatField

      FieldName = 'Vendas'

    end

  end

  object Ds: TDataSource

    DataSet = Tb

  end

end

 

//// Codigo fonte:

 

procedure TForm1.FormCreate(Sender: TObject);

begin

  if FileExists('c:\arq.xml') then Tb.LoadFromFile('c:\arq.xml');

end;

 

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);

begin

  Tb.SaveToFile('c:\arq.xml');

end;

 

*************************************************************************

Outra obs do junior: praticamente voce precisa de 1 item dentro

de Tb.Aggregates para cada quebra.

 

1 campo dentro do Field do tipo TAggregateField para calculos.

 

*************************************************************************

 

 

// "popule" o cliente com dados de algumas cidades, nomes e valores

// repita o nome da cidade e o nome algumas vezes...

 

*************************************************************************

************ Como fazer uma quebra sem somas          *******************

*************************************************************************

 

             CRICIUMA

                       JOAO

                           ANTONIO

                  ICARA

                       MARIA 

                           PEDRO

                           ANTONIO

 

1. Basta criar um indice pelo campo que será a quebra

   e coloque o grouplevel do indice para 1

   

2. Se quiser ver o resultado numa grid basta colocar este código

   no onGetText do campo cidade:

 

   if gbFirst in Tb.GetGroupState(1) then

     Text := TStringField(Sender).asString

   else

     Text := '';

    

3. Tb.AggregatesActive = True

 

*************************************************************************

************ Como fazer um somatório geral que ficará *******************

************ abaixo da grid                           *******************

*************************************************************************

 

                  JOAO ................... 10,00

                  ANTONIO ..................4,40

                  MARIA ....................2,20

                  TOTAL -----------------> 16,60

 

1. Crie um novo campo no FieldsEditor de nome TOTAL do tipo AGGREGATE

   (selecione Aggregate no radiogroup)

   

2. Nas propriedades do field coloque:

   Expression = 'sum(vendas)'

   Active     = True

 

3. No ClientDataSet coloque AggregatesActive = True

 

4. Coloque um DBText na tela e associe com este campo.

 

PS. Se quiser que o campo apareca na grid basta colocá-lo como Visible = True

 

*************************************************************************

************ Fazer um relatorio com quebra por um campo ***************** 

*************************************************************************

 

                 CRICIUMA

                    OBI WAN ................. 1,01

                    QUIM GON ................ 2,40

                 

                 FLORIPA

                    FRODO ................... 4,00

                    LANCELOT ................ 3,00

                    SHREK ................... 1,99

                 

                 ICARA

                    ANAKIN ................. 10,00

                 

Voce pode determinar a posicao relatorio de um registro dentro de 

um agregado chamando o metodo GetGroupState do dataset. GetGroupState

retorna um valor de gbFirst, gbLast, gbMiddle.

 

Para tal, voce precisar criar um indice pelo campo que quer

fazer a quebra

 

1. coloque um TMemo no exemplo com font COURIER NEW

 

2. No Aggrate Total coloque na propriedade

 

   IndexName = 'ICidade'

   GroupLevel = 1

 

3. coloque um botao e no click adicione:

 

   Tb.First;

   while not Tb.EOF do

   begin

     if gbFirst in Tb.GetGroupState(1) then Memo1.Lines.Add(TbCidade.asString);

     Memo1.Lines.Add('   ' + AlinhaEsq(TbNome.asString, 20) + AlinhaDir(TbVendas.asFloat, 10));

     Tb.Next;

   end;

 

o grouplevel diz para o dataset que deve utilizar apenas a primeira parte do

indice (no nosso exemplo nosso indice é por cidade e nome.) assim

a cada "mudanca" no campo cidade o cliente ativa a flag gbFirst para

Group(1)

 

 

*************************************************************************

***************** Fazer somatorios pela quebra **************************

*************************************************************************

 

                 CRICIUMA

                    OBI WAN ................. 1,01

                    QUIM GON ................ 2,40

                 subtotal.................... 3,41

                 

                 FLORIPA

                    FRODO ................... 4,00

                    LANCELOT ................ 3,00

                    SHREK ................... 1,99

                 sutotal .................... 8,99

                 

                 ICARA

                    ANAKIN ................. 10,00

                 subtotal .................. 10,00

                 

                 TOTALGERAL ................ 22,40

 

Basta usar o agregado que já criamos e adicionar esta linha ANTES do NEXT:

 

if gbLast in Tb.GetGroupState(1) then Memo1.Lines.Add('   ' + AlinhaDir(TbTotal.Value, 30));

 

Agora para colocar o valor total de todos os registros é necessário

criar um novo agregate:

 

    TbTotalGeral: TAggregateField;

      FieldName = 'TotalGeral'

      Active = True

      Expression = 'sum(Vendas)'

 

Após o End do While coloque:

 

Memo1.Lines.Add('   ' + AlinhaDir(TbTotalGeral.Value, 30));

 

 

*************************************************************************

*************** Fazer sub-grupo 2 niveis de quebra e soma  **************

*************************************************************************

 

                      CRICIUMA

                        OBI WAN

                        ....           1,01

                        ....           2,00

                        subtotal:      3,01

                      

                        QUIM GON

                        ....           2,40

                        subtotal:      2,40

                      

                      TOTAL Cidade:    5,41

                      ----------------------------

                      FLORIPA

                        FRODO

                        ....           4,00

                        ....           2,99

                        ....           0,50

                        subtotal:      7,49

                      

                        LANCELOT

                        ....           3,00

                        ....           2,20

                        subtotal:      5,20

                      

                        SHREK

                        ....           1,99

                        subtotal:      1,99

                      

                      TOTAL Cidade:   14,68

                      ----------------------------

                      TOTAL GERAL:     30,09

 

 

Basta criar apenas mais 1 aggregate, 

 

    TbTotalNome: TAggregateField

      FieldName = 'TotalNome'

      Active = True

      Expression = 'sum(Vendas)'

      IndexName = 'ICidade'

      GroupingLevel = 2  // usa a 2 parte do índice (o indice é composto)

 

modifique o código fonte do botão imprimir para isto:

 

  Tb.First;

  while not Tb.EOF do

  begin

    // cabeçalho de quebra por cidade

    if gbFirst in Tb.GetGroupState(1) then

      Memo1.Lines.Add(TbCidade.asString);

 

    // cabeçalho de quebra por nome (note o grouplevel [2])

    if gbFirst in Tb.GetGroupState(2) then

      Memo1.Lines.Add('  ' + TbNome.asString);

 

    // cada registro é impresso aqui (detalhe)

    Memo1.Lines.Add('  ....' + AlinhaDir(TbVendas.asFloat, 15));

 

    // subtotal por nome

    if gbLast in Tb.GetGroupState(2) then

    begin

      Memo1.Lines.Add('  subtotal:' + AlinhaDir(TbTotalNome.Value, 10));

      Memo1.Lines.Add('');

    end;

 

    // subtotal por cidade

    if gbLast in Tb.GetGroupState(1) then

    begin

      Memo1.Lines.Add('TOTAL Cidade:' + AlinhaDir(TbTotal.Value, 8));

      Memo1.Lines.Add('----------------------------');

    end;

 

    Tb.Next;

  end;

  // total geral

  Memo1.Lines.Add('');

  Memo1.Lines.Add('TOTAL GERAL:' + AlinhaDir(TbTotalGeral.Value, 10));

 

  // assim sucessivamente, tecnicamente nao existe limite do numero

  // de quebras que se pode fazer.

  

 ******************* Well done *********************