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

 

Curso

Sistema de Biblioteca – Parte IV: Devoluções

Finalmente, nosso último cadastro! Depois de cadastrarmos os leitores, livros, e empréstimos de nossa biblioteca, resta-nos apenas cadastrara as devoluções dos livros. Esta parte do curso é mais simples do que as anteriores, pois não veremos nenhuma novidade, será apenas uma revisão do aprendizado anterior. Veremos aqui o formulário de devoluções e a consulta, indicando os leitores que estão com suas datas vencidas. Neste passo, não usaremos nosso modelo de cadastro (criado nas edições anteriores), pois este formulário terá uma interface um pouco diferente. Na figura 1 podemos visualizar o formulário de devoluções compilado:


Figura 1: Formulário de Devoluções

Como mostrado na figura, o formulário de devoluções possui alguns TComboBoxes na parte superior e um TDBGrid no meio do formulário. Repare que pela primeira vez em nosso sistema usaremos o controle TPageControl, aquele que faz as abas do Windows. Nas respectivas abas, iremos visualizar os empréstimos em aberto, os empréstimos fechados e, no último, os empréstimos que ultrapassaram a data de vencimento, que é de 15 dias após o empréstimo, conforme especificado na edição nº 1. Nos objetos TComboBoxes, o usuário poderá selecionar pelo cliente e selecionar a ordem no qual os dados serão exibidos. Dando um clique duplo sobre o item na grade, o usuário estará cadastrando uma devolução para aquele empréstimo, tornando-o OK. Então, anime-se, pois com este iremos finalizar nossos cadastros.

Começaremos criando o objeto TForm e configurando-o de acordo com a tabela abaixo:

Tabela 1: Objeto TForm

Name

FrmDevolução

BorderStyle

bsDialog

Position

poScreenCenter

Caption

Devolução de Livros

Salve o formulário e chame sua unidade de devolucao.pas. Abra o formulário FrmPrincipal, o form "pai" da aplicação, e crie um item de menu abaixo da opção Controle (criado na 1ª edição). Configure a propriedade Caption desse submenu para ‘Devoluções’. Em seu evento OnClick, digite:

procedure TFrmPrincipal.

Devolues1Click (Sender : TObject);

begin

FrmDevolucao.ShowModal;

end;

Salve o projeto e execute. O Delphi irá questionar a inclusão da chamada a esta unidade2. Basta responder Yes e prosseguir.

Com o formulário criado e configurado, vamos inserir os objetos necessários, de acordo com a figura 3. Configure-os de acordo com a lista abaixo:




Figura 3: segunda aba do TPageControl

Tabela 2: Objeto ComboBox1

Name

cboLeito

Style

csDropDownList

 

Tabela 3: Ojeto ComboBox2

Name

cboOrdem

Style

csDropDownList

Items

Nome

 

Data

 

Tabela 4: Objeto Table1

Name

tbLeitor

DtabaseName

Biblio

TableName

Leitor.db

IndexName

IndNome

 

Tabela 5: Objeto Table2

Name

tbEmprestimo

DatabaseName

Biblio

TableName

Emprestimo.db

2

Tabela 6: Ojeto Query1

Name

qyEmpretimo

DatabaseName

Biblio

 

Tabela 7: Objeto Query2

Name

qyLivrosEmp

DatabaseName

Biblio

 

Tabela 8: Objeto DataSourcel

Name

dsEmprestimo

Dataset

qyEmprestimo

 

Tabela 9: Objeto DataSource2

Name

dsLivrosEmp

Dataset

qyLivrosEmp

 

Tabela10: Objeto DBGrid

Name

DBEmprestimo

DataSource

dsEmprestimo

 

Tabela 11: Objeto DBGrid2

Name

DBLivrosEmp

DataSource

dsLivrosEmp

Insira também um objeto TPageControl. Para criar as três abas morstradas na figura 3, clique com o botão direito do mouse sobre o objeto e selecione a opção New Page. Repare que dentro do objeto PageControl, existirão três objetos da classe TTabSheet, cada um em sua respectiva aba. Configura as propriedades dos objetos TabSheet de acordo com a lista abaixo: (Para selecionar o Tabsheet, clique dentro do corpo do PageControl)

Tabela 12: Objeto PageControl (aba 1)

Caption

Empréstimos

 

Tabela 13: Objeto PageControl (aba 2)

