Gerando Relatórios Dinâmicos usando QuickRep

 

Neste Artigo o objetivo é criar uma aplicação onde é possível gerar relatórios no QuickRep que o próprio usuário possa escolher os campos desejados e sua ordem de impressão. Vamos utilizar um tabela Funcionarios do tipo Dbase IV com a seguinte estrutura:

Report1.gif 

Figura 1.

Obs: Este exemplo pode ser utilizado com qualquer banco de dados.

Crie uma Aplicação Delphi e adicione um Data Module com o Nome = Dm. No Data Module coloque um componente Query (paleta BDE). Em DataBaseName coloque o alias ou caminho onde se encontra nossa tabela, no meu caso ficará assim: DataBaseName = C:\Artigo.

Report2.gif 

Figura 2.

Pré-configurando o Relatório

Como nosso objetivo é utilizar o QuickRep vamos deixar algumas coisas pré-configuradas, para isso adicione um novo Form ao Projeto com Name = FrmRelatorios. Coloque nesse formulário um QuickRep (paleta QReport), em Bands ative HasColumnHeader, HasDetail e HasPageHeader. No Detail e ColumnHeader mude a propriedade Heigth para 20.

Report3.gif 

Figura 3.

No Page Header vamos colocar um dois QrLabel e dois QrSysData mude suas propriedades conforme mostrado abaixo:

QrLabel1

Caption = Gerador de Relatórios

Top = 2

Left = 4

QrLabel2

 

Top = 21

Left = 4

QrSysData1

 

Top = 2

Alignment = taRightJustify

AlignToBand = True

Data = qrsPageNumber

Text = Pagina:

QrSysData2

 

Top = 2

Alignment = taRightJustify

AlignToBand = True

Data = qrsDate

Text = Data:

 

Ainda no Page Header na propriedade Frame Ative DrawBottom, DrawLeft, DrawTop, DrawRigth. Com isso seu QuickRep deve esta com mostrado abaixo.

 report4.gif

Figura 4.

Obs: O QRLabel2 será usado para o Titulo do Relatório.

Coloque na sessão USES a unit do Data Module e na propriedade DataSet do QuickRep coloque Dm.Query1.

Criando o Editor de Relatórios

Volte para o formulário principal, mude seu nome para FrmMenu, coloque no formulário um componente PageControl (paleta Win32). Crie duas paginas “Definindo Campos” e “Ordenando”.

Report5.gif 

Figura 5.

Na Pagina “Definindo Campos” coloque os Componentes: dois Listbox, três Label (ambos da paleta Standard), 4 SpeedButton (Paleta Additional). Organize conforme mostrado abaixo:

Report6.gif 

Figura 6.

Na pagina “Ordenando” coloque um Label (paleta Standard), um CheckListbox e dois SpeedButton (ambos da paleta Additional). Organize conforme abaixo:

Report7.gif 

Figura 7.

Para facilitar nosso trabalho vamos mudar os nomes dos SpeedButton:

SpeedButton1 = IncluirCampo

SpeedButton2 = RemoverCampo

SpeedButton3 = CampoUp

SpeedButton4 = CampoDown

SpeedButton5 = OrdemUp

SpeedButton6 = OrdemDown

No formulário logo abaixo ao PageControl coloque um Label, um Edit e um BitBtn e Organize conforme abaixo:

Report8.gif 

Figura 8.

Mude o nome do BitBtn1 para Gerar. Agora vamos declarar na sessão Public as variáveis abaixo:

 

public

  { Public declarations }

  Pagina:Integer;

  QrLabel:array[1..8] of TQrLabel;

  QrDbText:array[1..8] of TQrDbtext;

  Desc,Campo:array[1..8] of String;

  Largura:Array[1..8] of Integer;

end;

 

Observe que estamos criamos dois array de 8 posições (Nº Maximo de Campos da Tabela) do tipo TQrLabel e TQrDbText. Os QrLabel são os componentes que mostraram as descrições das colunas nos relatórios e os QrDbText são os componentes que mostraram as informações de cada coluna. Assim temos que incluir a QRCtrls na sessão USES.

O Array DESC terá os títulos de cada coluna, o CAMPO o nome dos campos que se deseja usar da tabela e LARGURA aguardará a largura de cada coluna. A variável PAGINA terá a quantidade de caracteres utilizados na pagina, com isso podemos definir se o relatório será impresso em PAISAGEM ou RETRATO.

Vamos até o evento OnCreate do formulário para definirmos os valores dos array e os itens de seleção (ListBox e CheckListBox). Digite o código abaixo:

 

