Esse artigo faz parte da revista Clube Delphi edição 6. 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. 

 

Sistema de Bibliotecas: Parte Final – Relatórios

 

Finalmente, chegamos a última parte de nosso curso! Gostaria de agradecer a todos que acompanharam a matéria, e anunciar que todo o projeto já está disponível no site do clube, em www.clubedelphi.com.br/jornal/biblio.zip. Para quem gostou, em breve iremos ilustrar outros cursos em nosso jornal. Caso tenha alguma sugestão de assunto que gostaria encontrar em nossa revista, basta mandar um e-mail para admin@clubedelphi.com.br, dando o seu recado. Acompanhe sempre o Jornal do Delphi para encontrar as próxima novidades.

E nosso último passo será a construção dos relatórios restantes. O curso poderia se estender por mais algumas edições e mostrar como criar os discos de instalação, sistemas de backup e funcionamento em rede. Porém, estes assuntos poderão ser explorados com mais detalhes em matérias independentes, e isto será feito em futuras edições.

Na edição anterior construímos os relatórios de listagem de leitores e listagem de leitores agrupados por escolaridade. Agora criaremos o relatório de empréstimos e de livros não devolvidos.

Veremos a seguir como implementar estes relatórios, utilizando, é claro, o QuickReport.

O primeiro relatório será o de Listagem de Empréstimos. O usuário poderá selecionar o período de data no qual ele deseja visualizar o relatório. Isto porque em algum tempo de uso a quantidade de empréstimos poderá ser gigantesca.

Criaremos um pequeno formulário, disponibilizando uma interface para o usuário escolher a data inicial final do relatório. Este formulário será parecido com a figura 1.

 

Figura 1 Form de seleção de data

 

Crie um novo formulário, salve o projeto e chame a nova unidades de SelData. Configure suas propriedades de acordo com a tabela abaixo:

 

Tabela 1: Formulário

Name

FrmSelData

Posaition

poScreenCenter

BorderStyle

bsDialog

Caption

Selecione a Data

 

E insira os objetos, como mostrado na figura 1. Configure suas propriedades de acordo com as tabelas abaixo:

 

Tabela 2 : Objeto Label1

Caption

Data Inicial

 

Tabela 3: Objeto Label2

Caption

Data Final

 

Tabela 4: Objeto DateTimePicker1

Name

Data1

 

Tabela 5: DateTimePicker2

Name

Data2

 

Tabela 6: Objeto BitBTn1

Name

btVisualizar

Glyph

Zoommin.bmp

 

Tabela 7: Objeto BitBtn2

Name

btImprimir

Kind

kdOk

ModalResult

mrNone

Default

False

 

Tabela 8: Objeto BitBtn3

Name

btImpressoras

Glyph

Printer.bmp

 

Tabela 9: Objeto BitBtn4

Name

btFechar

Glyph

DoorOpen.bmp

 

No evento clique do botão fechar, temos apenas o método close:

 

procedure TfrmSelData.btFechar

Click(Sender : Tobject);

begin

close;

end;

 

Temos uma novidade neste formulário: o botão Impressora ora exibir a caixa de diálogo Configurar Impressora, padrão do Windows. Isto pode ser feito simplesmente com o uso do objeto TprinterSetupDialog. Selecione a palheta Dialogs e insira uma objeto TrrinterSetupDialog. No evento ckique do botão Impressora, digite:

 

procedure TfrmSelData.

btImpressorasClick(Sender:

Tobject);

begin

PrinterSetupDialog1.Execute;

end;

 

No formulário principal, crie uma nova opção de menu, abaixo de relatórios. Em sua propriedade caption digite Listagem de Empréstimos Realizados. No entanto click deste menu digite a chamada ao formulário FrmSelData:

 

procedure TfrmPrincipal.

ListagemdeEmprstimosRealizados1

Clck(Sender: Tobject);

begin

FrmSelData. ShowModal;

end;

 

Para este relatório, precisamos de um novo índice na tabela de empréstimos, que a ordenará por data de empréstimos. Vá no database Desktop e crie um índice para a tabela de empréstimos, ordenando-a pelo campo Data emp. Chame o índice de IndDataEmp.