Caption

Devoluções

 

Tabela 14: Objeto PageControl (aba 3)

Caption

Em Atraso

Iniciaremos pelo evento mais simples, o clique no botão Fechar do formulário:

procedure TFrmDevolucoes.

btFecharClick (Sender:Tobject);

begin

close;

end;

O próximo passo será preencher o objeto cboLeitor com os respectivos nomes. O preenchimento deste ComboBox será feito de forma manual, percorrendo toda a tabela de leitores e preenchendo-a. Repare que a tabela está indexada pelo campo nome, conforme configurado anteriormente. No evento OnShow do Form, digite:

procedure TFrmDevolucoes.

FormShow (Sender: TObject);

begin

tbLeitor.Open;

cboLeitor.Itemsclear;

cboLeitor.Items.Add (‘Todos’);

while not tbLeitor.Eof do

begin

cboLeitor.ItemsAdd (

TbLeitor.Fieldbyname

(‘Nome’).asString);

tbLeitor.next;

end;

cboLeitor.ItemIndex: = 0;

cboOrdem.ItemIndex: = 0;

end;

Primeiramente, a tabela de leitores é aberta. Em seguida, limpa-se todos os itens do objeto cboLeitor, através do método clear da propriedade/objeto items. Antes de inserir os valores da tabela de leitores, é inserido o item ‘Todos’. Quando o usuário selecionar este item, será desconsiderado o filtro por leitor, e todos os empréstimos em aberto serão exibidos. Em seguida é feito um loop que percorre toda a tabela de leitores e preenche os respectivos valores do campo Nome no objeto cboLeitor. E por último, fora do loop, a propriedade ItemIndex dos objetos cboLeitor e cboOrdem são setadas para zero. Isto é feito porque, como a propriedade style desses objetos foram setadas para csDropDownList, a propriedade ItemIndex só pode ser alterada em tempo de execução.

Devemos então ativar os objetos de seleção para que passem a funcionar. Para isto, vamos criar algumas constantes, que servirão para armazenar o código SQL:

Const

Sql1 = ‘select Leitor.Nome, emprestimo.dataemp’;

Sql2 = ‘from leitor, emprestimo’;

Sql3: String = ‘where emprestimo.leitor = leitor.codigo and emprestimo.DataDevolucao is null’;

Sql4: String = ‘where emprestimo.leitor = leitor.codigo and emprestimo.DataDevolucao is not null’;

var

FrmDevolucoes:TFrmDevolucoes;

Implementation

A cláusula Const pode ser inserida antes da cláusula Var, da seção interface.

O filtro por cliente será executado quando o usuário selecionar algum item na lista. O código para o filtro será feito, então, no evento OnChange do objeto cboLeitor.

Vamos por partes: O filtro deve ser feito de acordo com duas situações: Quando o usuário selecionar a opção Todos (índice 0), todos os empréstimos em aberto serão executados. Caso contrário, somente os empréstimos do cliente selecionado serão exibidos. Vejamos a primeira situação:

procedure TFrmDevolucoes.

cboLeitorChange (Sender:TObject);

begin

qyDevolucao.Sql.clear;

qyDevolucao.Sql.Add (sql1);

qyDevolucao.Sql.Add (sql2);

qyDevolucao.sql.add (sql3);

if cboOrdem.ItemIndex = 0 then

qyDevolucao.Sql.Add (‘order

by leitor.nome’)

else

qyDevolucao.sql.add (‘order by emprestimo.dataemp’);

qyDevolucqo.Open;

end;

Primeiro, devemos limpar o conteúdo da propriedade SQL e atribuir o código SQL padrão:

qyDevolucao.Sql.Clear;

qyDevolucao.Sql.Add (Sql1);

qyDevolucao.Sql.Add (Sql2);

qyDevolucao.Sql.Add (Sql3);

Repare que a propriedade SQL, do objeto TQuery, é a que armazena o código SQL que será executado no momento da abertura da Query. A propriedade SQL é um objeto da classe Tstrings, e possui, portanto, métodos e propriedades para manipulação de seu conteúdo. O código descrito acima simplesmente limpa o conteúdo do código SQL e adiciona as três linhas básicas de nossa consulta, que foi armazenada nas constantes SQL1, SQL2 e SQL3. O último passo então é especificar em qual ordem os dados serão exibidos na grade. Esta ordem é executada de acordo com o objeto cboOrdem:

