Esse artigo faz parte da revista Clube Delphi edição 12. Clique aqui para ler todos os artigos desta edição



Atenção: por essa edição ser muito antiga não há arquivo PDF para download. Os artigos dessa edição estão disponíveis somente através do formato HTML.

Relatório com Múltiplas Quebras

 

         Na minha opinião, o QuickReport é uma ferramenta excelente para a criação de relatórios com o Delphi. Considero-o bastante poderoso devido a sua flexibilidade na manipulação de eventos e componentes. Porém, muitos usuários, por desconhecerem o funcionamento da ferramenta, se contentam com relatórios sem muita complexidade ou se rendem as famosas "marretas" para forçar um determinado resultado.  Este tipo de técnica (?), na maioria dos casos, pode ser evitada simplesmente alterando algumas propriedades.

         Para exemplificar isso, vamos criar um relatório que, apesar de pequeno, possui uma estrutura que servirá perfeitamente como referência para vários outros relatórios maiores e mais complexos. Nosso relatório abrange conceitos como agrupamentos, múltiplos níveis, subtotais, totais, e possui a seguinte hierarquia:

 

figura1

 

 

Antes de iniciar a construção do relatório, crie as tabelas necessárias para este exemplo, conforme a listagem abaixo:

 

EMPRESA.DB

CodEmpresa   +        *

Nome            A        50

 

FUNCIONARIO.DB

CodFuncionario        +        *

CodEmpresa   I

Nome            A        50

Salário          $

 

FILHO.DB

CodFilho        +        *

CodFuncionario   I   

Nome            A

 

As tabelas se relacionam da seguinte forma:

 

[gráfico]

 

 

Crie um alias para o diretório no qual as tabelas foram salvas, nomeando-o qrExemplo. Vamos agora iniciar a construção do relatório:

 

         Em um novo formulário do QR insira dois objetos  TQuery (palheta data access), quatro objetos TQRBand (palheta QReport), um objeto TQRGroup (palheta QReport) e um objeto TQRSubDetail. Configure suas propriedades conforme a listagem a seguir:

 

Query1

DatabaseName         QRExemplo

SQL              select

                   empresa.codempresa, empresa.nome as nomeempresa,

                   funcionario.codfuncionario, funcionario.nome as nomefuncionario,

                   funcionario.salario

                   from empresa, funcionario

                   where funcionario.codempresa = empresa.codempresa

                   order by nomeempresa, nomefuncionario

 

Query2

DatabaseName         QRExemplo

SQL              select nome

                   from filho

                   where codfuncionario = :MCodFunc

                   order by nome

 

Nota: É importante definir o tipo do parâmetro (MCodFunc) declarado na query acima, que será Integer (ftInteger). Para isto, clique na propriedade Params, selecione o item McodFunc e altere a propriedade

DataType.

 

QuickReport

DataSet        Query1

ReportTitle    Relação de Empresa/Funcionário/Dependente

 

QRBand1

BandType      rbPageHeader

Height          32

Frame.DrawTop                 TRUE

Frame.DrawLeft                 TRUE

Frame.DrawRight               TRUE

Frame.DrawBottom   TRUE

 

QRBand2

BandType      rbDetail

HasChild        True

Height          17

Frame.DrawTop                 TRUE

Frame.DrawLeft                 TRUE

Frame.DrawRight               TRUE

Frame.DrawBottom   FALSE

 

ChildBand1

Frame.DrawTop                 FALSE

Frame.DrawLeft                 TRUE

Frame.DrawRight               TRUE

Frame.DrawBottom   FALSE

 

 

QRBand3

BandType      rbGroupFooter

Color            $00DFDFDF

HasChild        True

Height          17

Frame.DrawTop                 TRUE

Frame.DrawLeft                 TRUE

Frame.DrawRight               TRUE

Frame.DrawBottom   TRUE

 

ChildBand2

Frame.DrawTop                 TRUE

Frame.DrawLeft                 TRUE

Frame.DrawRight               TRUE

Frame.DrawBottom   TRUE

 

 

QRBand4

BandType      rbSummary

Height          32

Frame.DrawTop                 TRUE

Frame.DrawLeft                 TRUE

Frame.DrawRight               TRUE

Frame.DrawBottom   FALSE

 

QRGroup1

Color            $00DFDFDF

Expression     Query1.CodEmpresa

FooterBand    QRBand3

Height          22

Frame.DrawTop                 TRUE

Frame.DrawLeft                 TRUE

Frame.DrawRight               TRUE

Frame.DrawBottom   TRUE

 

 

Nota: O QRGroup é a band responsável pela quebra do relatório. Portanto, o valor definido na propriedade Expression é considerado a chave dos agrupamentos.

 

QRSubDetail1

DataSet                           Query2

Height                    14

Frame.DrawTop                 FALSE

Frame.DrawLeft                 TRUE

Frame.DrawRight               TRUE

Frame.DrawBottom   FALSE

 

 

Ao final desta etapa nosso relatório ficará basicamente com o seguinte visual (em tempo de edição):

 

figura2

 

Em seguida, vamos inserir os objetos (todos da palheta QReport) para a exibição dos títulos das colunas e dos valores gravados no banco, conforme a listagem abaixo:

 

QrBand1        -        1 TqrSysData

QrGroup1      -        1 TqrDbText

QrBand2        -        2 TqrLabel e 2 TqrDbText