procedure TFrmMenu.FormCreate(Sender: TObject);

var

 i:integer;

begin

 // Matriz com Nome de Campo da Tabela

 Campo[1] := 'CODIGO';

 Campo[2] := 'NOME';

 Campo[3] := 'ENDERECO';

 Campo[4] := 'BAIRRO';

 Campo[5] := 'CIDADE';

 Campo[6] := 'UF';

 Campo[7] := 'SALARIO';

 Campo[8] := 'CARGO';

 // Matriz Com Descrição das Colunas do Relatório

 Desc[1] := 'Nº Código';

 Desc[2] := 'Nome';

 Desc[3] := 'Endereço';

 Desc[4] := 'Bairro';

 Desc[5] := 'Cidade';

 Desc[6] := 'UF';

 Desc[7] := 'Salário';

 Desc[8] := 'Cargo';

 // Matriz Com a Largura das Colunas

 Largura[1] := 9;

 Largura[2] := 40;

 Largura[3] := 40;

 Largura[4] := 20;

 Largura[5] := 20;

 Largura[6] := 2;

 Largura[7] := 10;

 Largura[8] := 15;

 // Colocamos as Descrições dos Campos para Seleção no Listbox e CheckListbox

 for i := 1 to 8 do

   begin

    CheckListBox1.Items.Add(Desc[i]);

    ListBox1.Items.Add(Desc[i]);

   end;

 

end;

 

Obs: O Array Largura deve conter o tamanho que se deseja para cada coluna do relatório, podendo ser o mesmo tamanho os campos na tabela ou tamanhos pré-definidos.

Agora vamos criar a função PosCampo que retornará a posição dentro dos arrays dos campos selecionados.

 

function TFrmMenu.PosCampo(Campo:String):Integer;

var

 i:integer;

begin

 for i := 1 to 8 do

   begin

   if Campo = Desc[i] then

     begin

       Result := i;

       Break;

     end;

   end;

end;

 

Obs: não esquece de declara a função na sessão public ou private.

Agora vamos colocar o código para a escolha dos campos nos relatórios. Vá até o evento OnClick do botão IncluirCampo e digite o código abaixo:

 

// Verificamos se existem itens

if Listbox1.ItemIndex >= 0 then

  begin

   // Verificamos se o nº de caracteres do campo não ultrapassa o total da pagina

   if Pagina + Largura[PosCampo(Listbox1.Items.Strings[ListBox1.ItemIndex])] > 125 then

       ShowMessage('Campo Supera o Tamanho da Pagina')

    else

      begin

        // Adiciona o Campo escolhido na lista de seleção

        Pagina :=  Pagina + Largura[PosCampo(Listbox1.Items.Strings[ListBox1.ItemIndex])];

        ListBox2.Items.Add(ListBox1.Items.Strings[ListBox1.ItemIndex]);

        ListBox1.Items.Delete(ListBox1.ItemIndex);

      end;

  end;

Obs: Estamos definindo 125 como o total de caracteres para o tamanho do papel em paisagem e 94 em retrato.

Digite agora o código do botão RemoverCampo.

 

if Listbox2.ItemIndex >= 0 then

  begin

     Pagina :=  Pagina - Largura[PosCampo(Listbox2.Items.Strings[ListBox2.ItemIndex])];

     ListBox1.Items.Add(ListBox2.Items.Strings[ListBox2.ItemIndex]);

     ListBox2.Items.Delete(ListBox2.ItemIndex);

  end;

 

Digitando os código dos botões de Organização.

Botão CampoUp.

 

var

 i: integer;

begin

 if Listbox2.ItemIndex > 0 then

  begin

    i := ListBox2.ItemIndex;

    ListBox2.Items.Move(i,i-1);

    ListBox2.ItemIndex := i-1;

  end;

end;

 

Botão CampoDown.

var

 i:integer;

begin

 if Listbox2.ItemIndex < ListBox2.Items.Count - 1  then

  begin

    i := ListBox2.ItemIndex;

    ListBox2.Items.Move(i,i+1);

    ListBox2.ItemIndex := i+1;

  end;

end;

 

Botão OrdemUp.

var

 i:integer;

begin

 if CheckListbox1.ItemIndex > 0 then

  begin

    i := CheckListBox1.ItemIndex;

    CheckListBox1.Items.Move(i,i-1);

    CheckListBox1.ItemIndex := i-1;

  end;

end;

 

Botão OrdemDown.

var

 i:integer;