if cboOrdem.ItemIndex=0 then

qyDevolucao.Sql.Add (‘order

by leitor.nome’)

else

qyDevolucao.sql.add (‘order

by emprestimo.dataemp’);

O método Add sempre insere no final da lista, e portanto, adicionará a cláusula Order by após as três linhas padrões da consulta.

Ok! Basta apenas abrir a query no final da procedure:

qyDevolucao.Open;

Para criar o filtro da segunda situação, basta adicionar o código a seguir:

procedure TFrmDevolucoes.

cboLeitorChange (Sender:TObject);

begin

qyDevolucao.Sql.Clear;

qyDevolucao.Sql.Add (Sql1);

qyDevolucao.Sql.Add (Sql2);

qyDevolucao.Sql.Add (Sql3);

if cboLeitor.ItemIndex>0

then begin

TbLeitor.FindKey ( [

CboLeitor.Text] );

qyDevolucao.Sql.Add (‘and

leitor.codigo = ‘+

TbLeitor.Fieldbyname

(‘codigo’).asString);

end;

if cboOrdem.ItemIndex=0 then

qyDevolucao.Sql.Add (‘order

by leitor.nome’)

else

qyDevolucao.Sql.Add (‘order

by emprestimo.dataemp’);

qyDevolucao.Open;

end;

Repare que após a inclusão das três linhas básicas da query, é feita a comparação pra verificar se foi selecionado um cliente específico:

if cboLeitor.ItemIndex>0

then begin

Após, devemos capturar o código do leitor selecionado. Para isto, é executado o método FindKey, passando o nome do leitor selecionado como parâmetro. Lembre-se que a tabela está indexada pelo campo nome:

TbLeitor.FindKey ( [CboLeitor. Text] );

E após é adicionado o filtro SQL no objeto Tquery:

qyDevolucao.sql.add (‘and

leitor.codigo = ‘+

TbLeitor.Fieldbyname

(‘codigo’).asString);

Com isto, o filtro pelo cliente já pode ser executado pelo usuário. Com este código, podemos também ativar o objeto CboOrdem. Este comboBox permite que o usuário selecione em qual ordem os dados serão exibidos: pelo nome do leitor ou pela data do empréstimo. O evento usado também foi o onChange:

procedure TFrmDevolucoes.

cboOrdemChange (Sender: TObject);

begin

cboLeitorChange (nil);

end;

O que devemos fazer é apenas executar o evento OnChange do objeto cboLeitor, pois nele já é executado todo o código necessário para a seleção por leitor e a ordem de exibição.

O objeto DbLivrosEmprestados, da classe TdbGrid, exibirá os livros relacionados ao empréstimo selecionado no objeto DbEmprestimo. O objeto DbLivrosEmprestados está linkado com o query QyLivrosEmp. Este query deve ser utilizado sempre que o usuário selecionar um empréstimo diferente na grade. Podemos então, executar o filtro no evento onAfterScroll, do objeto QyEmprestimos:

procedure TFrmDevolucoes.

qyEmprestimoAfterScroll

(DataSet: TDataSet);

begin

qyLivrosEmp.Close;

qyLivrosEmp.Prepare;

qyLivrosEmp.Sql.Clear;

qylivrosEmp.Sql.Add (

‘SELECT livrosemp.serie,

livros.titulo’);

qyLivrosEmp.Sql.Add (

‘from livrosemp, livros’);

qyLivrosemp.Sql.Add (

‘where livrosemp.codLivro

=Livros.Codigo’);

qyLivrosEmp.Sql.Add (‘and

livrosemp.CodEmp = ‘+

qyEmprestimo.Fieldbyname

(‘Codigo’).asString);

qyLivrosEmp.Open;

end;

Vamos nos ater a cláusula SQL:

Select LivrosEmp.Serie,

Livros.Titulo

From LirosEmp, Livros

Where LivrosEmp.Codlivro =

Livros.Codigo

And LivrosEmp.CodEmp = XXX

O que é feito é uma união entre as tabelas LivrosEmp e Livros. A tabela de livros é inserida no SQL apenas para que seja exibido o título do livro na grade. E a linha:

And livrosEMp.CodEmp =

(QyEmprestimo.Fieldbyname

(‘Codigo’).asString)

Seleciona apenas os livros relacionados aos empréstimo atualmente selecionado no objeto QyEmprestimo.