ChildBand1    -        1 TqrLabel

QrSubDetail1  -        1 TqrLabel

QrBand3        -        1 TqrLabel e 1 TqrExpr

ChildBand2    -        não tem objeto

QrBand4        -        1 TqrLabel e 1 TQrExpr

 

 

QRSysData1 (QRBand1)

Alignment      taCenter

AlignToBand   True

Data             qrsReportTitle

font.Style      Bold

Font.Size      12

 

QRDBText1 (QRGroup1)

Alignment      taCenter

AlignToBand   True

Color            $00DFDFDF

DataField       nomeempresa

DataSet                 Query1

 

QRLabel1 (QRBand2)

Caption                  Funcionario:

Left              16

 

QRDBText2 (QRBand2)

DataField       nomefuncionario

DataSet                 Query1

Left              96

 

QRLabel2 (QRBand2)

Caption                  Salario:

Left              264

 

QRDBText3 (QRBand2)

DataField       salario

DataSet                 Query1

Left              320

 

QRLabel3 (ChildBand1)

Caption                  Filho(s):

Left              40

Font.Style     Bold

 

QRLabel4 (QRSubDetail1)

Caption                  nome do filho

Left              56

 

QRLabel5 (QRBand3)

Caption                  SubTotal de Salários:

Left              424

Font.Style     Bold

 

QRExpr1 (QRBand3)

Expression     sum(Query1.Salario)

ResetAfterPrint        TRUE

Left              576

Font.Style     Bold

 

QRLabel7 (QRBand4)

Caption                  Total Geral de Salários:

Left              424

Font.Style     Bold

 

QRExpr2 (QRBand4)

Expression     sum(Query1.Salario)

Left              576

Font.Style     Bold

 

Agora nosso relatório já está com uma boa forma:

 

figura3

 

Abaixo o código do relatório:

 

 

unit ReEmpFun;

 

interface

 

uses Windows, SysUtils, Messages, Classes, Graphics, Controls,

  StdCtrls, ExtCtrls, Forms, Quickrpt, QRCtrls, Db, DBTables;

 

type

  TqrEmpFun = class(TQuickRep)

    Query1: TQuery;

    QRBand1: TQRBand;

    QRGroup1: TQRGroup;

    QRDBText1: TQRDBText;

    QRBand2: TQRBand;

    QRDBText2: TQRDBText;

    QRSubDetail1: TQRSubDetail;

    QRLabel4: TQRLabel;

    ChildBand1: TQRChildBand;

    QRLabel3: TQRLabel;

    Query2: TQuery;

    QRBand3: TQRBand;

    QRExpr1: TQRExpr;

    QRDBText3: TQRDBText;

    QRLabel1: TQRLabel;

    QRLabel2: TQRLabel;

    QRLabel5: TQRLabel;

    QRShape1: TQRShape;

    ChildBand2: TQRChildBand;

    QRBand4: TQRBand;

    QRLabel7: TQRLabel;

    QRExpr2: TQRExpr;

    QRSysData1: TQRSysData;

    procedure QRBand2BeforePrint(Sender: TQRCustomBand;

      var PrintBand: Boolean);

    procedure QRSubDetail1BeforePrint(Sender: TQRCustomBand;

      var PrintBand: Boolean);

  private

 

  public

 

  end;

 

var

  qrEmpFun: TqrEmpFun;

 

implementation

 

{$R *.DFM}

 

procedure TqrEmpFun.QRBand2BeforePrint(Sender: TQRCustomBand;

  var PrintBand: Boolean);

begin

  //atribui valor ao parâmetro da query filho para filtar o(s) filho(s) do funcionário corrente

  with Query2 do

  begin

    Close;

    ParamByName('MCodFunc').Value := Query1.FieldByName('codfuncionario').AsInteger;

    Open;

  end;

end;

 

procedure TqrEmpFun.QRSubDetail1BeforePrint(Sender: TQRCustomBand;

  var PrintBand: Boolean);

begin

  //testa se query de filho esta vazia para o funcionário corrente

  if Query2.IsEmpty then

     QRLabel4.Caption := 'Não Possui Filho(s)'

  else

     QRLabel4.Caption := Query2.FieldByName('nome').AsString;

end;

 

end.

 

 

 

         Conforme comentado, esta é uma estrutura que dá uma base para criar relatórios mais completos/complexos no Delphi. Não existe um segredo para a criação de relatórios que possuam agrupamentos, múltiplos níveis, subtotais, totais, etc. E nem muito menos a necessidade de escrever várias linhas de código para obter tal resultado, o importante é explorar ao máximo as propriedades dos componentes do QR.

         Após esses passos, nosso relatório está basicamente pronto. Ao executá-lo, teremos como resultado todos os funcionários agrupados por empresa que por sua vez terão todos os seus dependentes listados (se houverem). O total de salários pagos por empresa e o total geral de salários pagos também serão exibidos. Desta forma, teremos o relatório abaixo:

 

figura4

 

            Como você pode observar, foram criados dois grupos separados (Business Tech e Wam Corporation), na mesma página. Caso você queira colocar um grupo em cada página, basta mudar a propriedade ForceNewPage do QRGroup1 para True. Através deste artigo, meu objetivo foi mostrar como é fácil construir relatórios no QuickReport, sem a necessidade de páginas de digitação de código. Este exemplo pode ser baixado no endereço http://www.clubedelphi.com.br/edicao12/qr.zip