Crie uma nova instância do objeto TquickRep, através do Object Repository. Vá no menu File, opção New e clique duas vezes sobre o ícone Report.

Configure a propriedade Name do novo objeto para QrList Empréstimos. Salve o projeto e chame a nova unidade de RelListEmprestimos.

 

O nosso relatório será parecido com a figura 2.

 

Figura 2 – Relatório em tempo de projeto

 

Vamos iniciar com a banda de título do relatório. Insira os objetos necessários e configure suas propriedades, tudo de acordo com as tabelas a seguir:

 

Tabela 12: Objeto Tband1

Name

BandTitulo

 

Tabela 11: Objeto QRLabe2

Alignment

taCenter

AlignToBand True

Font.Size

14

Name

qrSubTitulo

 

Tabela 10: Objeto QRLabel

Caption

Listagem de

Empréstimos

Alignment

taCenter

AlignToBand True

Font.Size

18

Name

qrTitulo

 

Precisaremos de quatro objetos tables, que irão se conectar com as tabelas de leitores, livros, empréstimos e livrosemp. Insira quatro objetos table, dois datasources, e configure-os conforme a descrição abaixo:

 

Tabela 13: Objeto Ttable

Name

tbLeitores

DatabaseName

Biblio

TableName

Leitor.db

 

Tabela 14: Objeto Ttable

Name

tbLivros

DatabaseName

Biblio

TableName

Livros.db

 

Tabela 15: Objeto Ttable

Name

tbEmprestimos

DatabaseName

Biblio

TableName

Empréstimos.db

IndexName

IndDataEmp

 

Tabela 16: Objeto TdataSource

Name

dsEmprestimos

DataSet

tbEmprestimos

 

Tabela 17: Objeto Ttable

Name

tbLivrosEmp

DatabaseName

Biblio

TableName

LivrosEmp.db

 

Tabela 18: Objeto TdataSource

Name

dsLivrosEmp

DataSet

tbLivrosEmp

 

Após inserir o DataSource DsLivroisEmp, configure a propriedade de MasterSource e MasterFields do objeto TnLivrosEmp:

 

Tabela 19: MasterSource e MasterFields

MasterSource

dsEmprestimos

MasterFields

CodEmp – Código

 

Nota: Apenas dois datasources são utilizados. Isto porque os objetos linkados de relatório não utilizam o DataSource, mas sim o objeto Table. Os objetos dsEmprestimo e dsLivrosEmp foram necessários para linká-los as propriedades MasterSource e MasterFields.

 

Vamos linkar o relatório com a tabela principal, empréstimos. Altere a propriedade DataSet do objeto Tquinck Rep, e escolha o objeto tbempres timos.

Conforme ilustrado na figura 2, o relatório exibirá o nome do cliente e a descrição dos livros. Nas edições anteriores vimos como criar passo a passo campos virtuais e lookups em objetos ttable. Vamos agora repetir estes passos:

Primeiramente precisaremos do campo “LookUp” (pois é proveniente de outra tabela) nome do leitor. Para isto, clique duas vezes sobre o objeto TbEmprestimo. Na janela subseqüente, clique com o botão inverso e selecione a opção Add Fields. Após, clique com o botão inverso novamente e selecione a opção New Field. Preencha os campos conforme exibido na figura 3.

 

Figura 3 – Janela New Field Tabela: Empréstimos

 

Na tabela LivrosEmp, repita o processo, criando desta vez o campo LookUp DescricaoLivro. O campo será linkado com a tabela de livros, e a janela NewField deverá ser preenchida de acordo com a figura 4.

 

Figura 4 – Janela New Field Tabela: LivrosEmp

 

Agora que temos todos os campos necessários, vamos inserir as bandas no relatório. Insira um objeto TQRBand, e altere sua propriedade Name para BandDetalhes. Dentro do Tband, insira os labels necessários, e posicione-os de acordo com a figura 2.

 

Tabela 20: Objeto TQRDBText1

DataSet

tbEmprestimos

Datafield

Código

 

Tabela 21: Objeto TQRDBText2

DataSet

tbEmprestimos

DataField

NomeLeitor

 

Tabela 22: Objeto TQRDBText3

DataSet

tbEmprestimos

Datfield

DataEmp

 