Com este código, sempre que o usuário navegar no objeto dbEmprestimo, o objeto QyLivrosEmp será atualizado, exibindo assim, somente os livros referentes ao empréstimo atual.

Podemos refinar um pouco mais este código, inserindo as linhas abaixo:

procedure TFrmDevolucoes.

qyEmprestimoAfterScroll

(DataSet: TDataSet);

begin

if qyEmprestimo.Fieldbyname

(‘Codigo’).asString<>’’

then begin

qyLivrosEmp.Close;

qyLivrosEmp.Prepare;

qyLivrosEmp.Sql.Clear;

qyLivrosEmp.Sql.Add (

‘SELECT livrosemp.serie,

livros.titulo’);

qyLivrosEmp.Sql.Add (

‘from livrosemp, livros’);

qyLivrosemp.Sql.Add (

‘where livrosemp.codLivro

=Livros.Codigo’);

qyLivrosEmp.Sql.Add (‘and

livrosemp.CodEmp = ‘+

qyEmpretimo.Fieldbyname

(‘Codigo’).asString);

qyLivrosEmp.Open;

end;

Vamos nos ater a cláusula SQL:

Select LivorsEmp.Serie,

Livros.Titulo

From LivrosEmp, Livros

Where LivrosEmp.Codlivro =

Livros.Codigo

And LivrosEmp.CodEmp = XXX

O que é feito é uma união entre as tabelas LivrosEmp e Livros. A tabela de livros é inserida no SQL apenas para que seja exibido o título do livro na grade. E a linha:

And livrosEmp.CodEmp =

(QyEmprestimo.Fieldbyname

(‘Codigo’).asString)

Seleciona apenas os livros relacionados ao empréstimo atualmente selecionado no objeto QyEmprestimo.

Com este código, sempre que o usuário navegar no objeto dbEmprestimo, o objeto QyLivrosEmp será atualizado, exibindo assim, somente os livros referentes ao empréstimo atual.

Podemos refinar um pouco mais este código, inserindo as linhas abaixo:

procedure TFrmDevolucoes.

qyEmprestimoAfterScroll

(DataSet: TDataSet);

begin

if qyEmprestimo.Fieldbyname

(‘Codigo’).asString<>’’

then begin

qyLivrosEmp.Close;

qyLivrosEmp.Prepare;

qyLivrosEmp.Sql.Clear;

qylivrosEmp.Sql.Add

(‘Select livrosemp.serie,

livros.titulo’);

qyLivrosEmp.Sql.Add (‘from

livrosemp, livros’);

qyLivorsemp.Sql.Add (‘where

livorsemp.codLivro =

Livros.Codigo’);

qyLivrosEmp.Sql.Add (‘and

QyEmpretimo.Fieldbyname

(‘Codigo’).asString);

qyLivrosEmp.Open;

end

else

qyLivrosEmp.Close;

end;

Isto irá garantir que o sistema não falhe quando o usuário selecionar um leitor que não possua empréstimos.

Ok! A primeira Aba já está funcional. Devemos agora criar a funcionalidade da Segunda aba, cujo objetivo é exibir todos os empréstimos que já foram devolvidos. Primeiramente, a aba deve ser preenchida com os dois objetos TdbGrid correspondentes, conforme mostra a figura 3.

Coloque os dois objetos DbGrid, conforme a descrição abaixo:

Tabela 15: Objeto DBGrid3

Name

DBDevolucao

DataSource

dsEmprestimo

 

Tabela 16: Objeto DBGrid4

Name

DBLivrosDev

DataSource

dsLivrosEmp

E para exibir somente os empréstimos já fechados, basta inserir a cláusula abaixo no evento onchange do objeto CboLeitor:

procedure TFrmDevolucoes.

cboLeitorChange (Sender:TObject);

var

data: TDateTime;

begin

qyEmprestimo.Sql.Clear;

qyEmprestimo.Sql.Add (Sql1);

qyEmprestimo.Sql.Add (Sql2);

if PageControl1.ActivePage=

TabSheet2 then

qyEmprestimo.Sql.add (Sql4);

else

qyEmprestimo.Sql.add (Sql3);

if cboLeitor.ItemIndex>0

then begin

tbLeitor.FindKey ( [

CboLeitor.Text] );