begin

 if CheckListbox1.ItemIndex < CheckListBox1.Items.Count - 1  then

  begin

    i := CheckListBox1.ItemIndex;

    CheckListBox1.Items.Move(i,i+1);

    CheckListBox1.ItemIndex := i+1;

  end;

end;

 

Agora é a parte mais importante para a nossa aplicação o código do botão Gerar.

procedure TFrmMenu.BtnGerarClick(Sender: TObject);

var

 i, Col, Tamc:integer;

 NCampo,Ordem:String;

begin

 

//Verificamos se existem Campos Selecionados

 if Listbox2.Items.Count > 0 then

 begin

 

// Posição inicial da coluna

 Col := 5;

 

 // Informamos o Titulo do Relatório

 Form2.QRLabel2.Caption := Edit1.Text;

 

 for i := 0 to listbox2.Items.Count -1 do

   begin

 

     //Obtendo o Tamanho e Nome do Campo

     Tamc   := Largura[PosCampo(ListBox2.Items.Strings[i])] ;

     NCampo := Campo[PosCampo(ListBox2.Items.Strings[i])];

 

     //Criando Componentes Para os Títulos das Colunas

     QrLabel[i+1] := TQrLabel.Create(Form2.QuickRep1.Bands.ColumnHeaderBand);

     QrLabel[i+1].Parent     := Form2.QuickRep1.Bands.ColumnHeaderBand;

     QrLabel[i+1].Left       := Col;

     QrLabel[i+1].Top        := 4;

     QrLabel[i+1].Caption    := ListBox2.Items.Strings[i];

     QrLabel[i+1].Font.Style := [fsunderline,fsbold];

 

     //Criando Componentes de Exibição de Dados das Colunas

     QrDbtext[i+1] := TQrDbtext.Create(FrmRelatorios.QuickRep1.Bands.DetailBand);

     QrDbText[i+1].Parent    :=  Form2.QuickRep1.Bands.DetailBand;

     QrDbText[i+1].Left       := Col;

     QrDbText[i+1].Top        := 8;

     QrDbText[i+1].DataSet   := Dm.Query1;

     QrDbText[i+1].DataField := NCampo;

 

     //Obtendo o Valor da próxima Coluna. Como o valor precisa ser em pixel multiplicamos por

    //  5 o tamanho do Campo.

     Col := Col + (5 * Tamc);

 

     // Alinhamos a direita o Campo Salario

     if NCampo = 'SALARIO' then

       begin

         QrDbText[i+1].AutoSize  := False;

         QrDbText[i+1].Alignment := taRightJustify;

       end;

   end;

 

 // Criando Ordenação

 Ordem := '';

 for i := 0 to CheckListBox1.Items.Count - 1 do

   begin

    if CheckListBox1.Checked[i] = True then

       begin

         if Ordem = '' then

            Ordem := Ordem +' Order by ' + Campo[PosCampo(CheckListBox1.Items.Strings[i])]

          else

            Ordem := Ordem +' , ' + Campo[PosCampo(CheckListBox1.Items.Strings[i])];

       end;

   end;

 

//Passamos as instruções SQL

 Dm.Query1.Close;

 Dm.Query1.SQL.Clear;

 Dm.Query1.SQL.Add('select * from funcionarios.dbf');

 if Ordem <> '' then

    Dm.Query1.SQL.Add(Ordem);

 

 Dm.Query1.Open;

 

 //Chamamos o Relatório

 FrmRelatorios.QuickRep1.Preview;

 

 //Liberamos os Componentes utilizados

 for i := 0 to listbox2.Items.Count -1 do

    begin

     QrLabel[i+1].free;

     QrDbText[i+1].free;

    end;

 end;

end;

 

Agora precisamos definir se o relatório será impresso em paisagem ou retrato. Para isso vamos até o formulário FrmRelatorios e no evento OnBeforePrint do QuickRep digite o código abaixo:

 

if FrmMenu.Pagina <= 94 then

  QuickRep1.Page.Orientation := poPortrait

else

  QuickRep1.Page.Orientation := poLandscape;

 

Inclua a PRINTERS na sessão USES. Pronto agora é só fazer alguns testes.

Selecionado Campos

Report9.gif

Figura 9.

Ordenando Por Salário

Report10.gif

Figura 10.

Visualizando Relatório

Report11.gifFigura 11.

Conclusão

Mostrei aqui uma forma de como desenvolver um gerador de relatórios onde o próprio usuário pode escolher os dados desejados acredito que seja muito útil em diversas aplicações. Abraços T+

 

Walbert Castro (walbertsc@hotmail.com) Coordenador de Informática Revenda Ambev do Amapá.