Repare que este é nosso primeiro relatório máster-detail. Para criarmos a banda filho, usaremos o objeto TqrSubDetail. Insira um qrsubdetail e configure sua propriedade name para bandSubDetalhes. Precisamos agora linkar o objeto subDetail com a tabela filha do relacionamento. Para isto, basta configurar a propriedade DataSet, setando a tabela TbLivrosEmp. Certifique-se que a propriedade Máster esteja configurada para o objeto Quick report1.

Insira os objetos descritos abaixo, e posicione-os de acordo com a figura 2.

 

Tabela 23: Objeto TQRDBText4

DataSet

tbLivrosEmp

DataField

DescricaoLivro

 

Ok! Nosso relatório está praticamente terminado. Basta agora criarmos a chamada ao relatório, no formulário DrmSelData. Abra o formulário FrmSelData e chame o evento click do botão btVisualizar:

 

procedure TfrmSelData.

btVisualizarClick(Sender:

Tobject);

begin

 

with qrListEmprestimos do begin

tbLivros.close;

tbLeitor.Close;

tblivrosEmp.Close;

tbEmprestimos.Close;

tbEmprestimos. Filter:=

‘DataEmp >= ’’’ +

DateToStr

(DateTimePicker1.Date)

+ ’’’ and dataEmp <= ’’’ +

FateToStr

(DateTimePicker2.Date)

+ ’’’ and DataDevolucao =

null’;

 tbEmprestimos.Filtered:=true;

tbEmprestimos.Open;

tbLivrosEmp.Open;

tbLeitor.Open;

tbLivros.Open;

qrSubTitulo.Caption:= ’De’+

Datetestr

(DataTimePicker1.Date)+

‘ a ‘+

DatetoStr

(DatatimePicker2.Date);

Preview;

end;

end;

 

Não há novidades: primeiramente, a cláusula with é utilizada:

 

with qrLisEmprestimos do begin

 

O objetivo da cláusula with é evitar a repetição de um objeto dentro de um bloco. Por exemplo, vejamos o bloco abaixo:

 

Nome_do_objeto.propriedade1...

Nome_do_objeto, propriedade2...

Nome_do_objeto.método1...

Nome_do_objeto.método2...

 

Este bloco poderia ser substituído pela cláusula with. Veja:

 

with nome_do_objeto do

Propriedade1...

Propriedade2...

Método1...

Método2...

end;

 

Repare que dentro de nossa rotina, conteúdo da cláusula with é exatamente o conteúdo do objeto QrListEmprestimos.

 

Após, s tabelas são fechadas:

 

tbLivros.close;

tbLeitor.Close;

tbLivrosEmp.Close;

tbEmprestimos.Close;

 

E a propriedade Filter do objeto tbEmprestimos é atribuída :

 

tbEmprestimos.Filter:=

‘DataEmp >= ’’’ +

DateToStr

(DateTimePicker1.Date) +

’’’ and dataEmp <= ’’’ +

DateToStr

(DateTimePicker2.Date) +

’’’ and DataDevolucao =

null’;

 

A propriedade Filter, em conjunto com a propriedade Filtered, permite criar uma filtragem dos registros no objeto Ttable. A sintaxe é semelhante à cláusula Where, do SQL. No caso, filtramos todos os registros que estejam dentro do período de data especificado pelo usuário, através dos objetos TdateTimePicker, e cujo Campo DataDevolucao seja Null.

 

Nota: Quanto utilizar a propriedade Filter, tenha muito cuidado com o uso das aspas. No SQL, é permitido o uso de aspas diferentes. Veja:

 

SQL = Where nome = “João” ou Where nome = ‘João’

 

Filter = Where nome = ‘João’

 

Ou seja, a propriedade Filter permite apenas o uso de aspas simples. Repare que para representar uma aspa dentro de outra, é necessário utilizar duas aspas:

 

‘DataEmp >= ’’’ +

DateTostr(DateTimePicker1.Date)

+ ’’’

 

No exemplo acima, as aspas sublinhadas representam apenas uma única aspa, que será utilizada dentro do próprio filtro. O resultado da expressão poderia ser:

 

DataEmp >= ‘01/10/1998’

 

Após setar a propriedade filter, devemos alterar a propriedade Filtered, para True:

 