qyEmprestimo.Sql.add (‘ and

leitor.codigo = ‘ +

TbLeitor.Fieldbyname

(‘codigo’).asString);

end;

if cboOrdem.ItemIndex=0 then

qyEmprestimo.Sql.Add (‘order

by leitor.nome’)

else

qyEmprestimo.Sql.Add (‘order

by emprestimo.dataemp’);

qyEmprestimo.Open;

end;

Repare que a cláusula anterior:

QyEmprestimo.Sql.Add (SQl3);

Foi substituída por:

if PageControl1.ActivePage =

TabSheet2 then

qyEmprestimo.Sql.Add (Sql4)

else

qyEmprestimo.Sql.Add (Sql3);

A variável sql4 já contém a cláusula Where referente a exibição dos Empréstimos Fechados:

‘where emprestimo.leitor =

leitor.codigo and

emprestimo.DataDevolucao is

not null’;

O que deve ser feito é uma comparação para saber se a aba selecionada foi a Segunda. Esta comparação é feita através da propriedade ActivePage, do objeto Pagecontrol, que representa nossas abas:

if PageControl1.ActivePage=

TabSheet2 then

E no evento OnChange do objeto PageControl, devemos atualizar query, para que este reflita o novo filtro selecionado:

procedure TFrmDevolucoes.

PageControl1Change (Sender:

TObject);

begin

cboLeitorChange (nil);

end;

Simples – basta chamar o evento onchange do objeto cboLeitor, conforme feito anteriormente no objeto cboOrdem. Com isto, a segunda aba tem sua funcionalidade terminada. Vamos agora criar a terceira aba, que tem como objetivo exibir somente os empréstimos em atraso, conforme mostra a figura 4.

Insira os dois objetos DbGrid no formulário e configure suas respectivas propriedades de acordo com a descrição abaixo:

Tabela 17: Objeto DBGrid5

Name

DBEmAtraso

DataSource

dsEmprestimo

 

Tabela 18: Objeto DBGrid6

Name

DBLivrosEmAtraso

DataSource

dsLivrosEmp

Para exibir os empréstimos em atraso, basta incluir a cláusula abaixo no evento OnChange do objeto cboLeitor:

procedure TFrmDevolucoes.

cboLeitorChange (Sender:TObject);

var

data:TDateTime;

begin

qyEmprestimo.Sql.Clear;

qyEmprestimo.Sql.Add (Sql1);

qyEmprestimo.Sql.Add (Sql2);

if PageControl1.ActivePage=

TabSheet2 then

qyEmprestimo.Sql.Add (Sql4);

else

qyEmprestimo.Sql.Add (Sql3);

if cboLeitor.ItemIndex>0

then begin

TbLeitor.FindKey

( [CboLeitor.Text] );

qyEmprestimo.Sql.add (‘ and

leitor.codigo = ‘ +

TbLeitor.Fieldbyname

(‘codigo’).asString);

end;

if PageControl1.ActivePage=

TabSheet3 then

qyEmprestimo.Sql.Add (‘ and

" ‘ + FormatDateTime

(‘mm/dd/yyyy’, now) + ‘"

– DataEmp > 15’);

if cboOrdem.ItemIndex=0

then

qyEmprestimo.Sql.Add (‘order

by leitor.nome’)

else

qyEmprestimo.sql.add (‘order

by emprestimo.dataemp’);

qyEmprestimo.Open;

end;

 

Primeiro, é verificado se a aba atual é a terceira, através da propriedade ActivePage, do objeto PageControl:

if PageControl1.ActivePage =

Tabsheet3 then

Caso verdadeiro, é adicionado a cláusula SQL que retorna os empréstimos vencidos:

qyEmprestimo.Sql.Add (‘ and

" ‘ + FormatDateTime

(‘mm/dd/yyyy’, now) + ‘ "

– DataEmp > 15’)


Figura 4: Terceira aba do TPageControl

O filtro é feito baseado no período de 15 dias de vencimento, conforme especificado na edição nº 1. O que é feito é simplesmente a subtração da data atual com o campo DataEmp, que representa a data de empréstimo. Para retornar a data atual, foi usada a função FormatDateTime:

FormateDateTime

(‘mm/dd/yyyy’, now)

A função FormatDateTime converte um valor do tipo DateTime para String. O primeiro parâmetro especifica qual será o formato da datas, que no caso, deve ser passado ao SQL como mês/dia/ano.

