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!