tbEmprestimos.Filtered := True;

 

A propriedade Filtered indica se o filtro será aplicado. A seguir, as outras tabelas são abertas:

 

tbEnprestimos.Open;

tbLivrosEmp.Open;

tbLeitor.Open;

tbLivros.Open;

 

Repare que o Título do relatório é composto de dois labels. O label inferior, conforme exibido na figura 2. ora exibir o período de datas selecionado pelo usuário. Isto é feito na linha:

 

qrSubTitulo.Caption:=’De’+

Datetostr

(DateTimePicker.Date)+

‘ a ’+

DatetoStr

(DatetimePicker2.date);

 

Epor último, o método Preview, que irá exibir o relatório na tela.

O botão imprimir é muito semelhante, bastando apenas alterar o método preview para print:

 

procedure TfrmSelData.

btImprimirClick(Sender:

Tobject);

begin

 

with qrListEmprestimos do begin

tbLivros.close;

tbLeitor.Close;

tbLivrosEmp.Close;

tbEmprestimos.Close;

tbEmprestimos.Filter:=

‘DataEmp >= ’’’ +

DateToStr

(DateTimePicker1.Date)

+ ’’’ and dataEmp <= ’’’ +

DateToStr

(DateTimePicker2.Date)

+ ’’’ and DataDevolucao =

null’;

 

tbEmprestimos.Filtered:=true;

tbEmprestimos.Open;

tbLivrosEmp.Open;

tbLeitor.Open;

tbLivros.Open;

qrSubTitulo.Caption:=‘De’+

Datetostr

(DateTimePicker1.Date)+

‘ a ’+

DatetoStr

(DatetimePicker2.Date);

Print;

end;

end;

 

Ok! Se os passos foram seguidos corretamente, o relatório será parecido com a figura 5.

 

Figura 5 – Relatório em tempo de execução

 

Listagem de Livros

Não Devolvidos

 

Para treinarmos um pouco mais construiremos agora o relatório que listará os livros não devolvidos.

 

Figura 6 – Listagem de Livros Devolvidos

 

Crie um novo TquickReport, através do Repositório de objetos, e altere sua propriedade Name para QrLivrosAtrasados. Salve a nova unit e nomeie-a RelLivrosAtrasados.

Insira um objeto Tband, que será nosso título. Insira um objeto TqrLabel dentro do Tband, e configure suas propriedades de acordo com a tabela abaixo.

 

Tabela 24: Objeto QRLabel

Caption

Listagem de Livros

Atrasados

Alignment

taCenter

AlignToBandTrue

Font.Size

18

 

Insira também o QuickReport, um objeto Tband e configure sua propriedade BandType para rbDetail, e altere sua propriedade name para BandDetalhes.

Insira um objeto Tquery, que irá prover os dados para o nosso relatório.

 

Defina na propriedade DatabaseName Biblio, e coloque o código a seguir na propriedade SQL:

 

SELECT Liv.Titulo, LivEmp.*,

Leit.*, Emp.DataEmp

FROM Empréstimo Emp, LivrosEmp

LivEmp, Livros Liv, Leitor Leit

WHERE

Emp.Código = LivEmp.CodEmp

AND

LivEmp.CodLivro = Liv.Código

AND

Emp.Leitor = Leit.Código

AND

:Data – Emp.DataEmp > 15

ORDER BY LivEmp.CodLivro

 

na propriedade Params, defina o tipo ftDate para o parâmetro Data.

Com o objeto Query configurado, altere a propriedade DataSet do objeto QrLivrosAtrasados para Query1.

As informações exibidas para cada livro serão o nome do leitor, o número de série do livro e a data de Empréstimo. Dentro do objeto Band Detalhes, insira os objetos correspondentes, conforme a tabela abaixo:

 

Tabela 25: Objeto TQRDBText1

DataSet

Query1

Datafield

Nome

 

Tabela 26: Objeto TQRDBText2

DataSet

Query1

DataField

Serie

 

Tabela 27: Objeto TQRDBText3

DataSet

Query1

Datafield

DataEmp

 

Iremos quebrar o relatório por livro. Insira um objeto TqrGroup, e configure suas propriedades:

 