E com isto, as três abas passam a exibir corretamente seus respectivos conteúdos, assim como aceitam o uso dos filtros relacionados. O último retoque necessário é a chamada ao método cboLeitorChange no evento onShow do formulário, para que este inicie exibindo os dados corretamente:

procedure TFrmDevolucoes.

FormShow (Sender: TObject);

begin

tbLeitor.Open;

tbLeitor.First;

cboLeitor.Items.clear;

cboLeitor.Items.Add (‘TODOS’);

while not tbLeitor.Eof do

begin

cboLeitor.Items.Add (

TbLeitor.Fieldbyname

(‘Nome’).asString);

tbLeitor.next;

end;

cboLeitor.ItemIndex: = 0;

cboOrdem.ItemIndex: = 0;

cboLeitorChange (nil);

end;

O que deve ser feito agora é o cadastramento das devoluções. O usuário fará o registro de devolução de uma forma bem simples: dando um clique duplo sobre o empréstimo referente. No evento ondblClick do objeto DbGrid, o sistema exibirá uma caixa de diálogo pedindo a confirmação da entrega. Caso a resposta seja positiva, será gravado a data de devolução do empréstimo na tabela.

Coloque um objeto Ttable, para que possamos inserir a data de devolução na tabela de empréstimos.

NOTA: O objeto Tquery possui a propriedade RequestLive, que permite o uso de /inserções/alterações através da própria consulta. Esta propriedade está intimamente ligada ao tipo de query que é retornada pelo código SQL. No nosso caso, o SQL retorna uma query readonly, inviabilizando, portanto, o uso da propriedade requestlive. Veja a seguir as possíveis situações que fazem uma query se tornar do tipo read-only:

• Se alguma operação com o operador LIKE estiver sendo usada;

• Se existir a união de tabelas;

• O uso de cláusulas como JOIN ou UNION;

• O usuário não possuir permissões de alteração da tabela correspondente;

Vamos então configurar nosso objeto TTable, para que aponte para a tabela de empréstimos:

Tabela 19: Objeto Table1

Name

tbEmprestimo

DatabaseName

Biblio

TableName

Emprestimo.db

E vamos ao evento onDblClick do objeto dbEmprestimos:

procedure TFrmDevolucoes.

DBEmprestimosDblClick (Sender:

TObject);

begin

if QyEmprestimo.

RecordCount = 0 then exit;

if application.MessageBox

(‘Confirma devolução?’,

‘Clube Delphi’, mb_YesNo)

= IdYes then begin

tbEmprestimo.FindKey

( [QyEmprestimo.fieldbyname

(‘Codigo’).asInteger] );

tbEmprestimo.Edit;

tbEmprestimo.Fieldbyname

(‘dataDevolucao’).

asDateTime: =now;

tbEmprestimo.Post;

cboLeitorChange (nil);

end;

end;

Aqui não há novidades: caso o usuário confirme a devolução dos livros, o sistema localiza o registro referente a tabela de empréstimos e preenche o campo DataDevolucao com a data atual. Por último, o evento onchange do objeto cboLeitor é chamado, para que haja um referesh das informações na tela. Repare que é feita uma verificação na quantidade de registros retornados pelo objeto QyEmprestimos na linha:

if QyEmprestimo.

RecordCount = 0 then exit;

Que impede o usuário de tentar cadastrar uma devolução sem que haja empréstimos. E para finalizar, abra a tabela no evento Onshow do form.

Conclusão

Este formulário, por ser o último cadastro, foi previsivelmente mais simples do que os anteriores. É claro que em uma situação bibliotecária real, seriam exigidos uma quantidade maior de informações. Mas isso fica a cargo de vocês, desenvolvedores, o incremento da funcionalidade do programa. Um exercício interessante seria a possibilidade de filtrar também pela data do empréstimo ou pela data da devolução. Explanar sobre todas essas possibilidades seria redundante para o objetivo do curso.

Acredito que neste estágio o leitor já esteja apto a montar seus próprios cadastros, bastando usar apenas a imaginação, já que as ferramentas e métodos básicos já foram expostos durante nossas quatro edições. Nosso próximo passo será o refinamento da aplicação, criando as validações de integridade e o início da criação dos relatórios de nosso sistema.

Espero que tenham gostado e que este pequeno sistema tenha ajudado no aprendizado em Delphi!