Tabela 28: Objeto TQRGroup

Name

Grupo1

Expression

Query1.CodLivro

 

E insira um TqrDbText, dentro do objeto Grupo1. Posicione-o de acordo com a figura 7:

 

Tabela 29: Objeto TQRDBText

DataSet

Query1

Datafield

Titulo

 

E OK! Até aqui não temos nenhuma novidade, todos os passos já foram ilustrados em nossos relatórios anteriores. Nossa última implementação será o uso de eventos dos objetos de relatório. A possibilidade de programar os eventos de cada objeto de relatório é um dos grandes diferenciais do QuickReport para com os geradores de relatório, pois isto dá uma flexibilidade muito grande ao programador. Vejamos um pequeno exemplo:

Em nosso relatório de atrasados, indicaremos ao lado do nome do indivíduo, o seu estado atual. A tabela de leitores possui o campo booleano Ativo – utilizaremos este campo para indicar a situação do leitor.

As bandas e até mesmo o próprio quickreport possuem os eventos OnBeforePrint e OnAfterPrint. Estes eventos ocorrem antes e depois que a banda/Relatório for impresso. Com eles, o desenvolvedor pode criar situações específicas, cálculos complexos e outras rotinas. No nosso caso, iremos utilizar o evento OnBeforePrint para identificar a situação do leitor, e exibí-la no relatório. Insira um objeto TqrLabel na banda de detalhes, altere seu nome para qrLblSituacao, e posicione-o de acordo com a figura 7.

 

Figura 7 – TQRlabel: Situação do Leitor

 

E no evento OnBeforePrint da banda de Detalhes (BandDetalhes), basta digitar o código:

 

procedure TqrLivrosEmnprestados.

BandDetalhesBeforePrint

(Sender:TQRCustomBand; var

PrintBand: Boolean);

begin

printband:=True;

if not Query1.

Fieldbyname(‘ativo’).asBoolean

then

qrLblSituacao.Caption:=‘Inativo’

else

qrLblsituacao.Caption:=’’;

end;

 

Repare que o evento onBeforePrint irá acontecer antes da impressão de cada linha da banda. O código simplesmente verifica a situação do leitor e atribui o valor correto ao objeto qrLblSituacao. O parâmetro PrintBand especifica se a banda será ou não impressa. Por exemplo, se tivéssemos uma situação onde algumas linhas do relatório não poderiam aparecer, poderíamos criar a rotina no evento OnBeforePrint. Veja Abaixo:

 

begin

if Condição_Não_Satisfeita then

Printband:=False

else

Printband:=True;

end;

 

E a rotina seria executada para todas as linhas do relatório, exibindo somente os registros que estivessem dentro da condição especificada.

 

OK! Basta agora linkarmos o relatório a uma opção de menu. No formulário principal, crie uma opção de menu abaixo do menu Relatórios, e chame a de Relatório de Livros não Devolvidos. No seu evento click, digite:

 

procedure TfrmPrincipal.

LivrosnoDevolvidos1Click(Sender:

Tobject);

begin

qrLivrosAtrasados.Query1.Close;

qrLivrosAtrasados. Query1.

OaramByName(‘Data”).asDate :=

now;

qrLivrosAtrasados.Query1.Open;

qrLivrosAtrasados.Preview;

end;

 

Figura 8 – Livros Não Devolvidos

 

Conclusão

Chegamos ao final de nosso tema. Para facilitar o estudo, os fontes se encontraram disponíveis no endereço: www.clubedelphi.com.br/jornal/biblio.zip. Neste exemplo vimos os recursos básicos e indispensáveis para a construção de um sistema. Trabalhar com Table, Query, objetos DataControl, eventos, e o QuickReport são elementos que provavelmente não faltarão em qualquer sistema de controle. Os eventos do QuickReport e a parte programada são muito extensas, e serão matéria de próximas edições. Para quem ficou com alguma dúvida, crítica, ou queira acrescentar algum comentário, basta enviar um e-mail para suporte@clubedelphi.com.br. Espero que tenha sido claro em minhas considerações e que este pequeno sistema possa ter ajudado no aprendizado da linguagem. Agradeço a atenção dada por todos vocês e estou ansioso para nosso próximo encontro. Até a próxima!