Você está na página 1de 68

00 - Editorial.indd 2 24.03.

08 06:17:22
Sumrio
Ol, eu sou o DevMan! Desta pgina em diante, eu estarei lhe
ajudando a compreender com ainda mais facilidade o conte-
do desta edio. Ser um prazer contar com sua companhia!
Confira abaixo o que teremos nesta revista:

08 Streams
Expert Implemente compactao, download em mltiplos pacotes e resources em
suas aplicaes com tcnicas avanadas de Streams Parte 2
[ Gustavo Chaurais ]

Expert 16 Anlise de Pontos de Funo


Engenharia de Saiba mensurar o tamanho de seu software e estimar o tempo que levar para ficar pronto
Software [ Carmo Crdiney de Melo e Marco Antnio Pereira Arajo ]

24 Usando todo o poder do TDataSetProvider


Mo na Massa Usufrua de todos os recursos do DataSetProvider em suas aplicaes
[ Adriano Santos ]

Mo na Massa 32 ClientDataSet
Automatizando o tratamento de Erros
[ Rodrigo Lazoti ]

Web
Mini-Curso 36 Controle on-line de vdeo-locadora - Parte 2
Mo na Massa Veja como criar um sistema on-line de controle para uma vdeo-locadora
[ Maikel Marcelo Scheid ]

Tutorial 42 Desenvolvendo uma Aplicao Completa com PocketStudio


Mini-Curso
Aprenda a criar aplicaes para o sistema operacional PalmOS Parte 3
[ Ricardo C. Boaro ]

50 Envio de E-mails com componentes da paleta Indy


Easy Veja como enviar e-mails utilizando os componentes da paleta Indy
[ Maikel Marcelo Scheid ]
Voc percebeu os cones ao lado de cada matria? Eles in-
dicam o que voc vai encontrar no artigo dessa forma,
54 Editor de Textos com RichEdit voc tambm pode ter uma idia geral do que vai encon-
Easy Veja como criar seu prprio editor de textos com o componente RichEdit trar nesta edio como um todo! Os editores trabalham
[ Maikel Marcelo Scheid ] sempre no sentido de fechar a revista seguindo esta defi-
nio, para oferecer a voc o melhor contedo didtico!

Confira abaixo a lista com a definio dos tipos de artigo


Delphi PHP 60 Orientao a Objetos no Delphi for PHP
encontrados nesta edio:
Mini-Curso
Como aplicar conceitos de POO em aplicaes PHP Parte 2
[ Rodrigo Carreiro Mouro ]

[ Mo na Massa ] Artigos que focam na resoluo de problemas [ Delphi PHP ] Artigo com foco na verso PHP do Delphi [ Expert ] Artigo com foco no leitor avanado
- e no na tecnologia. A tecnologia empregada apenas conseq-
ncia. O artigo parte do pressuposto que o leitor j conhece a tec- [ Engenharia de Software ] Artigo dentro do contexto de [ Easy ] Com foco no desenvolvedor iniciante
nologia, mas tem dificuldade de implement-la em uma aplicao Engenharia de Software
cotidiana. Por exemplo, um artigo que ao invs de debulhar todos [ Mini-Curso ] Artigo que faz parte de um mini-curso
os mtodos e propriedades de um Recordset, mostre como usar o [ Web ] Artigos sobre ou que envolvam tcnicas de
Recordset de forma inteligente. para criar um carrinho de compras. desenvolvimento para WEB. [ Tutorial ] Artigo no estilo tutorial passo a passo

Edio 94 - ClubeDelphi 3

00 - Editorial.indd 3 25.03.08 16:57:19


ClubeDelphi EDITORIAL
Ano 8 - 94 Edio - 2008 - ISSN 1517990-7 Impresso no Brasil O DataSetProvider tem uma importante funo no ciclo de vida da manipulao
de dados em uma aplicao Delphi. Ele responsvel por se comunicar
Corpo Editorial com o engine (dbExpress por exemplo), obter os dados, empacot-los nos
chamados DataPackets e envi-los atravs da memria para o ClientDataSet
Editor Geral (em uma aplicao 2-tier) ou atravs da interface IAppServer em uma aplicao
Guinther Pauli multicamadas (SOAP, COM+ etc.). O DataSetProvider faz muito mais do que isso,
guinther@devmedia.com.br
e expe muitas de suas funcionalidades na forma de propriedades e eventos,
Editor Tcnico como mostra o Adriano Santos em seu completo artigo sobre o assunto.
Adriano Santos Falando em DataSetProvider, seu irmo ClientDataSet tambm exerce
adrianosantos@devmedia.com.br importante funo em aplicaes de banco de dados. Um dos problemas
Equipe Editorial relacionados a esse componente, e que confunde muitos, a correta manipulao
Fabricio Desbessel, Maikel Scheid, Paulo Quicoli, Luciano Pimenta de erros gerados no SGBD (Firebird por exemplo). No artigo do Rodrigo, veja
Editor de Arte como construir um descendente de ClientDataSet que automaticamente trata
Vinicius O. Andrade os principais erros do servidor, como violao de foreign-key.
viniciusoandrade@gmail.com Na seo Expert, o Gustavo Chaurais continua o artigo sobre Streams. Na
Diagramao parte final do seu artigo, veja como implementar compactao, download em
Adolfo Sabino mltiplos pacotes e resources em suas aplicaes. Ainda nesta seo, o
simininu@yahoo.com.br Marco e o Carma aprofundam um assunto muito importante, que na verdade
um desafio nos projetos de software: como mensurar o esforo e o prazo
Capa
Antonio Xavier
necessrio para desenvolver determinada aplicao, ajudando a reduzir
webdesigner@devmedia.com.br custos e no estropolar o cronograma.
O Maikel continua a srie que demonstra a construo de uma locadora
Reviso
Web. E nada melhor que o ASP.NET para construir um sistema completo desse
Gregory Monteiro
tipo. O Ricardo usa e abusa de seus conhecimentos sobre desenvolvimento
gregory@clubedelphi.net
com PocketStudio e continua seu excelente curso que mostra como criar uma
Distribuio aplicao para o sistema operacional PalmOS.
Fernando Chinaglia Dist. S/A Na sesso Easy Delphi, para quem est iniciando, temos o Maikel com dois
Rua Teodoro da Silva, 907 artigos: veja como utilizar os principais controles da VCL na construo de um
Graja - RJ - 206563-900
pequeno editor de textos, bem prtico. No outro artigo, mostra como utilizar os
componentes da paleta Indy para criar um sistema de envio de e-mails. ideal por
exemplo se voc precisar enviar e-mails automaticamente da sua aplicao.
Atendimento ao Leitor Para finalizar, o Rodrigo apresenta aquele que considero o melhor recurso da
A DevMedia conta com um departamento exclusivo para o atendi- POO, o polimorfismo, tudo em PHP! Se voc j domina ou conhece o assunto,
mento ao leitor. Se voc tiver algum problema no recebimento do seu sabe que ele realmente poderoso. Que tal utiliz-lo agora em suas aplicaes
exemplar ou precisar de algum esclarecimento sobre assinaturas, Web com o Delphi for PHP?
exemplares anteriores, endereo de bancas de jornal, entre outros,
entre em contato com: Grande abrao e sucesso com o Delphi!
Carmelita Mulin
www.devmedia.com.br/central/default.asp
(21) 3382-5025
Kaline Dolabella
Gerente de Marketing e Atendimento
kalined@terra.com.br Guinther Pauli
(21) 3382-5025
guinther@devmedia.com.br
Publicidade Microsoft Certified: MCP, MCAD, MCSD.NET
Para informaes sobre veiculao de anncio na revista ou no site Borland Certified: Delphi 6, 7, 2005, 2006, Web, Kylix
entre em contato com:
Kaline Dolabella
publicidade@devmedia.com.br

NO A
Portal do Assinante

C
PER
Fale com o Editor A ClubeDelphi tem uma novidade para voc que comprou este
exemplar na banca de jornal: voc pode acessar GRATUITAMENTE,
muito importante para a equipe saber artigo na revista ou no site ClubeDelphi, entre
o que voc est achando da revista: que em contato com os editores, informando o Portal do Assinante ClubeDelphi!
tipo de artigo voc gostaria de ler, que o ttulo e mini-resumo do tema que voc Confira o que voc encontra no Portal do Assinante:
artigo voc mais gostou e qual artigo gostaria de publicar:
- Mais de 560 Vdeo Aulas!
voc menos gostou. Fique a vontade
para entrar em contato com os editores - 7 cursos online!
e dar a sua sugesto! Guinther Pauli - Editor da Revista - 1 Livro Eletrnico sobre ADO.NET e BDP!
Se voc estiver interessado em publicar um guinther@devmedia.com.br - Mais de 150 Artigos Exclusivos!

Para Utilizar o Portal do Assinante, acesse www.devmedia.com.br/clubedelphi/potal.asp


Apoio e utilize as informaes abaixo: Login: DVM.PL e Senha: STX200

O acesso vlido por 30 dias a partida da data de lanamento da revista. Todos os


meses a ClubeDelphi lhe dar uma senha vlida para acessar o portal. Comprando a
A revista ClubeDelphi parte integrante da assinatura ClubeDelphi
PLUS. Para mais informaes sobre o pacote PLUS, acesse: revista regularmente em bancas, voc ter acesso ininterrupto a ele!
http://www.devmedia.com.br/clubedelphi/portal.asp
Informativo ClubeDelphi

Portal ClubeDelphi
+560 vdeo aulas e 7 cursos online
www.clubedelphi.net/portal

Caro Leitor
O portal ClubeDelphi PLUS a continuao, na Web, Acesse o portal ClubeDelphi PLUS e receba muito soais para acessar o portal. Se voc comprou em
da revista ClubeDelphi. O portal recebe um conte- mais contedo sobre Delphi! E o que melhor: de bancas, utilize o login e senha publicados na pgina
do novo todo dia e hoje conta com: i) mais de 560 graa! Todo leitor da revista ClubeDelphi, seja ele do editorial desta edio.
vdeo aulas; ii) 7 cursos online; iii) 1 livro eletrnico assinante ou comprador da revista em bancas, tem Confira a seguir as ltimas novidades do portal!
gratuito, de Guinther Pauli, sobre ADO.NET e BDP; iv) acesso ao portal (para quem compra em bancas, o
mais de 150 artigos exclusivos (que no foram pu- acesso vlido por 30 dias). Boa leitura e sucesso!
blicados na revista)!; Se voc assinante, utilize o seu login e senha pes- Equipe DevMedia

Brinde na web desta edio

1
Vdeo
Confira no portal ClubeDelphi PLUS um mini-curso sobre criao de um site com
ASP.NET e SQL Server 2005 Express
http://www.devmedia.com.br/articles/listcomp.asp?txtsearch=Delphi+e+SQL+Server+2005+Express

Gostou das vdeo aulas? O portal www.devmedia.com.br possui mais de 2 mil vdeo aulas e dezenas de
cursos online sobre desenvolvimento de software! Agora voc pode comprar as vdeo aulas que preferir e fazer
sua prpria combinao de vdeos! Saiba mais em www.devmedia.com.br/creditos

ltimas Vdeo-Aulas
Aprenda a desenvolver sistemas para o Desenvolvendo uma aplicao para PalmOS Construindo uma ferramenta de busca
sistema operacional PalmOS com PocketStucio - Parte XIII a XV de arquivos Parte I e II
Acompanhe as aulas de Ricardo Boaro que falam Veja nessas vdeo-aulas de Ricardo Boaro, como traba- Veja nessas vdeos de Paulo Quicoli como desen-
unicamente do desenvolvimento de aplicaes lhar com aplicaes PalmOS com o PocketStudio. volver uma podeorsa ferramenta para busca de
para PalmOS utilizando o IDE PocketStudio que arquivos no disco rgido.
bastante semelhate ao Delphi inclusive utilizan- Mini-Curso Controle de Verso com JEDI VCS
do-se de linguagem Pascal. Veja nesse mini-curso de Adriano Santos como
trabalhar com esta fabulosa ferramenta para con-
Curso Aplicao ASP.NET com Delphi e SQL Server trole de verso e gerenciamento de equipes.
2005 Express-Parte IV a X Testando a classe de
locao de fitas Como construir um WebServices com Delphi 7
Veja nessa vdeo aula de Luciano Pimenta as prin- Veja nessa vdeo aula de Guinther Pauli como de-
cipais diferenas de sintaxe para Stored Procedu- senvolver e trabalhar com WebServices usando o
res e Triggers entre FireBird e SQL Server 2005. Delphi 7.
Ask The Expert
Perguntas e Respostas
+460 vdeo aulas | 6 cursos online
Dvidas respondidas por Adriano Santos
(envie as suas para falecom@adrianosantos.pro.br)

Implementando Drag and Listagem 1. Declarao de mtodos na seo Private


Drop na aplicao ...
private
Ol Adriano, quando digitamos um { Private declarations }
function DragEnter(const dataObj: IDataObject;
texto no Word, selecionamos e depois grfKeyState: Longint; pt: TPoint;
var dwEffect: Longint): HResult; stdcall;
arrastamos para outro programa como o function DragOver(grfKeyState: Longint;
Bloco de Notas por exemplo, o texto co- pt: TPoint; var dwEffect: Longint): HResult; stdcall;
function DragLeave: HResult; stdcall;
lado. Gostaria de saber se possvel fazer function Drop(const dataObj: IDataObject;
grfKeyState: Longint; pt: TPoint; var dwEffect: Longint): HResult; stdcall;
essa implementao em meu sistema. function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
Andr Matheus public
...

Ol Andr, respondendo a sua questo: Listagem 2. Cdigos dos mtodos para interagir com o mundo externo
sim, possvel implementar isso em sua function TMemoDragDropFrm.DragEnter(const dataObj:
aplicao, mas o processo um tanto tra- IDataObject; grfKeyState: Longint; pt: TPoint;
var dwEffect: Longint): HResult;
balhoso. Vejamos como fazer isso. begin
dwEffect := DROPEFFECT_COPY;
Primeiramente devemos criar uma srie Result := S_OK;
end;
de funes capazes de interagir com o function TMemoDragDropFrm.DragOver(grfKeyState: Longint;
pt: TPoint; var dwEffect: Longint): HResult;
mundo externo, j que possibilitaremos begin
dwEffect := DROPEFFECT_COPY;
que o aplicativo receba o valor de um Result := S_OK;
texto vindo de outro aplicativo. Para isso end;
function TMemoDragDropFrm.DragLeave: HResult;
abra seu Delphi, salve o projeto e declare begin
Result := S_OK;
algumas funes na rea Interface da Unit end;
function TMemoDragDropFrm._AddRef: Integer;
como segue na Listagem 1. begin
Result := 1;
Pressione Ctrl + Shift + C para que o end;
function TMemoDragDropFrm._Release: Integer;
Delphi crie o cabealho das funes. Em begin
Result := 1;
seguida digite o cdigo de cada funo end;
conforme a Listagem 2. function TMemoDragDropFrm.Drop(const dataObj:
IDataObject; grfKeyState: Longint; pt: TPoint;
Por fim deemos alterar os eventos On- var dwEffect: Longint): HResult;
var
Create e OnDestroy do formulrio princi- aFmtEtc: TFORMATETC;
aStgMed: TSTGMEDIUM;
pal para se adaptarem s funes criadas. pData: PChar;
begin
Veja o cdigo na Listagem 3. if (dataObj = nil) then
raise Exception.Create(Ponteiro no vlido!);
Adicione a Unit ShellApi ao Uses do proje- with aFmtEtc do
to e por fim, insira um componente Memo begin
cfFormat := CF_TEXT;
na tela e execute o programa. Pra testar, ptd := nil;
dwAspect := DVASPECT_CONTENT;
abra o Word ou WordPad, digite alguma lindex := -1;
tymed := TYMED_HGLOBAL;
coisa, selecione e em seguida arraste-o end;
OleCheck(dataObj.GetData(aFmtEtc, aStgMed));
para o Memo do programa criado. Note try
pData := GlobalLock(aStgMed.hGlobal);
que o texto totalmente copiado. Memo1.Text := pData;
finally
GlobalUnlock(aStgMed.hGlobal);
ReleaseStgMedium(aStgMed);
end;
Result := S_OK;
end;

6 ClubeDelphi - Ask The Expert


Mudando fontes do programa de Listagem 3. Cdigo dos eventos OnCreate e OnDestroy
uma s vez procedure TMemoDragDropFrm.FormCreate(Sender: TObject);
Oi, gostaria de mudar todas as fontes begin
OleInitialize(nil);
do meu projeto automaticamente. Como OleCheck(RegisterDragDrop(Handle, Self));
end;
posso fazer isso?
Marcelo Jibas procedure TMemoDragDropFrm.FormDestroy(Sender: TObject);
begin
RevokeDragDrop(Handle);
OleUninitialize;
Ol Marcelo, uma alternativa para isso end;
seria criar uma funo que fizesse o
Listagem 4. Cdigo para modificao de fontes
servio pra ti. Essa funo teria que ser
implementada em todos os formulrios. procedure TForm1.ModificarFontes(AControle:
TWinControl);
Vejamos isso. procedure Modificar(AControle: TControl);
var
Crie um novo projeto no Delphi e na rea f: TFont;
private declare uma nova procedure como begin
if IsPublishedProp(AControle, Parentfont)
segue. and (GetOrdProp(AControle, Parentfont) =
.. Ord(False))
private and IsPublishedProp(AControle, font) then
procedure ModificarFontes( begin
AControle: TWinControl); f := TFont(GetObjectProp(AControle,
public font, TFont));
.. f.Name := Courier New;
end;
end;
Pressione Ctrl + Shift + C para que o var
i: Integer;
Delphi crie o cabealho da funo e em begin
seguida digite o cdigo da Listagem 4. Modificar(AControle);
for i := 0 to AControle.ControlCount - 1 do
No caso estamos fazendo um lao for if AControle.Controls[I] is TWinControl then
ModificarFontes(TWincontrol(AControle.
nos componentes do formulrio atual e Controls[I]))
utilizando os mtodos da Unit TypeInfo, else
Modificar(AControle.Controls[I]);
portanto declare a sua Unit no Uses do end;
Para utilizar a procedure basta incluir alguns controles em tela e em um boto fazer a
projeto. O nome da Unit TypInfo. chamada a ela, com mostrado a seguir:

procedure TForm1.Button1Click(Sender: TObject);


begin
D seu feedback sobre esta edio! Feedback ModificarFontes(Self);
eu
end;
s
D

A Java Magazine tem que ser feita ao seu


sobre e

gosto. Para isso, precisamos saber o que


s

ta
e
voc, leitor, acha da revista!
d i o

D seu voto sobre este artigo, atravs do link:


www.devmedia.com.br/javamagazine/feedback

Edio 94 - ClubeDelphi 7
Seo DELPHI Seo EASY DELPHI Seo PHP

Nesta seo voc encontra artigos intermedirios


sobre Delphi Win32 e Delphi .NET

Streams
Implemente compactao, download em mltiplos pacotes e resources em
suas aplicaes com tcnicas avanadas de Streams Parte 2

N
a edio anterior, iniciamos a finalmente, lemos o contedo do arqui-
criao de uma aplicao que vo atravs de um CopyFrom do stream
faz uso intensivo de streams temporrio.
(Edio 93), que implementa compac- Na Listagem 2 podemos ver a imple-
tao, download em mltiplos pacotes mentao de outro mtodo importante,
e resources. Desta vez, utilizaremos ReadEntry. Estamos apenas lendo uma
um stream temporrio para escrever o entrada e descartando-a caso WriteResult
arquivo que estamos lendo. Note que seja false. Para finalizar, vejamos o mto-
estamos utilizando GetDestStream e do Delete descrito na Listagem 3.
CleanDestStream para isso (veja ltima Este provavelmente o mtodo mais
listagem da edio anterior). Portanto, complicado da classe. Vamos precisar
poderemos estender essa classe futura- de um stream temporrio que ser, na
mente para gerar a sada em um stream verdade, o mesmo arquivo final, s que
Gustavo Chaurais qualquer, no s em arquivos. Seguem sem o arquivo deletado. Tivemos de fazer
(gustavoc@macrovision.com) suas implementaes (no se esquea da isso porque, ao deletarmos o arquivo no
Borland Delphi 7 Advanced Certified, Borland
diretiva virtual neles. Veja na Listagem 1 mesmo stream, depois no conseguimos
Delphi 2005 for Win32 Certified, Borland Del-
phi 2006 for Win32 Certified e Borland Delphi a implementao das funes GetDestS- reduzir o seu size para o tamanho novo
Instructor Certified. Foi palestrante das trs tream e CleanDestStream. (menor). Esse o comportamento padro
ltimas edies da Borland Conference Brasil Seu funcionamento tambm bsico: de um TCompressionStream.
e de outros grandes eventos nacionais. Alm descartamos do arquivo Index 1 entra- O primeiro passo ser ento copiar
disso, membro da coordenadoria do GIES-
das para posicionar o cursor do stream para este arquivo novo todas as entradas
SC. Hoje, ministra cursos, presta consultoria
e atua como Software Engineer do projeto de leitura; depois lemos o tamanho do at a de nmero Index (ReadEntry(True)).
InstallAnywhere para a empresa norte-ame- nome, o nome e o tamanho do arquivo, D e p o i s ig n ora mo s u m a e nt rad a
ricana Macrovision Corporation. tambm para posicionar o cursor; e, (ReadEntry(False)) e copiamos o resto do

8 ClubeDelphi - Streams
EXPERT

arquivo (CopyEntireStream). Em seguida, Listagem 1. Mtodos GetDestStream e CleanDestStream


substitumos o arquivo final atual pelo
function TCompressor.GetDestStream(const DestFilePath:
novo e repopulamos as entradas, pois string): TStream;
estas foram modificadas. begin
Result := TFileStream.Create(DestFilePath, fmCreate);
Pronto. Isso tudo o que precisvamos end;
procedure TCompressor.CleanDestStream(const DestStream: TStream);
para termos uma classe totalmente fun- begin
DestStream.Free;
cional com compactao para mltiplos end;
arquivos. Agora precisamos construir
uma interface com o usurio. Listagem 2. Mtodo ReadEntry

procedure TCompressor.ReadEntry(WriteResult: Boolean);


Criando um exemplo completo de var
Buffer: TBuffer;
compactao NameLength: Integer;
begin
No projeto atual, voc deve ter ignora- FStreamRead.Read(Buffer, 4);
if WriteResult then
do o Form padro, gerado pelo Delphi. FStreamWrite.Write(Buffer, 4);
NameLength := BinToInt(CopyFromBuffer(Buffer, 4));
Agora, volte a ele, mude seu nome para FStreamRead.Read(Buffer, NameLength);
fmCompression e adicione um com- if WriteResult then
FStreamWrite.Write(Buffer, NameLength);
ponente TToolBar. A este, adicione cinco FStreamRead.Read(Buffer, 8);
if WriteResult then
TToolButtons (tbNew, tbOpen, tbA- FStreamWrite.Write(Buffer, 8);
ReadFile(BinToInt64(CopyFromBuffer(Buffer, 8)), WriteResult);
dd, tbRemove e tbExtract). Adicione end;
tambm um TDBGrid(dbgEntries), Listagem 3. Mtodo Delete
um TClientDataSet (cdsEnt r ies),
procedure TCompressor.Delete(Index: Integer);
um TDataSource (dsEntries), dois var
i: Integer;
TOpenDialogs(OpenDialog e AddFile- ATempStream: TFileStream;
Dialog) e um TSaveDialog(SaveDialog). begin
RestartStream(fmOpenRead);
Opcionalmente, adicione um TImageList try
ATempStream := TFileStream.Create(FFilePath + .tmp, fmCreate);
para adicionar imagens ao TToolBar. try
Configure dbgEntries, apontando-o FStreamWrite := TCompressionStream.Create(clMax, ATempStream);
FStreamRead := TDecompressionStream.Create(FInternalStream);
para dsEntries e este para o cdsEntries. for i := 0 to Index - 1 do
ReadEntry(True);
Na propriedade Options de dbgEntries, ReadEntry(False);
CopyEntireStream;
acrescente dgMultiSelect. Adicione o finally
seguinte filtro aos componentes Open- CloseStreams;
ATempStream.Free;
Dialog e SaveDialog: ClubeDelphi Zip end;
finally
File (*.cdz)|*.cdz. Seu filtro inicial deve CloseStreams;
end;
ser configurado para *.cdz. D tambm DeleteFile(FFilePath);
um ttulo aos dilogos. Adicione a opo RenameFile(FFilePath + .tmp, FFilePath);
RestartStream(fmOpenRead);
ofAllowMultiSelect propriedade Options FStreamRead := TDecompressionStream.Create(FInternalStream);
try
do componente AddFileDialog. PopulateEntries;
finally
Abra o Fields Editor do componente cd- CloseStreams;
sEntries e adicione os seguintes campos: end;
end;
PATH (string - size: 256), FILE_SIZE
(largeint) e ENTRY_INDEX (integer - visi-
ble: False). Agora clique com o boto direito na seo private da classe TfmCompression ser implementado da mesma maneira.
em cdsEntries e selecione Create DataSet. e vamos implementao do mtodo Re- Porm, troque SaveDialog por OpenDia-
O componente cdsEntries armazenar loadEntries conforme a Listagem 4. log e de True para False na construo
as entradas do TCompressor. Estamos Este mtodo muito simples, estamos de FCompressor. Agora, uma vez criado
utilizando um TClientDataSet com dados apagando os dados de cdsEntries e adi- FCompressor, necessrio destru-lo. Fa-
em memria pela facilidade em se tra- cionando a ele todas as entradas do com- remos isso atravs do evento OnDestroy
balhar com os dados e com o TDBGrid. pressor. Alm de estarmos controlando do formulrio:
Opcionalmente, voc pode configurar a atualizao do dbgEntries atravs dos
if Assigned(FCompressor) then
a propriedade IndexFieldNames do cd- mtodos DisableControls e EnableControls. FreeAndNil(FCompressor);
sEntries para PATH para ordenar as Vamos implementar as operaes New
entradas por este campo. Posicione os e Open. Para isto, manipule o evento Finalmente, vamos as outras operaes.
componentes conforme a Figura 1. OnClick do boto tbNew de acordo com Comecemos pelo Add. Portanto manipu-
Antes da implementao de qualquer a Listagem 5. le o evento do boto tbAdd seguindo a
evento, declare FCompressor (TCompressor) O evento OnClick do boto tbOpen deve codificao prevista na Listagem 6.

Edio 94 - ClubeDelphi 9
Mais um mtodo bastante simples, no
Listagem 4. Cdigo do mtodo ReloadEntries
qual passamos ao FCompressor todos os
procedure TfmCompression.ReloadEntries;
var arquivos a serem adicionados. Para a
i: Integer; operao de Extract, implemente o evento
Entry: TCompressionEntry;
begin OnClick do boto tbExtract (Listagem 7)
cdsEntries.DisableControls;
cdsEntries.EmptyDataSet; A funo SelectDirectory no muito
try
for i := 0 to FCompressor.EntriesCount - 1 do
conhecida. Esta serve para que o usu-
begin rio possa selecionar um diretrio,
Entry := FCompressor.Entries[i];
como um dilogo qualquer. Passamos
cdsEntries.Append;
cdsEntriesPATH.AsString := Entry.Path; o Caption, o diretrio inicial e para
cdsEntriesFILE_SIZE.AsLargeInt := Entry.
FileSize;
onde enviar o diretrio selecionado.
cdsEntriesENTRY_INDEX.AsInteger := i; Ento, para cada linha selecionada no
cdsEntries.Post;
end; dbgEntries estamos chamando o m-
finally
cdsEntries.EnableControls; todo Extract do compressor passando
end;
end;
o Index da entrada, armazenado no
mtodo ReloadEntries.
Listagem 5. Cdigo do boto Novo Novamente, o caso mais complicado.
procedure TfmCompression.tbNewClick(Sender: TObject); Manipule o evento OnClick do boto tbDe-
var
AFileName: string;
lete para usando o cdigo da Listagem 8.
begin Para entender o cdigo anterior, preci-
if SaveDialog.Execute then
begin samos pensar em uma operao na qual
AFileName := SaveDialog.FileName;
if Assigned(FCompressor) then esto sendo removidos vrios registros
FCompressor.Free; de uma coleo. Caso removamos um
FCompressor := TCompressor.Create(AFileName,True);
Caption := ExtractFileName(AFileName); registro e, posteriormente, tentemos re-
ReloadEntries;
end; mover outro de ndice maior, o segundo
end;
registro estar sendo removido de ma-
neira incorreta. Portanto, vamos fazer a
operao pegando do maior ndice a ser
removido para o menor.
Por facilidade, vamos utilizar um
TStringList para armazenar os ndices.
A primeira tarefa ento alimentar o
TStringList com os ndices das entradas a
serem removidas. A segunda compreen-
de procurar o prximo ndice mais alto
da lista, guard-lo e salvar sua posio
na coleo de ndices. Aps isso, deleta-
mos a entrada e a exclumos da coleo.
Quando todos os registros forem remo-
vidos, simplesmente carregamos todas
as entradas novamente.
Pronto. Nossa verso simplificada do
WinZip para trabalhar com arquivos .cdz
est pronta para ser utilizada. Voc pode
agora tentar adicionar outros recursos
como criptografia ao seu arquivo com-
pactado. Alm disso, como criamos uma
Figura 1. Interface grfica do projeto Compression classe, voc pode embutir essa ferramen-
ta em sua aplicao para transportar
arquivos com mais facilidade.

Trabalhando com Resources


Todo programa Windows de interface
grfica apresenta uma srie de recursos que
no so apenas cdigo compilado, como:

10 ClubeDelphi - Streams
EXPERT

cones, cursores, sons, imagens, dentre Listagem 6. Cdigo do boto Add


outros. O prprio Windows nos permite procedure TfmCompression.tbAddClick(Sender: TObject);
inserir, em nossos executveis, qualquer var
i: Integer;
tipo de arquivo. Estes podem ser compila- Entry: TCompressionEntry;
begin
dos em arquivos de recursos (.RES) e ento cdsEntries.DisableControls;
try
embutidos em uma aplicao. if AddFileDialog.Execute then
Esta a receita de bolo para a utilizao begin
for i := 0 to AddFileDialog.Files.Count - 1 do
de arquivos de recursos: begin
Entry := FCompressor.Add(AddFileDialog.
1. Criamos um arquivo .RC, referencian- Files[i]);
cdsEntries.Append;
do os arquivos que iro constar no .RES; cdsEntriesPATH.AsString := Entry.Path;
2. Compilamos o arquivo .RC para .RES; cdsEntriesFILE_SIZE.AsLargeInt := Entry.
FileSize;
3. No Delphi, utilizamos a diretiva {$R cdsEntriesENTRY_INDEX.AsInteger := FCompressor.
EntriesCount - 1;
Arquivo.RES} para importar o arquivo cdsEntries.Post;
end;
de recursos; end;
4. Fazemos uso da classe TResourceStre- finally
cdsEntries.EnableControls;
am para a leitura dos arquivos. end;
end;

Nosso primeiro exemplo um clssico Listagem 7. Cdigo do boto de extrao


da customizao dos recursos de uma procedure TfmCompression.tbExtractClick(Sender: TObject);
aplicao. Certamente, se nunca utilizou, var
ExtractTo: string;
ir utiliz-lo um dia em sua aplicao. i: Integer;
begin
muito comum fazermos uso de biblio- if SelectDirectory(Extract to, c:\, ExtractTo)
then
tecas externas ao nosso programa. Con- begin
cdsEntries.DisableControls;
tudo, o fato de termos de distribu-las try
junto ao nosso executvel nos incomoda for i := 0 to dbgEntries.SelectedRows.Count-1 do
begin
bastante. Portanto, vamos inclu-las em cdsEntries.GotoBookmark(Pointer(dbgEntries.
SelectedRows.Items[i]));
nossa aplicao. Deste modo, podera- FCompressor.Extract(cdsEntriesENTRY_INDEX.
AsInteger, ExtractTo);
mos embutir tambm o executvel final end;
finally
e extrair todos eles antes da execuo cdsEntries.EnableControls;
propriamente dita. end;
end;
Crie (com o prprio bloco de notas) um end;

arquivo com a extenso .RC no disco


Listagem 8. Cdigo para remoo de arquivo
(por exemplo: Recursos.RC na pasta da
aplicao). Seu contedo ficaria parecido procedure TfmCompression.tbRemoveClick(Sender: TObject);
var
com o seguinte: i: Integer;
ToRemove: TStrings;
EntryIndexToRemove, iToRemove: Integer;
DLL DLLFILE caminho_para_biblioteca.dll begin
cdsEntries.DisableControls;
ToRemove := TStringList.Create;
A primeira coluna contm a chave que try
identificar o arquivo como recurso e for i := 0 to dbgEntries.SelectedRows.Count-1 do
begin
poder ser representada por qualquer cdsEntries.GotoBookmark(Pointer(dbgEntries.
SelectedRows.Items[i]));
palavra. A segunda coluna contm o ToRemove.Add(cdsEntriesENTRY_INDEX.AsString);
end;
tipo de arquivo. Os mais comuns so: while ToRemove.Count > 0 do
begin
BITMAP, ICON, CURSOR, JPEG, WAVE, EntryIndexToRemove := -1;
TEXT e RCDATA (genrico). A terceira iToRemove := -1;
for i := 0 to ToRemove.Count - 1 do
coluna contm o caminho (absoluto ou begin
if StrToInt(ToRemove[i])>EntryIndexToRemove
relativo) para o arquivo. Lembre-se de then
begin
que inmeras linhas (entradas) podem iToRemove := i;
ser adicionadas ao arquivo .RC. Aponte EntryIndexToRemove := StrToInt(ToRemove[i]);
end;
para qualquer biblioteca em seu sistema end;
FCompressor.Delete(EntryIndexToRemove);
para testar. ToRemove.Delete(iToRemove);
end;
Com o fonte .RC pronto, devemos finally
cdsEntries.EnableControls;
compil-lo para um .RES. Para isso, voc ToRemove.Free;
pode utilizar o programa BRCC32.exe, na end;
ReloadEntries;
pasta bin do Delphi. Abra uma linha de end;

comando e digite:

Edio 94 - ClubeDelphi 11
[caminho para a pasta bin]\brcc32.exe ge. O TResourceStream muito parecido mtodos especiais: SaveToFile e SaveToS-
[arquivo .RC]
com o TMemoryStream e necessita de tream. Isso muito til porque no preci-
Na pasta atual ser gerado um arquivo trs parmetros para sua construo. O samos de um TFileStream para salvar seu
.RES com o mesmo nome de seu fonte primeiro o HModule, ou seja, o handle contedo. O mtodo SaveToFile j faz isso
.RC. Crie um novo projeto e salve-o do mdulo retornado no carregamento para ns. E esta a operao presente em
como ResourceDLL.dpr. Na unit do de uma aplicao/DLL. No caso, o ar- nosso exemplo. Estamos simplesmente
formulrio principal, digite: quivo de recursos foi compilado junto criando o stream e chamando seu mtodo
aplicao corrente, portanto, utiliza- SaveToFile. Muito simples, no?
{$R caminho_para_o_arquivo_de_recurso_
compilado.RES} remos HInstance. No caso de querermos Como dica, podemos utilizar o plug-in
carregar recursos de outras aplicaes Simple Resource Editor (Figura 2), de minha
Adicione um boto ao formulrio e passaramos o HModule da aplicao autoria, para a manipulao dos arqui-
implemente seu evento OnClick igual a desejada. O segundo parmetro a cha- vos .RC. Com ele voc pode facilmente
Listagem 9. Inicie o programa e clique no ve que identifica o recurso, informada adicionar novos arquivos (buscando-os
boto. A DLL ser extrada para a mesma no .RC. E o terceiro o tipo de recurso, por dilogos especiais), compilar para
pasta, com o nome extracted.dll. tambm informado no .RC. arquivos .RES, dentre outras funciona-
Relembrando o conceito de streams do A classe TResourceStream, bem como lidades bastante teis. O assistente lhe
incio do artigo, finalmente fechamos as o TMemoryStream, herdam de TCustom- ajuda inclusive a, rapidamente, selecio-
principais classes que o assunto abran- MemoryStream. Esta ltima introduz dois nar o tipo de recurso a ser adicionado.
Seu download pode ser feito atravs
do CodeCentral da CodeGear (cc.codegear.
Listagem 9. Cdigo do boto de extrao dos recursos
com), procurando-se pelo autor Gustavo
procedure TForm1.Button1Click(Sender: TObject); Chaurais. Seu cdigo fonte est incluso e
var
Stream: TResourceStream; muito interessante para estudo.
const
EXTRACTED_DLL_NAME = extracted.dll;
begin
www.devmedia.com.br/clubedelphi/portal.asp
Stream := TResourceStream.Create(HInstance, DLL,
DLLFILE);
try Acesse agora o mesmo o portal do assinante ClubeDelphi e assista a uma
Stream.SaveToFile(EXTRACTED_DLL_NAME);
vdeo aula de Adriano Santos que mostra como trabalhar com o plug-in
MessageDlg(Arquivo extrado para: +
IncludeTrailingPathDelimiter(ExtractFilePath( Simple Resource Editor.
Application.ExeName)) + EXTRACTED_DLL_NAME,
mtInformation, [mbOk], 0); www.devmedia.com.br/articles/viewcomp.asp?comp=5476&hl=
finally
FreeAndNil(Stream);
end;
end;
Vamos agora misturar um pouco as
coisas. Construiremos um exemplo que
utilizar um arquivo comprimido atra-
vs do exemplo Compression.
Crie um novo projeto e salve-o como
ResourceZip.dpr. Adicione a ele uma nova
Unit e salve-a como ResCompressor.pas.
Adicione tambm a Unit Compressor.pas,
construda anteriormente.
Na seo Uses de ResCompressor, insira:
Compressor, Classes, SysUtils e Windows.
Agora, declare uma classe TResCompres-
sor, estendendo TCompressor. Declare e
implemente o seguinte mtodo (com a
diretiva reintroduce):

constructor TResCompressor.Create(const
ResName:
string);
begin
FResName := ResName;
inherited Create(, False);
end;

E declare FResName na seo private


como sendo do tipo string. Declare tam-
Figura 2. Simple Resource Editor bm e implemente o seguinte mtodo:

12 ClubeDelphi - Streams
EXPERT

procedure TResCompressor. Agora, vamos construir nosso arquivo E, se voc ainda no cansou de exem-
ExtractToStream(Index:
Integer; const ExtractTo: TStream); de recursos. Abra o programa Compres- plos, vamos finalizar com um muito
begin
FDestStream := ExtractTo; sion e crie um arquivo contendo algumas pouco conhecido: como alterar resources
inherited Extract(Index, );
end;
figuras do tipo jpg. Crie um arquivo .RC de outras aplicaes.
e adicione a ele a seguinte linha: Ainda no exemplo anterior, adicione a
Adicione tambm FDestStream seo seguinte linha na seo Interface da Unit
IMAGESZIP RCDATA caminho_para_arquivo_
private da classe. Este mtodo ser utili- compactado.cdz do formulrio:
zado para extrairmos um resource para
resourcestring
um stream qualquer. Compile o .RC para um .RES e o refe- TITLE = not changed;
Voc se lembra dos trs mtodos rencie no formulrio principal, atravs da
virtuais da classe TCompressor? Pois, diretiva {$R Arquivo.RES}. Adicione ao for- Resource Strings so como constantes. No
tenha certeza de que no esto na seo mulrio principal da aplicao um TPaint- entanto, podemos modificar seu contedo
private da classe TCompressor (devem Box (aba System). Na sua Unit, insira jpeg na utilizando programas que alterem resour-
estar preferencialmente em protected) e seo Uses e manipule o evento OnCreate ces como o Resource Hacker ou o Workshop
redeclare-os na classe TResCompressor digitando o cdigo da Listagem 10. Editor. Essas so muito utilizadas em
com a diretiva override. O atributo de O que este mtodo est fazendo se programas que desejamos internaciona-
TCompressor, FInternalStream, tambm refere criao de um TResCompressor, lizar, pois podemos alterar seu contedo
deve ser colocado preferencialmente na o qual ir carregar o .RES, contendo o para outra lngua sem ter de recompilar a
sua seo protected. arquivo das figuras compactado. Aps aplicao toda. Adicione como primeira
O mtodo RestartStream deve ser utili- sua abertura, podemos chamar seu linha do manipulador do evento OnCreate
zado para a inicializao do stream inter- mtodo ExtractToStream passando um do formulrio o seguinte:
no. Portanto, o inicializaremos como um ndice aleatrio. Finalmente, carregamos
Caption := TITLE;
TResourceStream conforme segue: figura em FJpeg (declare-a na classe do
formulrio). Utilizamos um TMemoryS- Crie um novo projeto e salve-o como
procedure TResCompressor.RestartStream(
Mode: Word); tream para carreg-la. Agora, no evento ResourceUpdate.dpr. No formulrio
begin
FInternalStream := TResourceStream.Create( OnPaint do TPaintBox, implemente o principal, adicione: trs TLabel, trs
HInstance, FResName, RT_RCDATA); cdigo seguinte. TEdit(edProgram, edResKey e edVa-
end;
lue), trs TButton(btList, btRCDATA
procedure TForm1.PaintBox1Paint(Sender:
O mtodo GetDestStream utilizado para TObject); e btString) e um TMemo(mmList).
begin
a inicializao de uma string onde ser if Assigned(FJpeg) then Posicione os componentes e configure
PaintBox1.Canvas.Draw(0, 0, FJpeg);
gravado o arquivo extrado. Neste caso, end;
seus Captions conforme a Figura 3.
quando for chamado o mtodo Extract- Vamos iniciar pela listagem dos re-
ToStream, o stream desejado ser gravado Pronto. Agora, toda vez que voc entrar cursos. Implemente o tratamento para
localmente em FDestStream. Podemos no programa, uma figura aleatria de o evento OnClick do btList observando o
ento simplesmente retorn-lo. Veja: sua lista ser carregada no TPaintBox. cdigo da Listagem 11.
function TResCompressor.GetDestStream(const Voc pode utilizar isso no splash screen Estamos, primeiramente, utilizando
DestFilePath: string): TStream; de sua aplicao, por exemplo. a funo LoadLibraryEx para carregar
begin
Result := FDestStream;
end;
Listagem 10. Cdigo OnCreate do formulrio
E, uma vez que o stream veio de fora para
procedure TForm1.FormCreate(Sender: TObject);
o ExtractToStream, no nossa responsa- var
bilidade limp-lo. Provavelmente, quem AResCompressor: TResCompressor;
AIndex: Integer;
chamou o mtodo vai querer ler o que foi AMemoryStream: TStream;
begin
extrado. Portanto, o mtodo CleanDestS- AResCompressor := TResCompressor.Create(IMAGESZIP);
try
tream ficar vazio. Note a seguir: AMemoryStream := TMemoryStream.Create;
try
procedure TResCompressor. Randomize;
CleanDestStream(const AIndex := RandomRange(0, AResCompressor.EntriesCount);
DestStream: TStream); AResCompressor.ExtractToStream(AIndex, AMemoryStream);
begin
end; AMemoryStream.Position := 0;
FJpeg := TJpegImage.Create;
Para fechar esta classe, voc pode, op- FJpeg.LoadFromStream(AMemoryStream);
finally
cionalmente, disparar uma exceo caso AMemoryStream.Free;
end;
sejam chamados os mtodos Add, Delete finally
AResCompressor.Free;
e Extract. Para tanto, declare-os como end;
virtual na classe TCompressor e override end;

na classe TResCompressor.

Edio 94 - ClubeDelphi 13
o programa. Esta funo pode ser exe- O mtodo implementado, conforme co-
cutada tanto para bibliotecas quanto mentado, ser chamado para cada recurso
executveis e retorna o handle do m- encontrado. Se o recurso for um RCDATA,
dulo. Aps isso, chamamos o mtodo apenas adicionamos na lista o nome do
EnumResourceNames, uma vez para o recurso. Caso seja um String Table, var-
tipo RCDATA e uma vez para o tipo remos a tabela lendo cada string atravs
STRING. Passamos tambm um pon- do mtodo LoadString. Para pegarmos o
teiro para a funo que ser chamada nome de recurso da tabela, utilizamos a
para cada recurso (@EnumResNames- funo LoWord, pois, nos interessa apenas
Proc) e um ponteiro para a lista de os bytes menos significativos.
strings do mmList. A lista j est pronta para ser preen-
Feito isso, declare (logo acima do m- chida. Voc ver primeiro os recursos
todo recm implementado, sem ser da RCDATA do aplicativo e, depois, os re-
classe TForm1) a funo EnumResNma- cursos do tipo String Table. No segundo
esProc (Listagem 12). caso, aparecer tambm a chave identi-
Quando o recurso for do tipo string, na ficadora de cada string.
verdade, ele ser um StringTable. Essas Agora, declare e implemente o mtodo
tabelas so a maneira que strings so UpdateResourceInProgram (Listagem 13).
adicionadas aos arquivos de recurso. Este o mtodo que ser utilizado
Em cada uma, teremos at 16 strings. para a modificao efetiva dos resources.
Cada string identificado por uma cha- Ele consiste em chamarmos BeginU-
ve prpria, que calculada da seguinte pdateResource para iniciar a alterao, o
forma: ([NOME DO RECURSO] 1) * qual nos retorna o Handle do programa.
16. Posteriormente, podemos utilizar a Se a alterao for do tipo RCDATA,
funo LoadString passando esta chave iniciamos um stream para a leitura do
Figura 3. Interface do exemplo ResourceUpdate para lermos cada string. arquivo que ir substituir o recurso
atual; reservamos memria para todo
este valor (note que o arquivo ser
Listagem 11. Cdigo do evento OnClick do boto btList totalmente carregado em memria);
procedure TForm1.btListClick(Sender: TObject);
lemos o arquivo no buffer e, por fim,
var chamamos UpdateResource. Este o
AHandle: THandle;
begin mtodo que ir modificar o recurso e,
mmList.Clear;
AHandle := LoadLibraryEx(PChar(edProgram.Text), 0, LOAD_LIBRARY_AS_DATAFILE); para ele, devemos passar: o Handle da
try aplicao a modificar, o tipo de recur-
mmList.Lines.Add(RCDATA RESOURCES);
EnumResourceNames(AHandle, RT_RCDATA, @EnumResNamesProc, Integer(mmList.Lines)); so, o nome do recurso ( interessante
mmList.Lines.Add();
mmList.Lines.Add(STRING TABLES); utilizar a funo MakeIntResource para
EnumResourceNames(AHandle, RT_STRING, @EnumResNamesProc, Integer(mmList.Lines));
finally a formatao do valor), a linguagem do
FreeLibrary(AHandle); recurso (0 = Neutral), o buffer com os
end;
end; bytes e o tamanho a ser gravado.
Caso estejamos interessados na altera-
Listagem 12. Funo EnumResNamesProc
o de uma string, chamamos o mtodo a
function EnumResNamesProc(Module: HMODULE; ResType, ResName: PChar; ser implementado GetStringTable e grava-
Strings: TStrings): Boolean; stdcall;
var mos, agora, toda a String Table novamente
InitialString, i: Integer;
Buffer: array[0..1023] of Char; na posio correta (retornada por GetRes-
begin
if ResType = RT_STRING then NameOfStrId. Para aplicar as atualizaes,
begin chamamos EndUpdateResource.
InitialString:=(LoWord(Cardinal(ResName))-1) * 16;
for i := 0 to 15 do Finalmente, implemente os mtodos
begin
if LoadString(Module,InitialString+i, relacionados construo do String Table
Buffer,1024) <> 0 then
Strings.Add(> + IntToStr(InitialString + i)
conforme a Listagem 14.
+ - + string(Buffer)); Para a montagem do String Table,
end;
end necessrio lermos todas as strings
else if ResType = RT_RCDATA then
begin novamente, adicionando-as na tabela
Strings.Add(> + ResName);
end;
e alterando somente a string desejada.
Result := True; Perceba que as strings esto presentes
end;
na tabela da seguinte forma: [LENG-

14 ClubeDelphi - Streams
EXPERT

TH][STRING]. O clculo da posio


Listagem 13. Mtodo UpdateResourceInProgram
inicial feito com base no nome do
procedure TForm1.UpdateResourceInProgram(const recurso correspondente String Table
ResType: PChar);
var em questo. J o Offset representa a
TempStream: TStream;
ResHandle: THandle; posio da string a ser alterada na
Buffer: PChar;
StringTable: WideString; tabela. Para finalizar, devemos gerar
begin o mesmo nmero de caracteres nulos
ResHandle := BeginUpdateResource(PChar(
edProgram.Text), False); correspondentes ao tamanho gerado.
try
if ResType = RT_RCDATA then Assim, fechamos a construo de um
begin
TempStream := TFileStream.Create(
String Table completo. J o mtodo Ge-
edValue.Text, fmOpenRead); tResNameOfStrId um simples clculo
try
GetMem(Buffer, TempStream.Size); para se saber o resource name do String
TempStream.Read(Buffer^, TempStream.Size);
UpdateResource(ResHandle, RT_RCDATA, Table com base no id de um string.
MakeIntResource(edResKey.Text), 0,
Buffer, TempStream.Size);
Teste seu programa apontando para o
finally executvel anteriormente criado Resour-
TempStream.Free;
end; ceZip.exe e clicando em btList. Voc ver a
FreeMem(Buffer); lista com os recursos do programa. Para
end
else if ResType = RT_STRING then
alterar um string, coloque no segundo
begin TEdit o id da string (copie da lista) e d
StringTable := GetStringTable(StrToInt(
edResKey.Text), edValue.Text); um novo valor. Por exemplo, procure
UpdateResource(ResHandle, RT_STRING,
MakeIntResource(GetResNameOfStrId(StrToInt( por not changed, correspondente ao
edResKey.Text))), 0, PWideChar(StringTable), resourcestring anteriormente adicionado,
Length(StringTable));
end; mude seu valor e execute o programa.
finally
EndUpdateResource(ResHandle, False); Voc ver que a string foi modificada
end;
end; com sucesso, atravs da barra de ttu-
los. Gere tambm outro arquivo .cdz
Listagem 14. Implementao dos mtodos GetStringTable e GetResNameOfStrId com diferentes figuras jpeg e faa uma
function TForm1.GetStringTable(StrId: Integer; const modificao apontando para o nome do
NewValue: string): WideString;
var recurso (IMAGESZIP) e para o caminho
ResName: Integer; ao arquivo .cdz. Abra o programa e voc
Offset: Integer;
StartPos: Integer; ver as imagens novas.
i: Integer;
AHandle: THandle;
Buffer: array[0..1023] of Char;
StrRead: string; Concluso
begin Por mais que achemos que sabemos
ResName := GetResNameOfStrId(StrId);
Offset := StrId mod 16; tudo, sempre h algo para aprender.
StartPos := (ResName - 1) * 16;
Result := ; Streams no so um contedo difcil,
AHandle := LoadLibraryEx(PChar(edProgram.Text), 0,
LOAD_LIBRARY_AS_DATAFILE);
porm, necessitam ser exercitados. Alm
try disso, aumentamos um pouco mais
for i := 0 to 15 do
begin nosso arsenal de possibilidades, com
if i = Offset then
begin a utilizao de poderosos compactado-
Result := Result + Char(Length(NewValue)) +
NewValue;
res de arquivos e arquivos de recurso
end bastante flexveis. Agora, s esperar a
else
begin oportunidade certa para aplicar o que foi
if LoadString(AHandle, StartPos + i, Buffer,
1024) <> 0 then explicado em um cenrio real.
begin
StrRead := string(Buffer);
Result := Result + Char(Length(StrRead)) +
StrRead;
end;
end;
end; D seu feedback sobre esta edio! Feedback
eu
s

Result:= Result + StringOfChar(#0,Length(Result));


D

finally
A Java Magazine tem que ser feita ao seu
sobre e

FreeLibrary(AHandle);
end; gosto. Para isso, precisamos saber o que
s

end;
ta
edio
function TForm1.GetResNameOfStrId(StrId: voc, leitor, acha da revista!
Integer): Integer;
begin D seu voto sobre este artigo, atravs do link:
Result := (StrId div 16) + 1;
end;
www.devmedia.com.br/javamagazine/feedback

Edio 94 - ClubeDelphi 15
Seo DELPHI Seo EASY DELPHI Seo PHP

Nesta seo voc encontra artigos intermedirios


sobre Delphi Win32 e Delphi .NET

Anlise de Pontos de Funo


Saiba mensurar o tamanho de seu software e estimar o tempo que levar
para ficar pronto

U
m dos grandes desafios atual- como a Anlise de Pontos de Funo (do
mente em projetos de software ingls FPA - Function Point Analysis).
garantir que estimativas de Dessa forma, pode-se estimar o tama-
tamanho, custo e cronograma sejam nho das funcionalidades de um sistema
realistas, tanto em projetos de desen- e, em funo disso, definir o tempo
Carmo Crdiney de Melo volvimento quanto de manuteno. e recursos para o projeto em questo
(carmo@jfnet.com.br) Entretanto, as crescentes necessidades com base na produtividade da equipe
Possui experincia desde 1990 em Tecnolo-
dos usurios, a alta complexidade e ou na taxa de entrega de projetos se-
gia da Informao. Bacharel em Sistemas de
Informao pela Faculdade Metodista Gran- baixo entendimento do domnio das melhantes. Essas estimativas definidas
bery (FMG). Acumula sete anos de estudos aplicaes a serem construdas, aliadas no incio do projeto so determinantes
acadmicos na rea de tecnologia e na rea s constantes mudanas tecnolgicas, para planejar as suas iteraes, prever o
de Gesto de Projetos. Possui capacitao em promovem um alto grau de incerteza custo e elaborar o oramento detalhado
Rational Unified Process (RUP), Arquitetura
nas estimativas para o cumprimento das do projeto, minimizando os riscos que
J2EE, Linux, Gesto de Projeto de Tecnologia e
Anlise de Pontos de Funo. metas estabelecidas. o projeto termine fora do prazo ou do
Como resultado, os desenvolvedores tm oramento previsto.
enfrentado problemas de subestimativas, Assim, o objetivo deste artigo descre-
Marco Antnio Pereira Arajo
culminando em atrasos no cronograma e ver como obter o tamanho de sistemas
(maraujo@granbery.edu.br)
Professor do Curso de Bacharelado em Sis- descumprimento de oramentos. Por outro atravs da tcnica de contagem de Pontos
temas de Informao da Faculdade Metodista lado, entende-se que os usurios tambm de Funo, atravs de um prottipo de
Granbery, Doutorando e Mestre em Engenharia precisam de respostas rpidas em relao interface de uma aplicao de exemplo.
de Sistemas e Computao pela COPPE/UFRJ, ao tempo e custos envolvidos em projetos No se tem a pretenso de apresentar
Especialista em Mtodos Estatsticos Compu-
de software. No sentido de obter estima- todas as regras de FPA, mas introduzir
tacionais e Bacharel em Matemtica com Ha-
bilitao em Informtica pela UFJF, Analista de tivas mais confiveis, necessita-se lanar os conceitos bsicos para a contagem em
Sistemas da Prefeitura de Juiz de Fora. mo de tcnicas especficas para esse fim, projetos de desenvolvimento.

16 ClubeDelphi - Anlise de Pontos de Funo


EXPERT

O estudo de caso apresentado neste Contagem de Pontos de Funo A partir dessa janela, o sistema deve
artigo relativo contagem de Pontos de A contagem de pontos de funo rea- possibilitar a manuteno no cadastro
Funo de um fragmento de um sistema lizada atravs de um conjunto de passos de cursos contendo cdigo e descrio do
de Controle Acadmico. previamente determinados. Para facilitar mesmo, alm do tipo do curso, que pode
o entendimento desse processo, cada um ser de graduao ou ps-graduao. Para
Introduo anlise de desses passos ser apresentado e aplicado cursos de graduao informa-se tambm
Pontos de Funo a um estudo de caso que demonstrar o nmero de perodos, enquanto que,
A FPA foi desenvolvida em meados da como a contagem pode ser feita. para cursos de ps-graduao, informa-
dcada de 70 na tentativa de minimizar Nesse sentido, o artigo conduzir um se a carga horria (Figura 2).
as dificuldades associadas medio de estudo de caso relacionado ao cadastro Ao final de qualquer dos processos de
tamanho de software atravs de linhas de de cursos e alunos de uma faculdade. O manuteno, o sistema deve emitir uma
cdigo-fonte, alm de prover um mecanis- cadastramento de cursos iniciado pelo mensagem de confirmao ao usurio.
mo que pudesse prever o esforo associado usurio e apresenta uma lista dos cursos Aps o cadastramento de cursos, po-
ao desenvolvimento de software. j cadastrados, permitindo pesquisa a demos matricular os alunos. Da mesma
Em 1984, uma verso mais refinada partir da descrio do curso e oferecendo maneira, existe uma janela de pesquisa
foi lanada e, posteriormente, com o as opes de cadastro relativas incluso, de alunos, praticamente igual de pes-
aumento da utilizao da FPA, tornou- alterao, excluso e consulta (Figura 1). quisa de cursos, exceto que oferece ainda
se necessrio definir um guia que
interpretasse as regras originais para
novos ambientes. Devido a essa neces-
sidade, em 1986 foi criado o Internatio-
nal Function Point Users Group (IFPUG).
No Brasil, esse grupo representado
pelo BFPUG (Brazilian Function Point
Users Group).
O clculo de Pontos de Funo (PF)
segue um conjunto de diretrizes des-
critas no manual de Prticas de Con-
tagem de Pontos de Funo do IFPUG.
Entretanto, divergncias de como
aplicar essas regras fazem com que as
contagens nem sempre resultem num
mesmo valor.
No sentido de criar um mtodo mais
rigoroso nesse processo de contagem,
surgiu a norma ISO/IEC 14143, que
estabelece uma srie de padres para
contagem funcional. Em 2002, a verso
4.1 do manual do IFPUG foi aprovada Figura 1. Janela de pesquisa de cursos
como aderente a essa norma.
Dessa forma, a FPA permite uma con-
tagem indicativa do tamanho do projeto
no incio do seu desenvolvimento, sem
conhecer detalhes de modelos de dados
ou de classes. Posteriormente, na fase de
construo, essa contagem representa
uma estimativa com maior preciso da
complexidade das funes e, ao trmino
da construo do software, na etapa de
transio, realizada uma contagem
detalhada, obtida a partir do grau de
complexidade das funes levantadas
no processo funcional, modelo de dados
ou modelo de classes, descrio de telas
e relatrios. Figura 2. Janela de cadastro de cursos

Edio 94 - ClubeDelphi 17
uma possibilidade de filtrar os alunos custo. Assim, para estimar o tamanho do includas em uma determinada contagem
por um curso especfico (Figura 3). software de acordo com a FPA, segue-se de pontos de funo. No nosso estudo de
O cadastramento de alunos, tambm um procedimento de contagem, que est caso, o escopo da contagem restringe-se
semelhante ao de cursos, possui matr- representado no esquema da Figura 7. s funcionalidades de pesquisa e cadas-
cula, nome, dados pessoais (Figura 4), A seguir, cada uma dessas atividades tramento de cursos e alunos, conforme
dados de endereo (Figura 5) e dados ser descrita e aplicada ao estudo de caso apresentado anteriormente;
de documentao (Figura 6). Aps o apresentado. 3) Funes de Dado: consiste na con-
cadastramento de um aluno, o sistema 1) Tipo de Contagem: existem trs tipos tagem dos tipos de dados utilizados
dever exibir para o usurio o valor da de contagem de pontos de funo. A di- nas funcionalidades a serem desen-
mensalidade a ser pago pelo aluno. ferena no procedimento adotado entre volvidas. Esses tipos de dados podem
Para o clculo da mensalidade, um esses tipos de contagem est nas frmulas ser agrupados em um Arquivo Lgico
valor base utilizado para cada tipo de aplicadas na contagem. So eles: Interno (ALI) que representa grupos
curso e considera ainda o nmero de Projeto de desenvolvimento: mede todas de dados relacionados e reconhecidos
perodos para cursos de graduao e a as funes que sero entregues com o pelo usurio, dentro da fronteira da
carga horria para cursos de ps-gradu- projeto em sua primeira verso. o tipo de aplicao; ou um Arquivo de Interface
ao. Os valores base das mensalidades contagem que ser utilizada neste artigo; Externa (AIE) que representa dados
so mantidos por um sistema financeiro Projeto de melhoria: mede as funciona- referenc iados pela apl icao mas
e esto fora dos limites dessa aplicao, lidades alteradas, includas e excludas mantidos dentro da fronteira de outra
sendo consultados por ela. ao projeto; aplicao. No exemplo temos:
Para a construo dessas funcionalidades, Aplicao: mede as funes de uma ALI: Curso, Aluno
ser primeiramente determinado o tama- aplicao j instalada. AIE: Mensalidade
nho da aplicao que ser desenvolvida, de 2) Escopo da Contagem: a fronteira Para calcular a complexidade das
forma a orientar as estimativas de prazo e da aplicao. Define as funes que sero funes de dados, deve-se contar o

Figura 3. Janela de pesquisa de alunos


Figura 5. Janela de Cadastro de Alunos Dados de Endereo

Figura 4. Janela de Cadastro de Alunos Dados Pessoais Figura 6. Janela de Cadastro de Alunos Dados de Documentao

18 ClubeDelphi - Anlise de Pontos de Funo


EXPERT

nmero de Tipos de Dados (TD) e Tipos para a contagem um nico ALI com dois ALI Aluno de complexidade baixa, pois
de Registros (TR) de cada uma dessas Tipos de Registros. possui um TR e 23 TDs e, por fim, o AIE
funes. Um TD refere-se a um campo Identificados os TDs e TRs, pode-se Mensalidade tambm de complexidade
nico reconhecido pelo usurio, sem calcular a complexidade de cada ALI/AIE baixa, pois possui um TR e dois TDs.
repetio, ou seja, se um campo se re- atravs da Tabela 4. Analisando-a, obser- 4) Funes de Transao: representam os
petir mais de uma vez numa interface, va-se que o ALI Curso de complexidade processos elementares fornecidos pela apli-
conta-se apenas uma vez. baixa, pois possui dois TRs e cinco TDs, o cao ao usurio, onde um processo elemen-
Um TR refere-se a um subgrupo de tipos
de dados, tambm reconhecidos pelo
usurio e componente de um ALI ou AIE.
No exemplo, os TDs esto apresentados
nas Tabelas 1 a 3, representando os arqui-
vos Curso, Aluno e Mensalidade, respec-
tivamente. Como Curso apresenta dois
tipos de registro (cursos de graduao e
de ps-graduao com dados especficos),
considera-se TR igual a 2.
Os demais possuem TR igual a 1. Se os
cursos estivessem divididos em mais de
um arquivo como, por exemplo, um ar-
quivo para cursos de graduao e outros
de ps, mesmo assim, consideraramos

TD Tipo de Dado
1 Cdigo do curso
2 Descrio do curso
3 Tipo do curso (1=Graduao / 2=Ps-Graduao)
4 Quantidade de perodos
5 Carga horria
Tabela 1. Tipos de Dados de Curso

TD Tipo de Dado
1 Matrcula do aluno
2 Nome do aluno
3 Data de nascimento
4 Identificador do curso
5 Ano de incio
6 Semestre de incio
7 Email
8 Telefone residencial
9 Telefone comercial
10 Telefone celular
11 Foto
12 Logradouro
13 Nmero
14 Complemento
15 Bairro
16 Cidade
17 UF
18 CEP
19 CPF
20 Nmero identidade
21 rgo expedidor
22 UF rgo expedidor
23 Data expedio
Tabela 2. Tipos de Dados de Aluno Figura 7. Processo de contagem de pontos de funo.

Edio 94 - ClubeDelphi 19
tar identifica a menor unidade funcional do AR: Para cada ALI lido ou mantido pela exibidos como resultado na interface
ponto de vista do usurio, e pode ser: aplicao, ou AIE lido, conta-se um; com o usurio. Pesquisar Curso e Pesquisar
Entrada Externa (EE): para sua identifi- TD: Aluno consideram AR igual a um, pois
cao devem ser analisados todos os pro- - Entrada Externa (EE): contam-se cada processo obtm informaes de um
cessos elementares que processam dados os atributos que so atualizados e nico ALI e TD igual a trs, pois, por ser
vindos de fora da fronteira da aplicao e determina-se a complexidade conforme um processo de entrada e sada, recebe
que atualizam um ou mais ALIs; a Tabela 6; o parmetro a ser consultado e exibe os
Sada Externa (SE): o processo gera - Sada Externa (SE): contam-se os dados previstos nas respectivas telas de
dados para fora da fronteira da aplicao, atributos da sada, alm de atributos cal- pesquisa (cdigo e descrio para cursos
tendo por objetivo principal apresentar culados, e determina-se a complexidade e matrcula e nome para alunos).
dados ao usurio atravs de lgica de conforme Tabela 7; Filtrar Alunos por Curso considera um AR
processamento que no apenas a recu- - Consulta Externa (CE): em um processo a mais por ter que exibir os cursos cadas-
perao de dados; de entrada de dados, contam-se os atributos trados. O processo elementar Exibir Men-
Consulta Externa (CE): processo que de seleo, alm de mensagem ao usurio sagem de Curso Cadastrado no considera
envia dados para fora da fronteira da quando for o caso. Em um processo de nenhum AR, pois no obtm informaes
aplicao, apresentando dados ao usu- sada de dados, contam-se os atributos de de nenhum ALI ou AIE e considera TD
rio por meio de uma simples recuperao sada. Em processos de entrada e sada, igual a um em funo da mensagem
de informaes de ALI ou AIE. somam-se os dois resultados. Determina-se exibida. Os processos elementares Incluir,
No estudo de caso deste artigo, podem- a complexidade conforme a Tabela 7. Alterar, Excluir e Consultar Alunos conside-
se identificar os processos elementares No estudo de caso deste artigo, con- ram dois AR por atualizar o ALI Aluno e
conforme apresentado na Tabela 5. sideram-se as anlises apresentadas na obter dados do ALI Curso.
As regras para definir a complexidade Tabela 8. O processo elementar Exibir Clculo de
de EE, SE ou CE consideram o nmero de Os processos elementares Listar Cursos Valor da Mensalidade considerou AR igual
Arquivos Referenciados (AR) e o nmero e Listar Alunos consideraram TD igual a a um por ler o AIE Mensalidade e TD igual
de Tipo de Dados (TD) utilizados, sendo: dois por ser esse o nmero de atributos a dois, em virtude de ler o valor da mensa-
lidade em funo do tipo de curso.
TD Tipo de Dado 5) Pontos de Funo No Ajustados:
1 Tipo do curso (1=Graduao / 2=Ps-Graduao) aps identificar as funes de dados e os
2 Valor Base da Mensalidade processos elementares, multiplica-se o
Tabela 3. Tipos de Dados de Mensalidade total de ALI, AIE, EE, SE e CE pelo respec-
tivo valor de ponto de funo da tabela de
Tipos de Dados (TD)
Tipos de Registro (TR) complexidade (Tabela 9) para determinar
Abaixo de 20 20 a 50 Acima de 50
o valor total que ser o PF no ajustado.
1 Baixa Baixa Mdia
A Tabela 10 exibe o resultado final do
2a5 Baixa Mdia Alta
clculo de pontos de funo no ajusta-
Acima de 5 Mdia Alta Alta
dos para o estudo de caso deste artigo.
Tabela 4. Complexidade das funes de dados (ALI e AIE)
6) Valor do Fator de Ajuste: represen-
Funcionalidade Processo Elementar Tipo ta a influncia de requisitos tcnicos e
Listar Cursos CE de qualidade no tamanho do software.
Pesquisa de Cursos calculado com base em 14 caracters-
Pesquisar Curso CE
Incluir Curso EE ticas gerais de um sistema, onde cada
Alterar Curso EE uma delas deve ser analisada com re-
Cadastramento de Cursos Excluir Curso EE lao ao seu nvel de influncia sobre
Consultar Curso CE o sistema e pontuada de 0 (nenhuma
Exibir Mensagem de Curso Cadastrado CE influncia) a 5 (grande influncia).
Listar Alunos CE A descrio completa de cada carac-
Pesquisa de Alunos Pesquisar Aluno CE terstica e as tabelas para avaliao dos
Filtrar Alunos por Curso CE valores de pontuao, pode ser obtida
Incluir Aluno EE no manual de Prticas de Contagem
Alterar Aluno EE de Pontos de Funo do IFPUG. Para
Excluir Aluno EE este exemplo, as caractersticas foram
Cadastramento de Alunos
Consultar Aluno CE descritas a seguir, bem como os valores
Exibir Cursos Cadastrados na Caixa de Combinao CE considerados para cada uma delas:
Exibir Clculo de Valor da Mensalidade SE 1. Comunicao de Dados: considera se
Tabela 5. Processos Elementares identificados no estudo de caso so utilizados recursos de comunicao

20 ClubeDelphi - Anlise de Pontos de Funo


EXPERT

pela aplicao. Neste exemplo, ser con- Tipos de Dados (TD)


Arquivos Referenciados (AR)
siderado o valor quatro, que relativo Abaixo de 5 5 a 15 Acima de 15
a aplicaes on-line, suportadas por 0 ou 1 Baixa Baixa Mdia
algum protocolo de comunicao; 2 Baixa Mdia Alta
2. Processamento Distribudo: relativo Acima de 2 Mdia Alta Alta
transferncia de dados entre os com- Tabela 6. Complexidade de Entrada Externa (EE)
ponentes da aplicao. Foi considerado
o valor um, uma vez que no realiza Tipos de Dados (TD)
processamento distribudo, fazendo uso Arquivos Referenciados (AR)
Abaixo de 6 6 a 19 Acima de 19
apenas de um sistema de gerenciamento 0 ou 1 Baixa Baixa Mdia
de banco de dados; 2 ou 3 Baixa Mdia Alta
3. Performance: determina como o tempo Acima de 3 Mdia Alta Alta
de resposta influencia a aplicao. Foi con-
Tabela 7. Complexidade de Sada Externa (SE) e Consulta Externa (CE)
siderado zero, uma vez que no foi indicada
nenhuma restrio a esse respeito;
Processo Elementar Tipo AR TD Complexidade
4. Configurao Altamente Utilizada: define
Listar Cursos CE 1 2 Baixa
o nvel de restries impostas pelo usurio.
Pesquisar Curso CE 1 3 Baixa
Tambm foi considerado o valor zero uma
Incluir Curso EE 1 5 Baixa
vez que nenhuma restrio foi imposta;
Alterar Curso EE 1 5 Baixa
5. Volume de Transaes: refere-se ao Excluir Curso EE 1 5 Baixa
volume de informaes processados pela Consultar Curso CE 1 5 Baixa
aplicao. Considerou-se o valor um, Exibir Mensagem de Curso Cadastrado CE 0 1 Baixa
uma vez que previsto um nmero de Listar Alunos CE 1 2 Baixa
transaes mais elevado em alguns pe- Pesquisar Aluno CE 1 3 Baixa
rodos especficos, como a cada perodo Filtrar Alunos por Curso CE 2 3 Baixa
de matrculas de alunos; Incluir Aluno EE 2 23 Alta
6. Entrada de Dados On-line: considera a Alterar Aluno EE 2 23 Alta
quantidade de transaes feitas on-line. Excluir Aluno EE 2 23 Alta
Foi considerado o valor cinco uma vez Consultar Aluno CE 2 23 Alta
que o sistema apresenta todas as transa- Exibir Cursos Cadastrados na Caixa de Combinao CE 1 1 Baixa
es como sendo desse tipo; Exibir Clculo de Valor da Mensalidade SE 1 2 Baixa
7. Eficincia do Usurio Final: refere-se a Tabela 8. Complexidade dos processos elementares identificados no estudo de caso.
facilidades oferecidas ao usurio final,
como ajuda on-line, auxlio navegao Processo Elementar Tipo Complexidade Pontos Funo
por teclas de funo, menus, dentre outros. Curso ALI Baixa 7
Foi considerado o valor um por apresen- Aluno ALI Baixa 7
tar algumas poucas caractersticas desse Mensalidade AIE Baixa 5
tipo, como a exibio dos cursos em caixa Listar Cursos CE Baixa 3
de combinao para facilitar a seleo do Pesquisar Curso CE Baixa 3
usurio no cadastramento de alunos; Incluir Curso EE Baixa 3
8. Atualizao On-line: define se os ar- Alterar Curso EE Baixa 3
quivos lgicos internos so atualizados Excluir Curso EE Baixa 3
on-line. Foi utilizado o valor trs, pois Consultar Curso CE Baixa 3
todos os arquivos internos so atualiza- Exibir Mensagem de Curso Cadastrado CE Baixa 3
dos dessa forma; Listar Alunos CE Baixa 3
9. Complexidade de Processamento: deter- Pesquisar Aluno CE Baixa 3
mina a complexidade de processamento Filtrar Alunos por Curso CE Baixa 3
Incluir Aluno EE Alta 6
Funo Baixa Mdia Alta Alterar Aluno EE Alta 6
Consulta Externa (CE) 3 4 6 Excluir Aluno EE Alta 6
Entrada Externa (EE) 3 4 6 Consultar Aluno CE Alta 6
Sada Externa (SE) 4 5 7 Exibir Cursos Cadastrados na Caixa de Combinao CE Baixa 3
Arquivo de Interface Externa (AIE) 5 7 10 Exibir Clculo de Valor da Mensalidade SE Baixa 4
Arquivo Lgico Interno (ALI) 7 10 15 Total de Pontos de Funo 80
Tabela 9. Contribuio de ponto de funo por complexidade Tabela 10. Identificao dos processos elementares e suas complexidade

Edio 94 - ClubeDelphi 21
das funcionalidades da aplicao. Foi ajustados so calculados a partir dos PFs lho de um nico desenvolvedor. Outra
considerado o valor zero, por ser uma no ajustados multiplicado pelo fator de situao que merece ateno utilizar
aplicao bastante simples; ajuste. No caso de processos de desen- o valor real de produtividade de um de-
10. Reutilizao: identifica se o cdigo volvimento, funes para converso de senvolvedor, uma vez que dificilmente
foi projetado para ser reaproveitado dados tambm devem ser consideradas algum tem produtividade igual a sua
em outras aplicaes. O valor zero foi e sua complexidade em pontos de fun- carga horria total de trabalho.
considerado por essa no ter sido uma o deve ser adicionada aos pontos de Neste exemplo hipottico, se considerar-
preocupao no projeto; funo no ajustados. mos que um desenvolvedor produz cerca
11. Facilidade de Instalao: considera Assim, a seguinte frmula para proces- de 35 horas reais por semana, o estudo de
se existem ferramentas de converso e sos de desenvolvimento aplicada: caso deste artigo levaria menos de duas
instalao da aplicao. Tambm foi con- semanas para ser desenvolvido, se condu-
PF Desenvolvimento = (PF No Ajustado +
siderado o valor zero por essa preocupa- PF Converso de Dados) * Fator Ajuste (VAF) zido por um nico desenvolvedor.
o no ter sido levada em considerao
no estudo de caso; Para o caso do exemplo utilizado, como Concluso
12. Facilidade de Operao: considera no foi considerada a converso de dados: Contagem de Pontos de Funo repre-
aspectos de segurana e recuperao de PF Desenvolvimento = (80 + 0) * 0,8 = 64 PFs senta uma tcnica de clculo do tamanho
informaes. Como isso tambm no foi de uma aplicao, no de esforo para
considerado, assumido o valor zero; Estimativas de esforo e prazo a partir seu desenvolvimento. Sua correta utili-
13. Mltiplos Locais: se a aplicao foi da Contagem de Pontos de Funo zao, baseada nas regras descritas no
projetada e desenvolvida para ser utili- Pontos de Funo tm por objetivo a manual de Prticas de Contagem de Pon-
zada em diferentes locais. Essa restrio medio do tamanho funcional de uma tos de Funo do IFPUG, pode ajudar na
tambm no foi considerada e assumido aplicao. Entretanto, no incomum que medio da funcionalidade de sistemas
o valor zero; desenvolvedores queiram estimar esforo e apoiar estimativas de esforo e prazo
14. Facilidade de Mudanas: se a aplicao e prazos a partir do nmero de pontos baseadas na produtividade conhecida de
foi projetada para facilitar mudanas de funo. Deve-se tomar cuidado com uma equipe de desenvolvimento.
na lgica de processamento ou em suas essa situao, pois a produtividade de Pode-se ainda encontrar diversas
estruturas de dados. O valor zero foi diferentes equipes de desenvolvimento ferramentas ou planilhas eletrnicas de
utilizado nesse caso. pode variar consideravelmente, inclusive diferentes fornecedores para apoiar os
Somam-se ento essas pontuaes para em funo das tecnologias utilizadas. procedimentos de clculo de pontos de
obter o nvel total de influncia (TDI Total A falta de conhecimento da produ- funo de forma a facilitar o processo de
Degree of Influence). Da basta aplicar a se- tividade da equipe pode fazer com contagem. Este artigo procurou apresen-
guinte frmula para obter o valor do fator que as estimativas de esforo sejam tar de forma prtica as principais regras
de ajuste (VAF Value Adjustment Factor): erradas, sem que pontos de funo de contagem de pontos de funo atravs
sejam os culpados por isso. Outra si- de um estudo de caso prtico.
Valor do Fator de Ajuste (VAF) =
(TDI x 0,01) + 0,65 tuao preocupante utilizar tabelas
de produtividade por ponto de funo Referncias
No caso do exemplo deste artigo: disponveis na internet, onde os dados
Site do IFPUG: International Function Point Users Group
VAF = (15 x 0,01) + 0,65 = 0,8
ali apresentados podem no refletir a www.ifpug.org
capacidade de produo de qualquer
Site do BFPUG-Brazilian Function Point Users Group
Atualmente esse um passo opcional equipe de desenvolvimento e, muitas www.bfpug.com.br
do processo de contagem. Muitas orga- vezes, no levam em considerao as
Livro Anlise de Pontos de Funo Medio,Estimativas
nizaes desconsideram o fator de ajuste caractersticas de diferentes tecnologias
e Gerenciamento de Projetos de Software
e usam apenas a medio dos pontos de que podem ser utilizadas.
3. edio, Carlos Eduardo Vazquez, Guilherme Siqueira
funo no ajustados. Isso se deve ao Portanto, o conhecimento da produti-
Simes e Renato Machado Albert.
fato de que as caractersticas gerais de vidade de cada equipe fundamental
Editora rica, 2003.
um sistema, apresentadas anteriormen- para estimativas de esforo e prazo a
te, so consideradas desatualizadas ou partir da contagem de pontos de funo.
incompletas em relao s tecnologias No estudo de caso deste artigo, vamos D seu feedback sobre esta edio! eu
Feedback
s

atualmente utilizadas, fazendo com que considerar hipoteticamente a situao de


D

A Java Magazine tem que ser feita ao seu


sobre e

sua utilidade seja questionada. que um ponto de funo desenvolvido


Isso fica mais evidenciado quando a em uma hora de trabalho de um desen- gosto. Para isso, precisamos saber o que
s

ta
e
voc, leitor, acha da revista!
d i o
norma ISO/IEC 14143 considera apenas volvedor (1 homem/hora).
os pontos de funo no ajustados em Assim, o esforo para esse projeto, D seu voto sobre este artigo, atravs do link:
suas estimativas de medio funcional. considerando-se os pontos de funo
www.devmedia.com.br/javamagazine/feedback
7) Pontos de Funo Ajustados: Os PFs ajustados, seria de 64 horas de traba-

22 ClubeDelphi - Anlise de Pontos de Funo


Seo DELPHI Seo EASY DELPHI Seo PHP

Nesta seo voc encontra artigos intermedirios


sobre Delphi Win32 e Delphi .NET

Usando todo o poder do TDataSetProvider


Usufrua de todos os recursos do DataSetProvider em suas aplicaes

S
em dvida nenhuma, um dos Entendendo o DataSetProvider
componentes mais poderosos da Basicamente o DataSetProvider respon-
VCL o DataSetProvider, que, alm svel por enviar e receber os Data Packets
de prover dados a toda a aplicao, da aplicao cliente para a o servidor de
capaz de auxiliar em uma srie de fun- dados. Os Data Packets so os pacotes de
cionalidades no sistema. dados trafegados na rede em uma aplica-
Veremos o que h de mais i nte- o duas camadas (two-tier ou client/
ressante nesse componente e dicas server) ou n camadas (n-tier). Toda
avanadas para usufruir ao mximo e qualquer requisio feita pela aplicao
de suas propriedades e mtodos. Em cliente enviada ao DataSetProvider que
conjunto com os componentes DBEx- por sua vez se encarrega de solicitar os
press o DataSetProvider capaz de dados ao servidor de aplicao. O result
realizar inmeras tarefas. Veremos set, ou seja, o resultado da requisio
nesse artigo: empacotado (Data Packets) e enviado
Introduo ao DataSetProvider; de volta aplicao cliente. Qualquer
Como usar o UpdateMode e Provi- exceo levantada, seja na requisio ou
Adriano Santos
(falecom@adrianosantos.pro.br) derFlags; no recebimento dos dados, retornada a
desenvolvedor Delphi desde 1998. Professor Configurando dinamicamente o aplicao cliente.
e programador PHP. Bacharel em Comunicao UpdateMode e ProviderFlags; Pode-se dizer que a utilizao mais
Social pela Universidade Cruzeiro do Sul, SP. Uso de Constraints; comum do DataSetProvider feita em
Editor Tcnico, Colunista e Membro da Comisso
conjunto dos componentes da paleta
Editorial da revista ClubeDelphi e WebMobile.
Mantm o blog Delphi to Delphi (www.delphi- Criaremos diversos exemplos para DBExpress acrescido do componente
todelphi.blogspot.com) com dicas, informaes entendermos corretamente cada funcio- ClientDataSet. Um exemplo de uso pode
e tudo sobre desenvolvimento Delphi. nalidade do DataSetProvider; ser visto na Figura 1.

24 ClubeDelphi - Usando todo o poder do TDataSetProvider


MO NA MAS S A

O que pouca gente sabe que o Data- de desenvolvimento, o que acarretaria Isso bastante interessante, visto
SetProvider pode se tornar mais do que em inconsistncia dos dados. que reduz drasticamente a quantida-
um simples componente de conexo Em aplicaes n-tier (multi-camadas) de desnecessria de cdigo e ainda
com o banco de dados por ser farto de podemos recorrer ao poderoso DataSnap permite que sejam personalizadas as
propriedades e eventos. e programar nossas regras de negcio mensagens de exceo geradas. Essas
diretamente no servidor de aplicao, propriedades so:
Constraints e DataSetProvider tornando a aplicao mais consistente Read Only: Como o prprio nome
Como sabemos, as constraints de e inteligente. Essas regras residem no indica, podemos setar um campo
uma aplicao podem ser inseridas cdigo fonte do servidor de aplicaes, como somente leitura;
de diversas formas em uma aplicao. e ficam centralizadas. Required: Essa propriedade estando
Em aplicaes two-tier, por exemplo, Resumindo, uma das melhores alterna- configurada como True, faz com que
temos apenas dois lugares onde elas tivas certamente fazer uso desta ltima a aplicao obrigue o usurio final a
podem ser includas: no lado servidor opo, ou seja, utilizar um servidor de digitar um valor nela. Grosseiramente
ou na aplicao cliente. No servidor aplicao que far o intercmbio entre falando, campos Not Null no banco de
devemos inseri-las diretamente no bando de dados (SGBD) e aplicao cliente, dados so fortes candidatos a serem
SGBD atravs de Stored Procedures, pois alm de propiciar maior controle campos Required, tanto , que quando
domains, rules, triggers etc. uma sobre as regras de negcios, ainda po- adicionamos um campo Not Null aos
excelente idia, pois centralizamos demos disponibilizar a aplicao para Fields Editors do DataSet, este j vem
nossas regras de negcios em um acesso remoto atravs da internet. como True em sua propriedade;
nico lugar. Porm, corremos o risco DefaultExpression: Valor padro
de ficarmos presos ao banco de dados Propriedades do TField para insero no banco de dados. Aqui
que estamos trabalhando por conta da Alg umas propriedades to TField podemos configurar um valor que ser
linguagem empregada no SGBD. Em so automaticamente passadas da gravado no banco caso esteja vazio;
outras palavras quando programamos aplicao servidora para o cliente e a CustomConstraint: exatamente
diretamente no banco necessitamos maioria dos valores so determinados nessa propriedade que definimos nossa
usar a linguagem de programao em tempo de projeto baseando-se constraint. Digitamos a expresso e poste-
SQL, tambm chamada ANSI, para na estrutura da tabela no SGBD. Po- riormente o sistema far a validao. Ex.:
criar nossas prprias instrues. Isso demos usufruir de alguns recursos X > 100 and X < 200;
pode se tornar uma dor de cabea em somente disponveis nas propriedades
uma eventual mudana de banco de do TField, seja em aplicaes single
www.devmedia.com.br/clubedelphi/portal.asp
dados ou mesmo se o produto vier a tier, two-tier ou n-tier e que no esto
ser comercializado com BDs diferen- disponveis no DataSnap. Em suma, Acesse agora o mesmo o portal do assinante ClubeDelphi e assista a uma
tes. Imagine um software que precisa possvel criarmos pequenas constraints vdeo aula de Guinther Pauli que mostra como trabalhar com constraints
ser capaz de se conectar aos bancos diretamente na aplicao cliente e que e ClientDataSet.
www.devmedia.com.br/articles/viewcomp.asp?comp=567&hl=
Interbase/Firebird, SQL Server 2005 podem ser facilmente configuradas.
Express e Oracle. De incio j teremos
algumas complicaes entre Interbase
e Firebird dependendo da verso de
ambos, haja vista que muitas modifi-
caes no BD foram feitas ao longo dos
anos. Por isso, da mesma forma que o
esquema interessante, tambm pode
tornar-se um trauma.
Por outro lado possvel incluir cons-
traints diretamente na aplicao cliente,
porm temos uma enorme desvanta-
gem: a decentralizao de nossas regras
de negcios. Elas precisam ser refeitas
para cada nova aplicao e espalhadas
por todo o cdigo fonte ou em Units,
componentes ou dlls. Essa prtica
altamente perigosa, pois podem ocor-
rer momentos em que uma regra de
negcio pode no ser alterada por
esquecimento dos membros da equipe Figura 1. Exemplo de uso do componente DataSetProvider

Edio 94 - ClubeDelphi 25
ConstraintErrorMessage: Por ltimo dbExpress. D um clique duplo no SQL- sistema obrigar o usurio a inserir um
a mensagem de erro que ser exibida ao Connection e crie uma nova conexo com valor nesses campos (Figura 3).
usurio final da aplicao; o banco de dados Employee.fdb presente no
Devemos nos lembrar que isso tudo diretrio de instalao do Firebird, nor- Propriedade adicionais do TField
s possvel com campos persistentes, malmente em C:\Arquivos de Programas\ usadas pelo DataSetProvider
ou seja, com tipificao de campos no Firebird\Firebird_Verso\examples\emp- Agora vejamos algumas das proprie-
projeto. Esse recurso utilizado quando build\Employee.fdb. Conecte o SQLDataSet dades mais importantes em um TField
adicionamos os campos da tabela no ao SQLConnection usando a propriedade e que so utilizadas fortemente pelo
Fields Editor do TDataSet, do contrrio SQLConnection e em seguida digite a DataSetProvider. A propriedade Options
no ser possvel. instruo SQL a seguir para selecionar os do DSP (DataSetProvider) suporta a
Outras duas informaes so importan- dados da tabela SALES do banco. passagem de propriedades adicionais
tssimas. A primeira que as mensagens do TFields. Quando configuramos como
SELECT * FROM SALES
de erro so resultantes da violao das True a propriedade poIncFieldProps, pode-
regras impostas nos TFields do TDataSet, Arraste agora um DataSetProvider e mos passar propriedades do TField para
e conseqentemente geraro excees. Se um ClientDataSet da paleta Data Access. o DSP. Essas propriedades so:
outras regras tambm forem definidas no Ligue o DataSetProvider ao SQLDataSet Alignment;
servidor de dados, ou seja, diretamente no pela propriedade DataSet e o ClientDa- Currency;
SGBD, estas tambm levantaro excees, taSet ao Provider usando ProviderName. DisplayFormat;
porm somente uma das duas mensagens Abra seu gerenciador de banco de dados DisplayLabel;
ser exibida. A segunda informao diz preferido e visualize a estrutura da ta- DisplayWidth;
respeito alterao de regras no SGBD. bela SALES (Figura 2). EditFormat;
Algumas das regras de negcios im- Note que os campos PO_NUMBER, EditMask;
postas diretamente no BD precisam ser CUST_NO, ORDER_STATUS, ORDER_ MaxValue;
replicadas para a aplicao, como o caso DATE, QTY_ORDERED, TOTAL_VALUE, MinValue;
de campos requeridos (Requires). Caso DISCOUNT e ITEM_TYPE, esto marca- Visible;
modifique de True para False ou vice-versa dos como Not Null, ou seja, no permitem
em um determinado campo, este precisa que sejam gravados sem nenhum valor. O que poucos sabem, que podemos
ser removido ou alterado em tempo de Experimente adicionar todos os campos configurar outras propriedades do DSP
projeto. Vejamos um exemplo: da tabela SALES ao Fields Editor do Clien- capazes de nos auxiliar em diversas
Abra o Delphi e crie uma nova aplicao teDataSet usando o menu de contexto e a tarefas. Ainda na propriedade Options
usando File|New>Application e salvando-a opo Add all fields. Em seguida clique vejamos algumas delas:
como Properties.dpr e o formulrio em cada campo e observe a propriedade poReadOnly: Desabilita qualquer al-
principal como Principal.pas. Insira no Required. Perceba que cada campo Not terao no DataSet ligado a ela;
formulrio um componente SQLConnec- Null teve sua propriedade Required mo- poDisableInserts: Desabilita a insero
tion e um TSQLDataSet, ambos da paleta dificada para True, isso significa que o de dados na tabela;
poDisableEdits: Dasativa a edio dos
registros;
poDisableDeletes: No permite a exclu-
so de registros;

Retorne ao projeto criado anterior-


mente e desenhe uma tela semelhante
Figura 4. Selecione o DataSerProvider e
configure a propriedade Options>poRead
Only para True, ative o ClientDataSet e
execute a aplicao. Perceba que o DB-
Navigator permite apenas a navegao
dos registros (Figura 5) e no mais as
demais opes.
Seguindo a mesma linha de racioc-
nio, agora modifique a propriedade
Options>DisableEdits, salve o projeto
e execute. Na seqncia, experimente
clicar no boto de alterao e note o
Figura 2. Estrutura da tabela SALES do banco Employee.fdb erro (Figura 6).

26 ClubeDelphi - Usando todo o poder do TDataSetProvider


MO NA MAS S A

Figura 3. Configurao do TField adicionado automaticamente

Isso acontece, porque informamos ao assinatura completa do evento podemos lizao no uma instruo para deletar
DSP que no permitida a alterao de ver a seguir, juntamente com a descrio o registro, pois caso seja no h necessi-
registros por parte da aplicao cliente, de cada parmetro: dade em se validar um registro que ser
logo a mensagem ClientDataSet1: Mo- BeforeUpdateRecord(Sender: TObject; apagado. Em seguida testamos se o valor
SourceDS: TDataSet; DeltaDS:
difications are note allowed., tradu- TClientDataSet;
recebido diferente de Null(VarIsNull)
zindo, ClientDataSet1: Modificaes UpdateKind: TUpdateKind; e diferente de vazio(VarIsEmpty). Por
var Applied: Boolean);
no so permitidas.. fim, verificamos se o valor do campo
Sender: DataSetProvider que disparou ORDER_DATE no superior ao SHIP_
Usando os eventos do DSP o evento; DATE. Havendo quaisquer divergncia
Podemos utilizar trs eventos para vali- SourceDS: Grosseiramente falando uma exceo levantada.
dar constraints em uma aplicao usando a fonte de dados, os dados em si;
o DataSetProvider. So eles: DeltaDS: Pacote de dados enviado Usando o evento OnUpdateData
BeforeUpdateRecord: Acontece antes pela aplicao cliente; O evento OnUpdateData ocorre uma
que os dados sejam atualizados na apli- UpdateKind: Tipo de update, atualiza- vez ao iniciar a aplicao dos dados no
cao remota; o, que ser feita. Os valores possveis servidor, ou seja, no recebimento dos
OnUpdateData: Acontece ao aplicar os so: ukInsert, ukModify e ukDelete; registros Delta do ClientDataSet. nesse
dados recebidos pela aplicao cliente, Applied: Indica se as modificaes momento que interceptamos as modifi-
no servidor de dados; sero aplicadas. caes e aceitamos ou at modificamos
OnUpdateError: Quando ocorrem os dados se necessrio. Aqui tambm
erros ao tentar efetuar o Update. Usando o evento podemos enviar mensagens aplicao
Usamos o evento BeforeUpdateRecord BeforeUpdateRecord cliente caso seja necessrio.
quando necessitamos fazer a validao Vejamos um exemplo prtico. No even- Veja a assinatura do evento logo em
individual dos registros enviados ao to BeforeUpdateRecord digite o cdigo da seguida:
servidor. Tambm podemos modificar Listagem 1. Nesse caso estamos verifi-
OnUpdateData(Sender: TObject; DataSet:
dados recebidos da aplicao cliente. A cando primeiramente se o tipo de atua- TClientDataSet);

Edio 94 - ClubeDelphi 27
Sender: DSP que disparou o evento; um DataSource(DataSource1) ao sistema. efetuadas. Execute o programa, efetue
DataSet: Pacote de dados, Data Packet; Desconecte o ClientDataSet do provider algumas alteraes na tabela e em segui-
limpando a propriedade ProviderName. da clique no boto Delta. Perceba que o 2
No caso do evento anterior, BeforeUpdate- Conecte o DataSource1 ao Delta. Insira um DBGrid mostra apenas alguns registros.
Data, no temos acesso total aos dados que Button e um DBGrid. Ligue o DBGrid ao Eles fazem parte do Data Packet, ou seja, o
esto vindo, e sim a um registro em particu- dsDelta e digite o cdigo da Listagem 2 no pacote de dados que ser enviado ao DSP
lar. J no caso do OnUpdateData, recebemos evento OnClick do Button (Figura 7). para montagem das instrues de inclu-
o DataSet, que contm todos os dados altera- O que estamos fazendo muito sim- so, alterao e excluso dos registros na
dos e no alterados. Sendo assim, podemos ples. Apenas atribumos propriedade base de dados. So assim que chegam os
ler individualmente o status de cada regis- Data do Delta o contedo da propriedade dados ao DSP (Figura 8).
tro da tabela atravs do Delta. Insira mais Delta do ClientDataSet1, que contm os O primeiro registro com o cdigo
um componente ClientDataSet(Delta) e dados originais acrescido das alteraes V91E0210, foi marcado para excluso. J

Figura 5. DBNavigator apenas com funes de navegao

Figura 6. Exceo gerada pelo DSP

www.devmedia.com.br/clubedelphi/portal.asp

Acesse agora o mesmo o portal do assinante ClubeDelphi e assista a uma


vdeo aula de Guinther Pauli que mostra como funciona a arquitetura do
Data e Delta do ClientDataSet.
www.devmedia.com.br/articles/viewcomp.asp?comp=5717&hl=

Nota do DevMan
Se voc quiser mostrar mensagens personalizadas de
erros em seu DSP, basta fazer uso dos eventos OnEditError,
OnPostError e OnDeleteError presentes no ClientDataSet.
Para isso basta acessar o evento que deseja modificar e
inserir a mensagem desejada. Ex:
Figura 4. Exemplo de tela
procedure TForm1.ClientDataSet1EditError
(DataSet: TDataSet;
E: EDatabaseError; var Action:
Listagem 1. Cdigo do evento BeforeUpdateRecord TDataAction);
begin
procedure TForm1.DataSetProvider1BeforeUpdateRecord( MessageDlg(No so permitidas
Sender: TObject; SourceDS: TDataSet; DeltaDS: alteraes nessa tabela.,
TClientDataSet; UpdateKind: TUpdateKind; mtInformation, [mbOk], 0);
var Applied: Boolean); Action := daAbort;
begin end;
if UpdateKind <> ukDelete then
if ((VarIsNull(DeltaDS.FieldByName(ORDER_DATE)
.NewValue) = False) and Note que estamos alterando o parmetro Action
(VarIsEmpty(DeltaDS.FieldByName(ORDER_DATE)
.NewValue) = False)) then para daAbort, dessa forma a mensagem original do
if DeltaDS.FieldByName(ORDER_DATE).NewValue >
DeltaDS.FieldByName(SHIP_DATE).OldValue then ClientDataSet no ser exibida, mostrando apenas nossa
raise Exception.Create(Data do pedido no pode ser
superior a data de compra.);
caixa de dilogo.
end;

28 ClubeDelphi - Usando todo o poder do TDataSetProvider


MO NA MAS S A

o segundo registro, V92J1003, teve o cam-


po CUST_NO alterado de 1010 para 300,
por isso aparece na visualizao apenas
o campo CUST_NO alterado. Por fim os
dois ltimos registros foram inclusos
na tabela. A partir do momento que o
mtodo ApplyUpdates do ClientDataSet Listagem 2. Cdigo do boto Delta
for chamado, o DSP far a montagem das procedure TForm1.Button2Click(Sender: TObject);
instrues SQL e as enviar ao servidor begin
try
de dados, que por sua vez executar todo Delta.Close;
Delta.Data := ClientDataSet1.Delta;
o processo de atualizao. Delta.Open;
except
MessageDlg(Sem registros no Delta,
Usando o evento OnUpdateError end;
mtWarning, [mbOK], 0);

Nas sees anteriores vimos que end;


possvel incluir mensagens persona-
lizadas na aplicao para lidar com
erros do sistema. Aqui veremos como
trabalhar com o evento OnUpdateEr-
ror. Nele podemos interceptar o erro,
process-lo, corrigi-lo e at mesmo
modific-lo para que o usurio final
tenha mais confiana no aplicativo e
entenda melhor tudo que est acon-
tecendo. A seguir encontramos uma
breve descrio de cada parmetro do
evento, bem como sua assinatura:
OnUpdateError(Sender: TObject;
DataSet: TClientDataSet;
E: EUpdateError;
UpdateKind: TUpdateKind;
var Response: TResolverResponse);

Sender: DataSerProvider que disparou


o erro;
DataSet: DataSet temporrio para
acessar o erro;
E: Objeto de exceo;
UpdateKind: Tipo de update;
Response: Ao de resposta ao erro;

Assim como os eventos que j vi-


mo s, aq u i n s p o de mo s u s a r o s
valores NewValue(Novo Valor) e
OldValue(Valor Anterior) do TField.
Tambm possvel utilizar o valor Cur-
Value (Valor atual), que indica o valor
atual do banco de dados. Com isso po-
demos visualizar o valor original, valor
armazenado atualmente e o valor que
dever ser aplicado.

www.devmedia.com.br/clubedelphi/portal.asp

Acesse agora o mesmo o portal do assinante ClubeDelphi e assista a uma


vdeo aula de Guinther Pauli que mostra como a arquitetura os Data
Packets no ClientDataSet.
www.devmedia.com.br/articles/viewcomp.asp?comp=5932&hl= Figura 7. Exemplo de tela com o Delta

Edio 94 - ClubeDelphi 29
O parmetro de exceo, E, possui uma
propriedade chamada OriginalException.
Ele permite que voc obtenha o valor ori-
ginal da exceo gerada pelo erro. Com
BDE podemos usar a classe EDBEngine-
Error para obter o cdigo de erro.
importante lembrar que dependendo
da quantidade de erros mencionada na
chamada ao ApplyUpdates, as excees
no sero propagadas, isso porque pode-
mos limitar o nmero de erros tolerados
pelo ClientDataSet.
Experimente digitar o cdigo da Lista-
gem 2 no evento OnUpdateError do DSP,
execute a aplicao e digite um valor
qualquer no campo Status. Depois salve
e clique em Apply. Repare na mensagem
que exibida na Figura 9.

Configurando UpdateMode e
ProviderFlags
Trabalhar com DSP no to difcil
quanto se pensa, mas muitos se atra-
palham com suas configuraes. Uma
das coisas que mais sou indagado, diz
respeito s propriedades UpdateMode do
DataSetProvider e ProviderFlags do Clien-
tDataSet. No h segredos mirabolantes
nessas duas propriedades, vejamos o que
cada uma significa e como funciona.
Em suma temos apenas trs estados do
UpdateMode que so:
upWhereAll: Utiliza todos os campos na
clusula Where para encontrar o registro;
upWhereChanged: Utiliza apenas os
campos alterados na clusula Where para
encontrar os registros;
upWhereKeyOnly: Utiliza apenas os
Figura 8. Delta do ClientDataSet1 sendo visualizado campos chave para procurar os registros.
Bem, pra ser mais objetivo toda vez
que chamamos o mtodo ApplyUpdates,
o ClientDataSet envia os Data Packets
para o DSP que se encarrega de varr-lo
e montar as instrues SQL que sero
enviadas ao servidor e posteriormente
aplicadas ao banco. Quando passamos
para o DSP a opo upWhereAll, ele
montar uma instruo utilizando
todos os campos da tabela em sua
Figura 9. Mensagem personalizada no evento OnUpdateError
clusula Where para que o registro seja

30 ClubeDelphi - Usando todo o poder do TDataSetProvider


MO NA MAS S A

atualizado. Supondo que nossa tabela ProviderFlag diferente. Ento pensamos retirados os atributos do ProviderFlags,
possui os campos ID, NOME, ENDE- na seguinte situao: nosso usurio pois toda a regra de negcio ou parte
RECO, CIDADE, ESTADO e TELEFONE, entrou na tela de cadastro de Clientes dela, depende dessas propriedades bem
sendo que apenas o campo ID chave, e alterou apenas o nome do cliente. configuradas.
imagine a instruo montada pelo DSP Ao efetuar um ApplyUpdates, o DSP
quando apenas o campo TEFONE fosse entra em ao e far a montagem da Consideraes finais
alterao. Veja: instruo. A instruo mais sensata O componente TDataSetProvider ainda
que o DSP precisa montar consiste possui uma srie de outras funcionali-
UPDATE CLIENTES SET TELEFONE=555-5525
WHERE ID=ID, NOME=NOME, ENDERECO=ENDERECO, apenas em fazer um Update usando dades que no puderam ser vistas aqui
CIDADE=CIDADE, TELEFONE=TELEFONE
como campo de alterao o Nome, e por conta da sua complexidade, como
Perceba que a clusula Where possui na clusula Where necessitamos apenas por exemplo Nested DataSets e o uso de
todos os campos da tabela, o que desne- dos campos da chave, que nesse caso pacotes de dados personalizados para
cessrio. Se o mesmo caso fosse aplicado vamos imaginar o ID do cliente. Uma montagem de tokens de validao ou
utilizando a opo upWhereChanged a instruo seria: logs de evento.
instruo seria: UPDATE CLIENTES SET NOME=JOSE DA SILVA altamente recomendvel fazer um
WHERE ID=ID
estudo aprofundado de todos os me-
UPDATE CLIENTES SET TELEFONE=555-5525
WHERE TEFONE=TELEFONE Para configurar o ClientDataSet de tal canismos e tcnicas pra utilizao de
forma que essa seja a instruo base, todos ou pelo menos grande parte dos
Nesse caso teramos problemas, pois po- precisamos modificar os ProviderFla- recursos desse fantstico componente.
deramos perder a referncia e atualizar gs do campo ID parara [pf InUpdate, Importante tambm lembrar que
o registro incorreto. O melhor de todos pfInWhere, pfInKey]. Os demais campos perfeitamente possvel utilizar outras
os casos usar a opo upWhereKeyOnly ficam configurados apenas com as estruturas de componentes com o DSP,
que monta a instruo usando apenas os duas primeiras opes. Dessa forma como por exemplo TDataBases> TQuery
campos da chave primria, ex: garantimos que os dados sero atuali- >TDataSetProvider>TClientDataSet.
zados corretamente.
UPDATE CLIENTES SET TELEFONE=555-5525
WHERE ID=ID Concluso
Configurando dinamicamente Falar sobre TDataSetProvider no
Por fim restam as configuraes dos UpdateMode e ProviderFlags fcil, visto que sua complexidade
campos no ClientDataSet. Nesse caso a Essa ltima etapa de nosso artigo bastante alta e a quantidade de re-
configurao acontece campo a campo demonstra como fazer a configurao cursos existentes fantstica. O uso
nos Fields Editor do objeto. O principal do UpdateMode e ProviderFlags dina- de DataSetProvider no dia-a-dia, faz
objetivo dos ProviderFlags informar micamente, o que na verdade no h com que a programao seja sempre
ao DataSetProvider qual a providncia segredo algum. uma caixinha de surpresa, j que so-
ser tomada com cada campo. O mais A propriedade UpdateMode do DataSe- mos capazes de descobrir inmeras
importante entender que nem todos tProvider possui apenas trs opes, e finalidades e funcionalidades para o
os campos precisam ser alterados no para modific-la em tempo de execuo componente. Por isso recomendvel
banco de dados, como campos vindos de apenas atribua o valor diretamente a sua que se estude a fundo todas as suas
Joins com outras tabelas. Como informar propriedade, veja: particularidades. Nesse artigo vimos
DSP que determinado campo pertence a os principais aspectos da programa-
DataSerProvider1.UpdateMode := upWhereAll;
outra tabela e no necessrio grav-lo? o com DSP e seus principais recur-
a que entram os ProviderFlags. Suas J o ClientDataSet a histria muda de sos, dicas e macetes.
opes so: figura. Nele, sua propriedade Provi- Espero que tenham gostado. Um forte
pf InUpdate: Campo incluso nos derFlags do tipo enumerado, ou seja, abrao e at a prxima.
Updates; pode ter mais de um valor. Mesmo
pfInWhere: Campo incluso na clusu- assim ainda bastante simples de
la Where; Usado para encontrar o registro fazer a implementao. Apenas atri-
original; bua o valor entre colchetes ao campo
pfInKey: Campo chave; Usado para que deseja adicionar os ProviderFlags, D seu feedback sobre esta edio! eu
Feedback
s

encontrar o registro original; como segue:


D

A Java Magazine tem que ser feita ao seu


sobre e

pfHidden: Campo oculto; Campo in-


ClientDataSet1.FieldByName(CustNo). gosto. Para isso, precisamos saber o que
cluso do Data Packet, mas usado apenas
s

ta
ProviderFlags := [pfInUpdate,pfInKey]; edio
voc, leitor, acha da revista!
para encontrar o registro original;
Como pode ver, muito simples. S D seu voto sobre este artigo, atravs do link:
Para ser mais direto, cada campo preciso tomar muito cuidado em qual www.devmedia.com.br/javamagazine/feedback
em um Fields Editor pode receber um o momento que sero adicionados ou

Edio 94 - ClubeDelphi 31
Seo DELPHI Seo EASY DELPHI Seo PHP

Nesta seo voc encontra artigos intermedirios


sobre Delphi Win32 e Delphi .NET

ClientDataSet
Automatizando o tratamento de Erros

Q
uem j criou algum tipo de Criando o componente
aplicativo que fizesse acesso MyClientDataset
com banco de dados e que Vamos iniciar a criao de componente,
teve que implementar alguma forma para isso inicie o Delphi (estou utilizan-
para tratar os erros retornados pelo do a verso 7, mas nada impede que se
SGBD, sabe o quanto vai ser til a use outra verso), no menu principal,
utilizao desse componente (criado entre na opo Component >> New
neste artigo), pois com ele no ser Component. Com isso ser aberta a tela
mais necessrio ter que implementar da Figura 1. Veja a Tabela 1.
a lg u m mtodo de t rata mento em Aps informar os valores acima, clique
todos os componentes ClientDataset em OK, ser criado o arquivo fonte do
espalhados pelo aplicativo. nosso componente. Agora s precisamos
O principal objetivo desse compo- implementar as novas funcionalidades
nente retirar do desenvolvedor a no componente. Vamos iniciar incluindo
necessidade de implementar rotinas no uses do nosso componente as units
para tratar os erros retornados no ban- necessrias para compilao e criar um
co de dados atravs dos eventos On- novo tipo chamado TMyErrors para iden-
ReconcileError e OnPostError. Nesse tificar os erros retornados (Listagem 1).
artigo irei criar esse novo componente Com isso concludo, vamos inserir
derivado da classe TClientDataset. os mtodos, o construtor e o destrutor
Rodrigo Lazoti Os erros tratados pelo componente do componente, irei criar duas funes
(rodrigolazoti@yahoo.com.br)
programador e desenvolvedor Delphi, .Net, so baseados nas mensagens retor- sobrecarregadas com o nome de Detec-
Java,Php e Asp. Possui certificao SCJP e atu- nadas utilizando o banco de dados tarErros para identificar o erro retornado
almente trabalha como consultor J2EE. Firebird. pelo SGBD, ver em qual opo do nosso

32 ClubeDelphi - ClientDataSet
MO NA MAS S A

tipo criado a mensagem de erro se en-


quadra e retorn-la como resultado da
funo. Criarei tambm dois procedi-
mentos sobrecarregados com o nome de
RetornarErros que tem como finalidade
disparar uma nova exceo tratada para
o aplicativo. E para finalizar criarei dois
mtodos para fazer o vnculo com os
eventos onReconcileError e onPostError
do componente. Primeiro vamos incluir
as declaraes da sesso private do com-
ponente (Listagem 2).
Antes de criarmos o corpo desses mto-
dos vamos incluir os mtodos restantes
para criar o corpo de todos os mtodos
de uma vez. Veja na Listagem 3 os m-
todos da sesso public.
Pronto, agora j temos todos os mto-
dos que iremos usar em nosso compo-
nente declarados. Aperte Ctrl+Shift+C
para que seja criado automaticamente
o corpo de todos os mtodos do compo- Figura 1. Criando um novo componente derivado da classe TClientDataset

Edio 94 - ClubeDelphi 33
Campo Valor Descrio
Ancestor type TClientDataset Contm a classe que nosso componente ser derivado.
Class name TMyClientDataset O nome da classe do novo componente
Palette Page ClubeDelphi O nome da aba onde o componente ser instalado.
Unit file name C:\Arquivos de programas\Borland\Delphi7\Lib\MyclientDataset.pas Nome e local do arquivo fonte do componente criado.
Tabela 1. Informaes iniciais para criao do componente

Listagem 1. Declarando o novo tipo de retorno e incluindo as units no uses nente e insira a codificao dos mtodos
unit MyClientDataSet;
conforme a Listagem 4.
O cdigo est todo comentado para
interface
fcil entendimento. Pronto, nosso com-
uses
SysUtils, Classes, DB, DBClient; ponente est finalizado, salve a unit.
type
No menu principal do Delphi clique em
TMyErrors = (meViolacaoChave, meValidacao, meChavePrimaria, meChaveEstrangeira, Component >> Install Component. Na
meConflito, meOutros);
opo Unit file name informe o local e
type
TMyClientDataSet = class(TClientDataSet) nome da unit criada, clique em OK, ser
private aberta uma janela com o pacote DCLUSR.
{ Private declarations }
protected DPK, compile o pacote, com isso o novo
{ Protected declarations }
public componente j estar disponvel para o
{ Public declarations }
published uso. Experimente utilizar o novo compo-
{ Published declarations } nente com os componentes do dbExpress
end;
acessando o Firebird, e veja que erros do
procedure Register;
servidor, como violao de chave, sero
implementation
automaticamente tratados.
procedure Register;
begin
RegisterComponents(ClubeDelphi, [TMyClientDataSet]);
end;
Concluso
Como vimos nesse artigo, a criao
end.
de componentes pode nos ajudar a no
escrever cdigos repetitivos, tornando
Listagem 2. Declarando novos mtodos no componente a criao a manuteno dos aplicativos
private mais fcil.
{ Private declarations }
FTratarErros :Boolean;
function DetectarErros(e: EReconcileError): TMyErrors; overload;
function DetectarErros(e: EDatabaseError): TMyErrors; overload;
procedure RetornarErros(cds: TClientDataSet; Err :EReconcileError); overload;
procedure RetornarErros(cds: TClientDataSet; Err :EDataBaseError); overload;

Listagem 3. Declarando novos mtodos no componente

public
{ Public declarations }
constructor Create(aOwner :TComponent); override;
destructor Destroy; override;
procedure MyReconcileError(DataSet: TCustomClientDataSet; E: EReconcileError;
UpdateKind: TUpdateKind; var Action: TReconcileAction);
procedure MyPostError(DataSet: TDataSet; E: EDatabaseError;
var Action: TDataAction);

34 ClubeDelphi - ClientDataSet
MO NA MAS S A

Listagem 4. Codificando os mtodos do componente


constructor TMyClientDataSet.Create(aOwner: TComponent); Valor invlido ou nulo foi encontrado em campos que contm restries. +
begin Motivo: + Err.Message);
// Associa os eventos aos mtodos meChavePrimaria:
inherited Create(aOwner); raise Exception.Create(Erro ao salvar + cds.Name + .+#10#13+
Self.OnPostError := MyPostError; O registro no pode ser gravado, ocorreu um erro de duplicidade na chave primria. +
Self.OnReconcileError := MyReconcileError; Motivo: + Err.Message);
end; meChaveEstrangeira:
destructor TMyClientDataSet.Destroy; raise Exception.Create(Erro ao efetuar operao + cds.Name +
begin .+#10#13+Dependncia invlida entre tabelas ligadas. +
inherited Destroy; Motivo: + Err.Message);
end; meConflito:
function TMyClientDataSet.DetectarErros(e: EReconcileError): TMyErrors; raise Exception.Create(Erro ao salvar + cds.Name + .+#10#13+
begin O registro foi modificado ou deletado por outro usurio. +
// Verifica qual o erro ocorrido pela mensagem Motivo: + Err.Message);
if (Pos(VALIDATION ERROR, UpperCase(E.Message))<>0) then else
Result := meValidacao raise Exception.Create(Erro ao salvar + cds.Name + .+#10#13+
else if (Pos(VIOLATION OF FOREIGN KEY, UpperCase(E.Message))<>0) then Erro desconhecido: +err.Message);
Result := meChaveEstrangeira end;
else if (Pos(VIOLATION OF PRIMARY OR UNIQUE KEY, end;
UpperCase(E.Message))<>0) then
Result := meChavePrimaria Procedure TMyClientDataSet.RetornarErros(cds: TClientDataSet;
else if (Pos(RECORD NOT FOUND OR CHANGED BY ANOTHER USER, Err: EDataBaseError);
UpperCase(E.Message))<>0) then Begin
Result := meConflito cds.CancelUpdates;
else cds.Refresh;
Result := meOutros; case DetectarErros(Err) of
end; meViolacaoChave:
function TMyClientDataSet.DetectarErros(e: EDatabaseError): TMyErrors; raise Exception.Create(Erro ao salvar +cds.Name+ .+
begin J existe um registro com o cdigo informado!);
// Trata Key Violation else
if (Pos(KEY VIOLATION, UpperCase(E.Message))<>0) then raise Exception.Create(Erro ao salvar + cds.Name + .+#10#13+
Result := meViolacaoChave Erro desconhecido: +err.Message);
else end;
Result := meOutros; end;
end; procedure TMyClientDataSet.MyPostError(DataSet: TDataSet;
procedure TMyClientDataSet.RetornarErros(cds: TClientDataSet; E: EDatabaseError; var Action: TDataAction);
Err: EReconcileError); begin
Begin RetornarErros(Self, E);
// Faz o tratamento do OnReconcileError end;
// Cancela o Update procedure TMyClientDataSet.MyReconcileError(
cds.CancelUpdates; DataSet: TCustomClientDataSet;
cds.Refresh; E: EReconcileError; UpdateKind: TUpdateKind;
// Trata o tipo de erro var Action: TReconcileAction);
case DetectarErros(Err) of begin
meValidacao: RetornarErros(Self, E);
raise Exception.Create(Erro ao salvar + cds.Name + .+#10#13+ end;

Edio 94 - ClubeDelphi 35
Seo DELPHI Seo EASY DELPHI Seo PHP

Nesta seo voc encontra artigos intermedirios


sobre Delphi Win32 e Delphi .NET

Controle on-line de vdeo-locadora - Parte 2


Veja como criar um sistema on-line de controle para uma vdeo-locadora

N
este artigo veremos a continu- Relembrando o artigo anterior, criamos
ao da criao de um sistema o banco de dados com toda a estrutura de
online para vdeo-locadora, tabelas necessrias, alm da configura-
onde faremos a concluso dos princi- o da conexo do sistema com o banco
pais processos que envolvem reservas, de dados utilizando os componentes
retiradas e devoluo de filmes por especficos para conexo com o Firebird.
meio de usurios e tambm a dispo- Criamos tambm no artigo anterior as
nibilidade de consultas. Nesta etapa pginas de manuteno dos gneros e
do artigo faremos a criao de pginas vdeos da locadora, onde criamos todos
para autenticao de usurios e tambm os nossos componentes de conexo e
para autenticao de administradores pesquisas no cdigo da pgina (runtime),
do sistema de locadora. processo este que ter continuao nesta
Para reservas, criaremos uma pgina segunda etapa do artigo.
especfica aos usurios onde os mes-
mos podero realizar buscas de filmes Login de Usurios
e reservar os mesmos para retirada na Retomando o projeto criado no artigo
locadora. Tambm a criao de uma anterior, aps reaberto o mesmo adicio-
Maikel Marcelo Scheid rea administrativa para efetivao das ne uma nova ASP.NET Page, atravs do
(maikelscheid@gmail.com) retiradas feitas por meio de reservas menu File|New>Other>Delphi for .NET
tcnico em Informtica com nfase em An- online e manutenes de emprstimos, Projects>New ASP.NET Files>ASP.NET
lise e Programao de Sistemas. Atua na rea podendo registrar novas locaes ou Page e altere seu nome para login.
de Desenvolvimento de Softwares em Delphi
para plataforma Win32 e .NET com banco de
devolvendo filmes locados, centrali- aspx. Adicione ao corpo da pgina
dados Firebird e MS SQL. membro da equipe zando este processo aos administra- uma tabela de 4 linhas e 1 coluna com
Editorial ClubeDelphi. dores da locadora. 300 pixels de largura. Na primeira linha

36 ClubeDelphi - Controle on-line de vdeo-locadora - Parte 2


WEB M INI- C URSO M O NA MAS S A

digite o texto Login de Clientes e faa de informaes corretas na autenticao, A existncia de um bloco try..except
a formatao do texto. Na segunda linha algumas informaes contidas no objeto muito importante neste trecho do cdigo
da tabela adicione uma nova tabela com sero armazenadas em variveis de para interpretar a seguinte situao:
2 linhas e 2 colunas ocupando 100% da sesso (Session) para serem usadas futu- - Supondo que o usurio esteja logado
largura disponvel, onde dever digitar ramente para identificao e validao no sistema, logo a Session[NOME] ter
nas linhas da primeira coluna o texto de usurios. Adicione tambm junto as um valor relacionado e o mesmo ser
Usurio e Senha e nas linhas da Uses da pgina o namespace FirebirdSQL. exibido no LblUsuario, mas no caso de
segunda coluna adicionar dois compo- Data.Firebird que possibilitar o trabalho o usurio no ter realizado a autenti-
nentes TextBox(txtUser, txtSenha) com o objetos de conexo e pesquisa cao e a seo Nome no existir, um
alterando a propriedade TextMode do para Firebird. tratamento de erros faz com que o bloco
txtSenha para Password. Adicione na except redirecione o usurio de volta
linha 3 um Button(btnLogin) e na Validando usurios na pgina pgina de login, inibindo seu acesso a
ltima linha da tabela crie um link para A validao dos usurios na pgina todas as pginas onde o User Control
o login dos administradores, direcio- bastante simples de ser implementada. estiver sendo utilizado.
nando pgina login_adm.aspx que ser Localize no projeto o User Control uccon-
criada no decorrer do artigo. trole.ascx criado j no incio do artigo e Pgina de Reservas OnLine do
Acessando o cdigo da pgina (use com um duplo clique sobre uma rea em cliente
a tecla de atalho F12), crie a constante branco, acesse o evento Load do mesmo No menu File|New>Other>Delphi for
strConexao na rea Interface da pgina onde dever digitar as seguintes linhas .NET Projects>New ASP.NET Files>ASP.
informando a string de conexo com o de cdigo: NET Page crie uma nova pgina salvan-
banco. Esse valor ser usado mais adian- try do-a como user_reservas.aspx. Adi-
LblUsuario.Text := Session[NOME].
te para que o componente fbConnection ToString;
cione ao corpo da pgina uma tabela
acesse o BD. Da mesma maneira como except de 11 linhas e 1 coluna com 700 pixels
Response.Redirect(login.aspx);
utilizado no artigo anterior, declare a end; de largura. Adicione alguns compo-
constante conforme cdigo a seguir:
Listagem 1. Evento Click para autenticao de usurio e senha dos clientes
const
strConexao = User=SYSDBA; procedure TWebForm1.btnLogin_Click(sender:
Password=masterkey; System.Object; e: System.EventArgs);
Database=<Caminho>LOCADORA.FDB;;
var
Comand: FbCommand;
De volta ao corpo da pgina (F12), DataAdapter: FbDataAdapter;
Conn: FbConnection;
com um duplo clique sobre o btnLogin, prUser : FbParameter;
adicione ao seu evento OnClick o cdigo prSenha : FbParameter;
fbReader : FbDataReader;
da Listagem 1 responsvel por realizar a
begin
autenticao do usurio e senha digitados { Criao dos objetos de conexo }
Conn := FbConnection.Create;
e direcionar o usurio a pgina corres- DataAdapter := FbDataAdapter.Create;
pondente no sistema. O cdigo utilizado Comand := FbCommand.Create;
{ Atribuio da string de conexo e abertura do BD}
acompanha a metodologia empregada Conn.ConnectionString := strConexao;
Conn.Open;
no artigo da edio anterior, onde logo { Atribuio dos atributos de seleo dos dados }
de incio criamos todos os componentes DataAdapter.SelectCommand := Comand;
DataAdapter.SelectCommand.Connection := Conn;
e atribumos a string de conexo com o DataAdapter.SelectCommand.CommandText :=
select clientes.nome, clientes.cod_cliente +
banco ao Conn, componente de conexo. from clientes where ((clientes.login = ?) and
(clientes.senha = ?));
Em seguida atribumos a conexo ao prUser := FbParameter.Create;
objeto interno do DataAdapter chamado prSenha := FbParameter.Create;
DataAdapter.SelectCommand.Parameters.Add(prUser);
SelectCommand. ele que receber a ins- DataAdapter.SelectCommand.Parameters.Add(prSenha);
DataAdapter.SelectCommand.Parameters[0].Value :=
truo SQL de seleo dos dados em sua txtUser.Text;
DataAdapter.SelectCommand.Parameters[1].Value :=
propriedade CommandText. txtSenha.Text;
Em seguida atribumos os parme- fbReader := DataAdapter.SelectCommand.ExecuteReader;
if fbReader.Read then
tros de usurio e senha para a SQL de
begin
seleo do CommandText atravs do Session[USUARIO] := txtUser.Text;
Session[NOME] := fbReader[NOME].ToString;
objeto FbParameter criado e instanciado Session[CODIGO] := fbReader[COD_CLIENTE]
separadamente para cada parmetro .ToString;
Response.Redirect(user_reservas.aspx);
adicionado, onde ao final executamos end else
RegisterStartupScript(erro,<script>javascript
a consulta e relacionamos o resultado a :alert(Usurio ou Senha incorretos!);
</script>);
um objeto FbDataReader que ser verifi- end;
cado quanto ao sucesso do login. No caso

Edio 94 - ClubeDelphi 37
nentes ao corpo dela, organizando-os sobre o DataGrid acesse sua proprieda- de Header text para Prev. Dev. em Data
respect ivamente de acordo com o de Auto Format e aplique um estilo de Field digite o valor PREV_DEVOLUCAO
layout exibido na Figura 1. Arraste formatao desejado. Novamente com e em Data Formatting Expression o valor
na primeira linha da tabela o User o boto direito do mouse, acesse agora {0:dd/MM/yyyy} que far a formata-
Control uccontrole.ascx, aps insira um o item Property Builder onde iremos o da forma de exibio da data.
Button(btnSair) na segunda linha, modificar a estrutura da categoria Selecionando o gridReservas, faremos
seguido de uma linha com o texto Columns. Desmarque o item Create configuraes semelhantes as aplica-
Minhas Locaes Ativas identifi- columns automatically at run time. Em das na configurao do gridLocacao.
cando o contedo a ser carregado no seguida clique no item Bound Column Com o boto direito do mouse sobre o
DataGrid(gridLocacao) da linha se- em Available columns e envie-o para DataGrid acesse sua propriedade Auto
guinte. Uma linha em branco com um Selected columns. Agora selecione-o e Format e aplique um estilo de formata-
espao ir separar o contedo do texto atribua o valor COD_LOCACAO na o ao mesmo. Novamente com o boto
Minhas Reservas Ativas identifican- propriedade Data Field, onde rece- direito do mouse, acesse agora o item
do o DataGrid(gridReservas) que ser beremos o valor do campo na tabela Property Builder onde iremos modifi-
preenchido com as reservas ativas do Locacao atravs do result set da Select car a estrutura da categoria Columns,
usurio. As ltimas da tabela sero que faremos nos registros com status onde no topo da janela desmarque o
caracterizadas por cadastrar novas N indicando Locao. Desmarque item Create columns automatically at run
reservas, onde alm do texto informa- tambm a opo Visible da coluna. time. Em seguida clique no item Bound
tivo Criar nova reserva um compo- Agora insira uma nova coluna, ou seja, Column em Available columns e envie-o
nente DropDowList(ddlVideos) para clique novamente em Bound Column e para Selected columns. Agora selecione-
listagem dos vdeos disponveis para envie-o para a rea Selected columns. Na o e atribua o valor COD_LOCACAO na
reserva e um Button(btnReservar) propriedade Header text (Texto de cabe- propriedade Data Field, onde recebere-
para salvar o processo da reserva. alho), digite Titulo e em Data Field o mos o valor do campo na tabela Locacao
Selecionando o gridLocacao, faremos valor TITULO que justamente o campo atravs do result set da Select que fare-
agora algumas configuraes necess- resultante de um Inner Join da tabela mos nos registros com Status R para
rias antes da codificao dos proces- Locacao com a tabela Videos semelhante Reservas. Desmarque tambm a opo
sos que iro exibir as informaes na como no passo anterior. Por fim, adicione Visible da coluna.
pgina. Com o boto direito do mouse uma nova coluna e altere sua proprieda- Agora insira uma nova coluna, ou
seja, cl ique nova mente em Bound
Column e envie-o para a rea Selected
columns. Na propriedade Header text
(Texto de cabealho), digite Titulo
e em Data Field o valor TITULO que
justamente o campo resultante de um
Inner Join da tabela Locacao com a ta-
bela Videos semelhante como no passo
anterior. Por fim, adicione uma nova
coluna e altere sua propriedade Hea-
der text para Data Reserva. em Data
Field digite o valor DATA e em Data
Formatting Expression o valor {0:dd/
MM/yyyy} que far a formatao da
forma de exibio da data.
Selecionando o ddlVideos, adicione a
sua propriedade DataValueField o valor

Nota do DevMan
Para alterar a largura das colunas, basta entrar novamente
no Property Builder e selecionar o item Format. Nele
podemos definir atributos para vrias caractersticas do
componente Data Grid. Note que temos a opo Columns.
Expanda este item e clique na ltima coluna (Alterar).
direita digite 50 no campo Width (largura) e confirme.
Figura 1. Layout da pgina de reservas do usurio

38 ClubeDelphi - Controle on-line de vdeo-locadora - Parte 2


WEB M INI- C URSO M O NA MAS S A

COD_VIDEO e para DataTextField o valor


Listagem 2. Codificando as aes para carregamento de vdeos, reservas e locaes
TITULO, sendo estas duas colunas de in-
procedure TWebForm2.CarregaVideos;
formaes que sero carregadas atravs var
do result de um select em todos os vdeos Comand: FbCommand;
DataAdapter: FbDataAdapter;
disponveis para reserva. Ds: DataSet;
Conn: FbConnection;
O processo para carregamento das in-
formaes requer que 1 procedure e uma begin
{ Criao dos objetos de conexo }
function sejam criadas, especificando Conn := FbConnection.Create;
DataAdapter := FbDataAdapter.Create;
para cada uma delas componentes que Comand := FbCommand.Create;
{ Atribuio da string de conexo e abertura
sero criados em tempo de execuo do BD}
conforme exemplos anteriores e que Conn.ConnectionString := strConexao;
Conn.Open;
requerem a criao de uma constante { Atribuio dos atributos de seleo dos dados }
DataAdapter.SelectCommand := Comand;
strConexao e incluso da namespace DataAdapter.SelectCommand.Connection := Conn;
DataAdapter.SelectCommand.CommandText :=
FirebirdSQL.Data.Firebird na clusula SELECT V.COD_VIDEO, V.TITULO FROM VIDEOS V +
Uses. Declare na seo Private do cdigo WHERE V.COD_VIDEO NOT IN (SELECT LOCACAO.VIDEO
FROM LOCACAO +
a procedure e tambm a function conforme WHERE ((LOCACAO.VIDEO = V.COD_VIDEO) AND
((LOCACAO.STATUS = R) +
lista adiante e adicione a cada uma delas OR (LOCACAO.STATUS = N)))) ORDER BY V.TITULO;
{ Criao em memria do DataSet auxliar }
os respectivos cdigos encontrados na Ds := DataSet.Create;
Listagem 2, sendo que todos os pro- DataAdapter.Fill(Ds, Titulo);

cessos encontram-se comentados entre Try


{ Popularizao dos vdeos no componente da
as linhas do mesmo. Observe que para pgina }
ddlVideos.DataSource := Ds;
carregar as locaes e reservas ativas ddlVideos.DataBind;
utilizamos apenas uma funo, a qual finally
Conn.Close;
requer a passagem do parmetro Status end;
end;
de acordo com a situao cadastral dos
registros que desejamos exibir: function TWebForm2.CriaListaVideos(Status: String):
DataSet;
var
procedure CarregaVideos; Comand: FbCommand;
function CriaListaVideos(Status: DataAdapter: FbDataAdapter;
String):DataSet; Ds: DataSet;
Conn: FbConnection;
Finalizada a criao e codificao prCliente : FbParameter;
begin
dos mtodos para carregar os dados { Criao dos objetos de conexo }
Conn := FbConnection.Create;
de locaes, reservas e vdeos preci- DataAdapter := FbDataAdapter.Create;
Comand := FbCommand.Create;
samos fazer a chamada dos mesmos. { Atribuio da string de conexo e abertura do BD}
Para isso usaremos o evento Load da Conn.ConnectionString := strConexao;
Conn.Open;
pgina onde dever digitar as seguin- { Atribuio dos atributos de seleo dos dados }
DataAdapter.SelectCommand := Comand;
tes linhas do cdigo, que iro jogar o DataAdapter.SelectCommand.Connection := Conn;
DataAdapter.SelectCommand.CommandText :=
resultado aos componentes relaciona- SELECT LOCACAO.COD_LOCACAO, VIDEOS.TITULO,
dos. Observe que estamos utilizando CLIENTES.NOME, +
LOCACAO.PREV_DEVOLUCAO, LOCACAO.DATA FROM +
a mesma f uno para carregar as LOCACAO +
INNER JOIN VIDEOS ON (LOCACAO.VIDEO = +
reservas e locaes, alterando apenas VIDEOS.COD_VIDEO) +
INNER JOIN CLIENTES ON (LOCACAO.CLIENTE = +
o valor do parmetro Status repassada CLIENTES.COD_CLIENTE) +
para a function: WHERE ((LOCACAO.STATUS = + Status + )
AND (LOCACAO.CLIENTE = ?)) ORDER BY +
LOCACAO.DATA;
gridLocacao.DataSource :=
{ Criao dos parmetros da pesquisa. O Status
CriaListaVideos(N);
ser configurado ao chamar a function }
gridLocacao.DataBind;
prCliente := FbParameter.Create;
gridReservas.DataSource :=
DataAdapter.SelectCommand.Parameters.Add(
CriaListaVideos(R) AND
prCliente);
(LOCACAO.PREV_DEVOLUCAO >= TODAY);
DataAdapter.SelectCommand.Parameters[0].Value :=
gridReservas.DataBind;
Session[CODIGO].ToString;
CarregaVideos;
{ Criao em memria do DataSet auxliar }
Ds := DataSet.Create;
DataAdapter.Fill(Ds, Titulo);
Se executar a pgina neste momento,
j poder perceber que todas as infor- try
{ Joga o resultado do Select para o Result
maes sero listadas, porm ainda est da funo }
Result := Ds;
disponvel o cadastro de novas reservas. finally
Uma nova reserva ser realizada a partir Conn.Close;
end;
do click ao boto btnReservar no qual end;

adicione o cdigo da Listagem 3.

Edio 94 - ClubeDelphi 39
O c d igo t a mb m s e ut i l i z a da
Listagem 3. Cdigo para reservar um vdeo
criao dos componentes em runti-
procedure TWebForm2.btnReservar_Click(sender:
System.Object; e: System.EventArgs);
me onde passamos uma instruo
SQL ao objeto InsertCommand do
var
Comand: FbCommand; Dat a Adapter e c on f ig u ra o do s
DataAdapter: FbDataAdapter;
Conn: FbConnection; parmetros de cadastros. Ao execu-
prVideo : FbParameter; tarmos a instruo, e o resultado for
prCliente : FbParameter;
prData : FbParameter; de sucesso, chamamos os mtodos
prStatus : FbParameter;
prDev : FbParameter; para que a pgina seja recarregada e
begin
as informaes atualizadas. Lembre-
{ Criao dos objetos de conexo } se de adicionar nas Uses da pgina o
Conn := FbConnection.Create;
DataAdapter := FbDataAdapter.Create; namespace DateUtils da qual estamos
Comand := FbCommand.Create;
chamando uma funo para incremen-
{ Atribuio da string de conexo e abertura do BD} tar certa quantidade de dias data de
Conn.ConnectionString := strConexao;
Conn.Open; vencimento da reserva.
{ Atribuio dos atributos de seleo dos dados } Adicione tambm ao evento OnClick do
DataAdapter.InsertCommand := Comand;
DataAdapter.InsertCommand.Connection := Conn;
btnSair o cdigo adiante para fazer o re-
DataAdapter.InsertCommand.CommandText := direcioamento da pgina e aps execute
INSERT INTO LOCACAO +
(VIDEO, CLIENTE, DATA, STATUS, PREV_DEVOLUCAO) a pgina fazendo uma nova reserva para
VALUES (?, ?, ?, ?, ?);
o usurio autenticado.
prVideo := FbParameter.Create;
prCliente := FbParameter.Create;
Response.Redirect(login.aspx);
prData := FbParameter.Create;
prStatus := FbParameter.Create;
prDev := FbParameter.Create;
DataAdapter.InsertCommand.Parameters.Add(prVideo);
DataAdapter.InsertCommand.Parameters.Add(prCliente);
Concluso
DataAdapter.InsertCommand.Parameters.Add(prData); No perca a prxima parte deste artigo,
DataAdapter.InsertCommand.Parameters.Add(prStatus);
DataAdapter.InsertCommand.Parameters.Add(prDev); onde continuaremos a implementao
DataAdapter.InsertCommand.Parameters[0].Value :=
ddlVideos.SelectedValue; das retiradas e devoluo de filmes por
DataAdapter.InsertCommand.Parameters[1].Value := meio de usurios e tambm a disponi-
Session[CODIGO].ToString;
DataAdapter.InsertCommand.Parameters[2].Value := bilidade de consultas.
DateTime.Today.ToString(dd.MM.yyyy);
DataAdapter.InsertCommand.Parameters[3].Value := R;
DataAdapter.InsertCommand.Parameters[4].Value :=
System.&String.Format({0:dd/MM/yyyy},
IncDay(DateTime.Today, 7));{Uses DateUtils} D seu feedback sobre esta edio! Feedback
eu

s
D
if DataAdapter.InsertCommand.ExecuteNonQuery> 0 then
begin A Java Magazine tem que ser feita ao seu

sobre e
gridReservas.DataSource := CriaListaVideos(R)
AND (LOCACAO.PREV_DEVOLUCAO >= TODAY); gosto. Para isso, precisamos saber o que

s
ta
e
gridReservas.DataBind; voc, leitor, acha da revista!
d i o
CarregaVideos;
end;
end; D seu voto sobre este artigo, atravs do link:
www.devmedia.com.br/javamagazine/feedback

40 ClubeDelphi - Controle on-line de vdeo-locadora - Parte 2


Seo DELPHI Seo EASY DELPHI Seo PHP

Nesta seo voc encontra artigos intermedirios


sobre Delphi Win32 e Delphi .NET

Desenvolvendo uma Aplicao Completa com


PocketStudio
Aprenda a criar aplicaes para o sistema operacional PalmOS Parte 3

N
o artigo anterior, aprendemos o PC. Para isso devemos criar uma nova
a criar uma tabela e fazer refe- Unit, como vimos no artigo anterior.
rncia a ela em nosso formul- Acesse o menu File|New>Unit, salve-a
rio de consulta de clientes. Com base no com o nome de ProdutosDB.pas. Vale
mesmo conceito e aprendizado, faremos lembrar que podemos utilizar as teclas
a incluso de novas telas em nosso sis- de atalhos CTRL + Shift + S para salvar
tema, tais como: cadastro de produtos e nosso projeto. Feito isso vamos montar
digitao de pedidos. a tabela de produtos.
Lembrando que nossas telas no sistema Logo abaixo da palavra reservada
apenas consultam a base de dados no Interface declare uma seo Uses para
possibilitando a incluso de registros. adicionarmos a PSL que a Library do
Essa tarefa ser efetuada atravs do sin- PocketStudio onde esto os mtodos
cronismo entre dispositivo e PC. necessrios para manipularmos o BD
Poderamos criar e utilizar a tela para dentro da Unit PSDatabase. Aps a seo
editar os registros e envi-los ao PC, Uses declaramos uma nova seo Const
porm em nosso exemplo ser apenas onde informaremos o DBName, DBType
Ricardo C. Boaro
(rboaro@aquasoft.com.br) mais uma janela de consulta. As telas e os ndices para recuperao e configu-
trabalha com desenvolvimento de sistemas que iro manipular informaes so as rao dos valores nos campos da tabela
em Delphi h mais de 10 anos e PocketStudio de pedidos e itens do pedido. de Produtos.
h 3 anos. Atualmente gerente de inform- O primeiro passo criarmos a tabela Aps a definio dos campos e seus
tica na Di Hellen Indstria de Cosmticos, e
produtos para armazenarmos os dados respectivos ndices, declaramos uma se-
atual como instrutor certificado Borland na
Aquasoft Tecnologia da Informao parceira e podermos navegar entre os registros. o Var, onde informaremos ao PocketS-
da Borland, em Porto Alegre RS. Borland Lembrando que essa tabela ser preen- tudio o FieldDefs e um array. Tambm
Instrutor, Delphi 7, 2007 e Certified. chida no momento do sincronismo com iremos declarar as variveis globais que

42 ClubeDelphi - Desenvolvendo uma Aplicao Completa com PocketStudio


TUTORIAL M INI-CURSO

iro referenciar nossa base de dados em artigo anterior para incluso de Bitmaps navegarmos entre os registros. Para isso
todo projeto. A estrutura de todas as ta- e associao deles aos botes da parte in- utilizaremos as funes da PSDataBase
belas criadas no PocketStudio sempre ferior. O boto que ficar ao lado do ttulo da PSL. Pressione F12 no formulrio para
a mesma, como uma receita de bolo. Mu- do formulrio se chamar BtnVoltar. visualizar a pgina de cdigo e localize
damos apenas nome da tabela e campos, Antes de codificarmos os botes, pre- a palavra reservada Implementation.
mas a maneira de montar e manipular cisamos criar uma funo para carregar Declare o procedimento da Listagem 2
exatamente igual para todas. os dados na tela de consulta conforme abaixo de Implementation.
Como no artigo anterior criamos a tabe-
la de clientes, no vou entrar em detalhes
Listagem 1. Cdigo completo da tabela de Produtos
de como funciona cada funo criada em
unit ProdutosDB;
nossa tabela. Altere a Unit ProdutosDB interface
conforme a Listagem 1. uses PSL;
const
ProdutosDBName = ProdutosDB;
Criando a Tela de Consulta a ProdutosDBType = Rsc(DBPR);
Prod_Codigo = 0;
Produtos Prod_DescProd = 1;
Prod_Preco = 2;
Criada a tabela de produtos, vamos adi- Prod_Estoque = 3;
Prod_Tam = 4;
cionar um novo formulrio para criarmos Prod_Un = 5;
var
a tela de consulta. No menu principal FieldDefs : array[0..5] of TFieldDef =
do PocketStudio acesse File|New>Form ((DataType: ftUInt16),
(DataType: ftString),
e salve-o como UDadosProdutos.pas (DataType: ftDouble),
(DataType: ftUInt32),
usando File>Save ou pelas teclas de atalho (DataType: ftString),
(DataType: ftString));
CTRL + S. Altere a propriedade Name bProdutosInclui : Boolean;
para FrmDadosProdutos e seus Title DBPro : TDatabase;

para Consulta a Produtos. Desenhe function Open: Boolean;


function Close: Boolean;
uma tela semelhante a Figura 1. function ProcuraCodigo(Codigo: UInt16): Boolean;
Nomeie os componentes do tipo Field implementation
com os nomes FldCodigo, FldDescri-
function Open: Boolean;
cao, FldPreco, FldEstoque, FldTa- var
Atributos : UInt16;
manho e FldUn, respectivamente. begin
Result := PSDatabase.Open(DBPro, ProdutosDBName,
Insira cinco botes, sendo, quatro na dmModeReadWrite);
parte inferior que se chamaro BtnPri- if not Result then
begin
meiro, BtnAnterior, BtnProximo e Result := PSDatabase.CreateDatabase(ProdutosDBName,
Creator, ProdutosDBType);
BtnUltimo, seguindo da esquerda para if Result then
Result := PSDatabase.Open(DBPro, ProdutosDBName,
a direita. Aproveite e repita os passos do dmModeReadWrite);
end;
if not Result then
begin
ShowSystemError(PSDatabase.LastError);
Exit;
end;
PsDataBase.DataBaseAttributes(ProdutosDBName,
Atributos);
Atributos := Atributos and $FFF7;
PsDataBase.SetDataBaseAttributes(ProdutosDBName,
Atributos);
PSDatabase.SetFieldDefs(DBPro, FieldDefs[0],
SizeOf(FieldDefs) div SizeOf(FieldDefs[0]));
end;
function Close: Boolean;
begin
Result := PSDatabase.Close(DBPro);
end;

function ProcuraCodigo(Codigo: UInt16): Boolean;


begin
PSDatabase.First(DBPro);
while not PSDatabase.EOF(DBPro) do
begin
if PSDatabase.FieldUInt16(DBPro, Prod_Codigo) =
Codigo then
begin
Result := True;
exit;
end;
PSDatabase.Next(DBPro);
end;
Result := False;
end;
end.
Figura 1. Exemplo de tela de Consulta a Produtos

Edio 94 - ClubeDelphi 43
Na funo CarregaProdutos utilizamos vertido na propriedade Text do Field. de nossa tabela de produtos declare as
uma varivel Buffer que um Array de Para isso utilizamos a Unit PsField da Units ProdutosDB e UPrincipal no Uses
Char para auxiliar a transformao do PSL e o mtodo SetText. Um passo im- do formulrio atual. Observe o cdigo
cdigo do produto de UInt16 para String. portante na funo CarregaProdutos a serguir:
Para isso utilizamos a funo StrIToA. fazer um teste para saber se existem
implementation
Aps isso recuperamos o valor do campo registros na tabela, pois caso no exis- uses
ProdutosDB, UPrincipal;
cdigo da tabela e o transformarmos tam, uma exceo ser gerada. Para
String. Por fim recebemos o valor con- isso usamos o mtodo RecourdCount Em seguida podemos codificar o
da Unit PsDataBase. restante dos botes. Na Listagem 3
O prximo passo codificarmos os encontramos o cdigo de cada boto.
Nota do DevMan botes, por isso iniciaremos pelo bo- Observe que a codificao muito sim-
to de Voltar. D um clique duplo no ples. Apenas chamamos os mtodos
Nas verses mais antigas do PocketStudio, principalmente boto BtnVoltar e seremos levados ao First (primeiro), Prior (anterior), Next
as verses Trial, a Unit LibAll, que possue diversas funes fonte da Unit no evento Select. Digite (prximo) e Last (ltimo), apropriado
de converso, no vinha instalada no diretrio de instalao
do PS. Por isso, caso tenha problemas ao compilar a apenas o cdigo que segue: para cada boto.
aplicao, recomendado que salve o arquivo LibAll.pas Note que em todos os botes utilizamos
FrmGotoForm(FrmPrincipal);
no diretrio do seu cdigo fonte. Esse arquivo pode ser a PsDataBase e os mtodos de navegao
encontrado juntamente com os fontes de exemplo desse
artigo. Acesse o portal DevMedia e localize a pgina de Para que possamos fazer referncia passando como parmetro a varivel
downloads das revistas ClubeDelphi. ao formulrio principal e s funes DBProd. Essa varivel faz referncia a
nossa tabela de produtos.
Para finalizar a codificao da tela de
Listagem 2. Procedimento de carga de Produtos consulta de produtos vamos codificar o
evento OnOpen do formulrio para apre-
procedure CarregaProdutos;
var sentarmos os dados da tabela. Clique no
Buffer: Array [0..10] of Char;
begin formulrio e pressione F11 para visuali-
if PsDataBase.RecordCount(DBPro) > 0 then
begin
zar suas propriedades e eventos. Na aba
StrIToA(Buffer, PsDataBase.FieldUInt16(DbPro, Events clique duas vezes sobre o evento
Prod_Codigo));
PsField.SetText(FldCodigo, Buffer); OnOpen e acrescente uma chamada ao
PsField.SetText(FldDescricao, PsDatabase. procedimento CarregaProdutos. O cdigo
FieldStringPtr(DbPro, Prod_DescProd));
completo ficar como a seguir:
FormatFloat(Buffer, PSDatabase.FieldDouble(DBPro,
Prod_Preco), 2); procedure FrmDadosProdutosOpen;
PsField.SetText(FldPreco, Buffer); begin
CarregaProdutos;
StrIToA(Buffer, PsDataBase.FieldUInt32(DbPro, PSForm.Draw;
Prod_Estoque)); end;
PsField.SetText(FldEstoque, Buffer);
O nico detalhe agora que devemos
PsField.SetText(FldUn, PsDatabase.FieldStringPtr(
DbPro, Prod_Un)); incluir uma chamada ao formulrio de
PsField.SetText(FldTamanho, PsDatabase.
FieldStringPtr(DbPro, Prod_Tam)); produtos na tela principal de nosso sis-
end; tema, por isso volte ao formulrio princi-
end;
pal, clique duas vezes no boto Produtos
Listagem 3. Cdigo dos botes de navegao e digite a chamada como segue:
procedure BtnPrimeiroSelect; FrmGotoForm(FrmDadosCliente);
begin
PsDataBase.First(DBPro);
CarregaProdutos; H mais uma configurao necessria
end;
a ser feita em nosso projeto para que os
procedure BtnAnteriorSelect;
begin formulrios sejam efetivamente cha-
PsDataBase.Prior(DBPro); mados. Assim como fizemos no artigo
CarregaProdutos;
end; anterior, teremos que alterar o mtodo
procedure BtnProximoSelect; ApplicationHandleEvent de forma que
begin
PsDataBase.Next(DBPro);
possa chamar o formulrio que dese-
CarregaProdutos; jamos. Para isso, abra o arquivo Vendas
end;
equivalente ao Project>Source do Delphi.
procedure BtnUltimoSelect;
begin Pressione CTRL + F12 e selecione-o.
PsDataBase.Last(DBPro);
CarregaProdutos;
Ser necessrio fazer a alterao apenas
end; do case..of ao final do procedimento.
Veja a seguir:

44 ClubeDelphi - Desenvolvendo uma Aplicao Completa com PocketStudio


TUTORIAL M INI-CURSO

case FormID of
FrmPrincipal: Listagem 4. Cdigo completo do evento ApplicationHandleEvent
FrmSetEventHandler(Form, uPrincipal.
HandleEvent); function ApplicationHandleEvent(var Event: EventType)
FrmClientes: : Boolean;
FrmSetEventHandler(Form,UDadosClientes. var
HandleEvent); FormID: UInt16;
FrmDadosProdutos: Form: FormPtr;
FrmSetEventHandler(Form, begin
UDadosProdutos.HandleEvent); Result := False;
end; if Event.eType = frmLoadEvent then
begin
Veja que adicionamos o formulrio FormID := Event.frmLoad.formID;
Form := FrmInitForm(FormID);
FrmDadosProdutos ao case..of. Cada FrmSetActiveForm(Form);
case FormID of
formulrio que vamos adicionando ao FrmPrincipal: FrmSetEventHandler(Form,
sistema, necessrio fazer alterao uPrincipal.HandleEvent);
FrmClientes: FrmSetEventHandler(Form,
nesse evento. Veja o evento completo na UDadosClientes.HandleEvent);
FrmDadosProdutos: FrmSetEventHandler(Form,
Listagem 4. UDadosProdutos.HandleEvent);
end;
Result := True;
Criando a tela de Pedidos e Itens end
end;
O primeiro passo antes de criarmos a
tela propriamente dita, criar as tabelas
necessrias para armazenar os dados
digitados. Uma boa dica, seguir os mes-
mos passos usados para criar a tabelas de
clientes e produtos. Vejamos os principais
passos a executar:
Crie uma nova Unit usando o menu
File|New>Unit e salve-a com o nome que
preferir. Nessa srie de artigos estamos
usando NomeDaTabelaDB.pas, ex:
ProdutosDB.pas;

Nota do DevMan
Formulrios Destrutivos e No Destrutivos
At agora trabalhamos apenas com formulrios
Destrutivos, mas existem duas formas de se trabalhar com
formulrios no PocketStudio como podemos ver a seguir:
Modo Destrutivo: neste modo todos os objetos visuais
do formulrio atual e seu contedo sero perdidos.
Se necessitarmos preservar os dados informados no
formulrio precisamos criar funes para salvar e restaurar
os dados. Nesse modo utilizamos a funo FrmGotoForm
para alternar entre os formulrios.
Modo No Destrutivo: o problema dessa abordagem
que no podemos dar mais de um passo, ou seja,
imaginemos trs formulrios. Podemos navegar do
primeiro para o segundo e voltar para o primeiro, mas
se tentarmos navegar do primeiro direto para o terceiro
formulrio, uma exceo ser gerada. Nessa abordagem
usamos a funo FrmPopupForm para ir para o formulrio
e FrmReturnToForm para retornar.
Tenha em mente que se precisarmos navegar entre vrios
formulrios e voltar aleatoriamente entre eles, devemos
utilizar o modo destrutivo. Tambm devemos considerar
o que o modo No Destrutivo ir carregar a memria do
dispositivo medida que os formulrios so chamados.
Em resumo, precisamos considerar cada situao e analisar
o que realmente necessrio, evitando maiores problemas
na aplicao.

Edio 94 - ClubeDelphi 45
Crie as constantes de nome de cam- dDB.pas. O cdigo fonte completo da File|New>Form e salve-o como UPedidos.
pos e as funes necessrias para abrir criao de ambas tabelas podemos ver pas e seu Name modifique para FrmPe-
e fechar a tabela; nas Listagens 5 e 6. didos. Modifique tambm a propriedade
Crie uma funo para naveo dos Title para Cabealho do Pedido. Desenhe
dados, CarregaDados por exemplo; Desenhando a tela de pedidos uma tela semelhante a Figura 2.
No caso de Pedidos e Itens de Pedidos, A tela de pedidos e itens de pedido fu- H trs novidades aqui, ou seja, trs no-
devemos criar duas novas Units, que se gir um pouco do que j vimos at agora. vos componentes que no vimos at ago-
chamaro PedidosDB.pas e ItemPe- Crie um novo formulrio usando o menu ra. So eles, PopupTrigger, SelectorTrigger e
List. O componente PopupTrigger em con-
junto com List funciona como se fosse um
Listagem 5. Cdigo da tabela PedidosDB
ComboBox do Delphi. Isso significa que
unit PedidosDB; podemos simular listas suspensas. Para
interface
uses PSL; isso insira no formulrio um componente
const PopupTrigger(PopCondicoes) da paleta
PedidosDBName = PedidosDB; Form. Altere o seu Caption para Cond.
PedidosDBType = Rsc(DBPE);
Ped_NumeroPedido = 0; Pagto, assim enquanto no houver um
Ped_CodCli = 1;
Ped_Emissao = 2; item selecionado, a indio de Condies
Ped_Cond = 4;
Ped_Total = 5; de Pagamento estar ativa. Inclua agora
var
um componente List(LstCondicoes)
FieldDefs : array[0..4] of TFieldDef = e insira alguns itens na propriedade
((DataType: ftUInt32),
(DataType: ftUInt16), Items do controle. Em seguida retorne ao
(DataType: ftDateTime),
(DataType: ftString), componente PopCondicoes e selecione o
(DataType: ftDouble)); LstCondicoes na propriedade PopupList.
bPedidosInclui : Boolean; Isso far com que a lista de condies de
dPedidoData : DateTimeType;
DBPed : TDatabase; pagamento aparea ao clicar no Popup-
function Open: Boolean;
Trigger. Para evitar que o PopCondicoes
function Close: Boolean; aparea constantemente, marque sua
function ProcuraCodigo(Codigo: UInt32): Boolean;
propriedade Visible com o valor False.
implementation

function Open: Boolean;


begin www.devmedia.com.br/clubedelphi/portal.asp
Result := PSDatabase.Open(DBPed, PedidosDBName,
dmModeReadWrite); Acesse agora o mesmo o portal do assinante ClubeDelphi e assista a
if not Result then
begin uma vdeo aula de Ricardo Boaro que mostra como trabalhar com os
Result := PSDatabase.CreateDatabase(PedidosDBName, componentes SelectorTrigger e List.
Creator, PedidosDBType);
if Result then www.devmedia.com.br/articles/viewcomp.asp?comp=7606
Result := PSDatabase.Open(DBPed, PedidosDBName,
dmModeReadWrite);
end;

if not Result then


begin
ShowSystemError(PSDatabase.LastError);
Exit;
end;

PSDatabase.SetFieldDefs(DBPed, FieldDefs[0],
SizeOf(FieldDefs) div SizeOf(FieldDefs[0]));
end;

function Close: Boolean;


begin
Result := PSDatabase.Close(DBPed);
end;

function ProcuraCodigo(Codigo: UInt32): Boolean;


begin
PSDatabase.First(DBPed);
while not PSDatabase.EOF(DBPed) do
begin
if PSDatabase.FieldUInt32(DBPed, Ped_NumeroPedido)
= Codigo then
begin
Result := True;
exit;
end;
PSDatabase.Next(DBPed);
end;
Result := False;
end;
end.
Figura 2. Exemplo de tela de Consulta a Pedidos

46 ClubeDelphi - Desenvolvendo uma Aplicao Completa com PocketStudio


TUTORIAL M INI-CURSO

Os nomes dos componentes seguem a Abaixo do campo Emisso, insira um da famlia dos botes, portanto uti-
mesma linha empregada nas telas ante- boto comum e troque seu Caption para lizamos a Unit PsButton da PSL para
riores. Use o prefixo Fld para campos Localiza Cliente. Aproveite e modifi- trabalharmos com ele. A diferena
e Btn para botes. Nessa janela en- que a propriedade Frame usando a opo que podemos chamar formulrios em
contramos os campos FldNumPedido, frNone, assim retiramos sua borda. modo modal com ele. Esse componente
FldCliCodigo, FldCliNome e Fld- Com exceo dos controles SelectorTri- ser usado na Emisso, portanto insira
ValTotal. E ainda os botes BtnNovo, gger, PopupTrigger e List, j trabalhamos um SelectorTrigger(SltEmissao) logo
BtnItens, BtnPrimeiro, BtnAnte- com os componentes utilizados nessa direita do Label Emisso;
rior, BtnProximo, BtnUltimo, Btn- tela, sendo assim cabe um explicao PopupTrigger: Mais um componente
Fim e BtnGravar, respectivamente da sobre os novos componentes. da famlia dos botes e sua funciona-
esquerda para a direita. SelectorTrigger: Este componente lidade depende do uso em conjunto
com um objeto lista. Ele sozinho no
tem utilidade, imaginemos ele como o
Listagem 6. Cdigo da tabela ItemPedDB
conhecido ComboBox do Delphi, em
unit ItemPedDB; run-time ele muito similar;
interface
uses PSL; List: Lista um objeto bastante uti-
const lizado por ns desenvolvedores, pois
ItemPedDBName = ItemPedDB; est disponvel em praticamente todos
ItemPedDBType = Rsc(DBIP);
Itp_NumeroPed = 0; os ambientes de desenvolvimento. Du-
Itp_CodProd = 2;
Itp_Qtde = 3; rante o desenvolvimento da nossa srie
Itp_Preco = 4;

var Listagem 7. Cdigo de todos os botes da tela de Pedidos


FieldDefs : array[0..3] of TFieldDef =
((DataType: ftUInt32),
procedure BtNovoSelect;
(DataType: ftUInt16),
begin
(DataType: ftUInt16),
PsDataBase.Insert(DBPed);
(DataType: ftDouble));
end;
procedure BtPedItensSelect;
bItemPedInclui : Boolean;
begin
DBItp : TDatabase;
FrmGotoForm(FrmPedidoItem);
end;
function Open: Boolean;
procedure BtInicioSelect;
function Close: Boolean;
begin
function ProcuraCodigo(Codigo: UInt16): Boolean;
PsDataBase.First(DBPed);
end;
implementation
procedure BtAnteriorSelect;
begin
function Open: Boolean;
PsDataBase.Prior(DBPed);
begin
end;
Result := PSDatabase.Open(DBItp, ItemPedDBName, dmModeReadWrite);
procedure BtProximoSelect;
if not Result then
begin
begin
PsDataBase.Next(DBPed);
Result := PSDatabase.CreateDatabase(ItemPedDBName, Creator, ItemPedDBType);
end;
if Result then
procedure BtFimSelect;
Result := PSDatabase.Open(DBItp, ItemPedDBName, dmModeReadWrite);
begin
end;
PsDataBase.Last(DBPed);
end;
if not Result then
procedure BtGravarSelect;
begin
begin
ShowSystemError(PSDatabase.LastError);
PsDataBase.Post(DBPed);
Exit;
end;
end;
procedure BtExcluirSelect;
begin
PSDatabase.SetFieldDefs(DBItp, FieldDefs[0],
PsDataBase.Delete(DBPed);
SizeOf(FieldDefs) div SizeOf(FieldDefs[0]));
end;
end;
procedure BtnVoltarSelect;
begin
function Close: Boolean;
FrmGotoForm(FrmPrincipal);
begin
end;
Result := PSDatabase.Close(DBItp);
end;
Listagem 8. Cdigo dos botes Produtos e Pedidos
function ProcuraCodigo(Codigo: UInt16): Boolean;
begin
..
PSDatabase.First(DBItp);
uses
while not PSDatabase.EOF(DBItp) do
UDadosClientes, UDadosProdutos,
begin
UDadodsPedidos;
if PSDatabase.FieldUInt16(DBItp, Itp_NumeroPed) = Codigo then
..
begin
procedure btnProdutosSelect;
Result := True;
begin
exit;
FrmGotoForm(FrmDadosProdutos);
end;
end;
PSDatabase.Next(DBItp);
end;
procedure btnPedidosSelect;
Result := False;
begin
end;
FrmGotoForm(FrmDadosPedidos);
end.
end;

Edio 94 - ClubeDelphi 47
de artigos trabalharemos muito com Precisamos agora preparar o sistema dever adicionar ao Uses do formulrio
a List e entenderemos suas principais para que possa abrir as novas telas a principal as duas Units para referncia.
funcionalidades. partir do formulrio principal. Por- Se preferir veja o trecho cdigo dos dois
Aps entendermos o funcionamento tanto, retorne o formulrio principal e botes na Listagem 8.
dos novos componentes, vamos codificar codifique, no evento OnSelect dos botes Apenas para lembrar, devemos acres-
nosso fonte. Na Listagem 7 encontramos Produtos e Pedidos, uma chamada ao centar o formulrio de pedidos no Unit
o cdigo de cada boto incluso no exem- mtodo FrmGotoForm indicando qual principal do projeto, na funo Appli-
plo. Codifique conforme necessrio. formulrio ser aberto. No esquea que cationHandleEvent, para que o sistema
operacional do PalmOS reconhea o
Listagem 9. Cdigo do mtodo ApplicationHandleEvent alterado formulrio de Pedidos e Produtos como
function ApplicationHandleEvent(var Event: EventType):
parte da aplicao. Abra a unit Vendas
Boolean; e adicione a chamada ao case..of no
var
FormID: UInt16; mtodo. Veja o cdigo completo na
Form: FormPtr;
begin Listagem 9.
Result := False; Aproveitando que estamos mexendo
if Event.eType = frmLoadEvent then
begin na Unit Vendas, precisamos fazer dois
FormID := Event.frmLoad.formID;
Form := FrmInitForm(FormID); ltimos ajustes. Precisamos abrir e fe-
FrmSetActiveForm(Form);
case FormID of char as tabelas ProdutosDB, PedidosDB e
FrmPrincipal: FrmSetEventHandler(Form, ItemPedDB nos mtodos StopApplication
uPrincipal.HandleEvent);
FrmClientes: FrmSetEventHandler(Form, e StartApplication.
UDadosClientes.HandleEvent);
FrmDadosProdutos: FrmSetEventHandler(Form, Localize-os e altere conforme a Lis-
UDadosProdutos.HandleEvent);
FrmDadosPedidos: FrmSetEventHandler(Form,
tagem 10. Observe que o evento Sto-
UDadodsPedidos.HandleEvent); pApplication fecha as tabelas usando o
end;
Result := True; mtodo Close e o evento StartApplication
end.
end; abre-as usando o mtodo Open. A nica
particularidade, que na abertura das
Listagem 10. Cdigo dos eventos StopApplication e StartApplication alterados
tabelas, ns testamos se a tabela pode ser
function StartApplication: Boolean; aberta. Em caso negativo enviamos uma
begin
{ Abre o banco de dados de Clientes. Se no conseguir mensagem informando que a tabela no
abrir, }
{ no executa a aplicao}
pode ser encontrada.
if not ClientesDB.Open then
begin
ShowMessage(Tabela de Clientes no encontrada!); Concluso
Result := False;
Exit; Nesse artigo criamos a tela de consulta
end;
if not ProdutosDB.Open then
a produtos, o banco de dados de pedidos
begin e itens do pedido, conhecemos os concei-
ShowMessage(Tabela de Produtos no encontrada!);
Result := False; tos de formulrios do Palm, destrutivo
Exit;
end; e no destrutivo, e criamos a tela do
if not PedidosDB.Open then cabealho do pedido. No prximo artigo
begin
ShowMessage(Tabela de Itens no encontrada!); criaremos a tela de Itens do Pedido e
Result := False;
Exit; construiremos o Conduit. At o prximo
end;
if not ItemPedDB.Open then artigo, e bons cdigos a todos!
begin
ShowMessage(Tabela de Itens no encontrada!);
Result := False;
Exit;
end;
Result := PSApplication.CheckROMVersion($2003000);
if not Result then
begin
FrmCustomAlert(AlertIncompatible,2.0, nil, nil);
Exit;
end;
D seu feedback sobre esta edio! Feedback
eu
FrmGotoForm(FrmPrincipal);
s
D

end;
A Java Magazine tem que ser feita ao seu
sobre e

procedure StopApplication; gosto. Para isso, precisamos saber o que


begin
s

ta
e
voc, leitor, acha da revista!
d i o
ClientesDB.Close;
ProdutosDB.Close;
PedidosDB.Close;
ItemPedDB.Close;
D seu voto sobre este artigo, atravs do link:
FrmCloseAllForms;
end; www.devmedia.com.br/javamagazine/feedback

48 ClubeDelphi - Desenvolvendo uma Aplicao Completa com PocketStudio


AMIGO
...s pra lembrar,
Existem coisas sua assinatura pode
estar acabando!
que no
conseguimos
ficar sem!
Renove J!

www.devmedia.com.br/renovacao
Para mais informaes:
www.devmedia.com.br/central
Seo DELPHI Seo EASY DELPHI Seo PHP

Nesta seo voc encontra artigos para iniciantes


na linguagem Delphi

Envio de E-mails com componentes


da paleta Indy
Veja como enviar e-mails utilizando os componentes da paleta Indy

O
envio de e-mails automatizado com componentes da paleta Indy.
em sistemas simplesmente Com o Delphi aberto, utilize o menu
uma ferramenta fantstica. File|New>Application para criar uma
Atravs de componentes e mtodos, o nova aplicao. Altere a propriedade
desenvolvedor disponibiliza em seu Name do formulrio principal para frm-
sistema uma agenda de e-mails, que ao SendMail e o Caption altere para Envio
ser configurada dispara e-mails com re- de E-mails. Salve a Unit do formulrio
latrios, avisos, entre outros, automatica- principal como uEmail.pas e o projeto
mente aos seus destinatrios. No Delphi, salve como prjEmail.dpr.
podemos contar com os componentes
da paleta Indy para criar um sistema de
envio de e-mails. Nota do DevMan
Neste artigo veremos a criao de um
sistema simples de envio de mensagens De forma bem simples, o envio de e-mails funciona
eletrnicas (e-mail), onde faremos alm basicamente atravs de um cliente de e-mail acessado
das configuraes normais de remetente, pelo browser de internet ou atravs de gerenciadores
instalados e configurados nas estaes de trabalho,
destinatrio, assunto e mensagem a confi- tais como Microsoft Outlook, Outlook Express, Mozilla
Maikel Marcelo Scheid gurao de autenticao dos usurios por Thunderbird entre outros. O usurio que necessita de sua
(maikelscheid@gmail.com) SMTP, tambm a configurao para que o utilidade precisa ter uma credencial de cadastro (usurio
tcnico em Informtica com nfase em An- e senha) em um servidor de e-mails SMTP (Simple Mail
e-mail possa ser enviado com anexos. Transfer Protocol) para o envio dos e-mails. Toda vez
lise e Programao de Sistemas. Atua na rea
que a ao de envio for requisitada ao gerenciador, uma
de Desenvolvimento de Softwares em Delphi
para plataforma Win32 e .NET com banco de Criando a aplicao autenticao ser realizada no servidor, e este por sua
vez ir proceder com o envio do texto/arquivo para o
dados Firebird e MS SQL. membro da Equipe Utilizaremos o Delphi 7 para a cria- destinatrio pr-informado.
Editorial ClubeDelphi. o do sistema de envio de e-mail

50 ClubeDelphi - Envio de E-mails com componentes da paleta Indy


EASY DELPH I

Ajuste as dimenses do formulrio al-


terando sua propriedade Height para 580
e Width para 510. Logo no cabealho do
formulrio arraste da paleta Standard um
componente GroupBox(gbSMTP), alte-
rado sua propriedade Caption para Au-
tenticao de Usurios SMTP. Dentro
do componente gbSMTP adicione ao topo Figura 1. Componentes para autenticao SMTP
um componente CheckBox(CkSMTP),
alterando sua propriedade Caption para
Meu servidor requerer uma autentica-
o SMTP para envio de e-mails, que
ser utilizado nos casos em que neces-
sria autenticao para realizar o envio
da mensagem. Adicione logo abaixo do
ckSMTP trs componentes Label, alteran-
do a propriedade Caption de ambos para
Host, Usurio e Senha, respecti-
vamente. Logo abaixo cada Label adicio-
nado iremos inserir trs componentes
de texto. Arraste da paleta Additional
um componente MaskEdit(edtHost) e
altere sua propriedade EditMask para
999\.999\.999\.999;1;_, sendo esta a
Figura 2. Cabealho do E-mail
mscara para formatao do endereo
TCP/IP do servidor de autenticao
SMTP a ser utilizado para o envio.
Altere tambm a propriedade Text do
componente para 000.000.000.000.
Arraste agora da paleta Standard dois
componentes Edit, alterando a proprie-
dade Name de ambos para edtUsuario
e edtSenha, respectivamente de acordo
com os Captions dos Labels acima. Seu
gbSMTP ficar semelhante imagem
ilustrada na Figura 1.
Ad ic ione i med iata mente aba i xo
ao gbSMTP um novo componente
GroupBox(gbEmail), alterando seu Cap-
tion para Cabealho do E-mail. Dentro
do gbEmail adicione ao topo um Label
com o Caption De: e imediatamente
abaixo arraste da paleta Standard um
Edit(emailDe) e remova o valor da sua
propriedade Text deixando-o em branco.
Logo abaixo ao emailDe, arraste um novo
Label com o Caption Para: inserindo em
seguida da paleta Standard um compo-
nente Memo(edtPara) e removendo seu
texto na propriedade Lines. Altere tam-
bm a propriedade ScrollBars do edtPara
para ssVertical fazendo com que uma
barra de rolagem no sentido vertical seja
exibida no componente. Ainda abaixo
do mesmo, arraste um Label com o Cap- Figura 3. Formulrio de envio de e-mails

Edio 94 - ClubeDelphi 51
tion Assunto e insira um componente Ao final do formulrio, adicione ainda cada componente, veja para qual funo
Edit(edtAssunto), removendo tambm da paleta Additional dois componentes ser utilizado e quais as configuraes
o seu Text. Ao final desta configurao, BitBtn(btnEnviar e btnCancelar). necessrias:
seu formulrio dever estar de acordo Altere a propriedade Caption de ambos - IdSMTP (CompSMTP) da paleta
com a Figura 2. para ENVIAR e CANCELAR, respec- IndyClients: ser o responsvel pela
Para incluso de anexos ao e-mail, adi- tivamente. Inclua, atravs da propriedade comunicao direta com o servidor de
cione logo abaixo ao gbEmail um novo Glyph, uma imagem a cada um dos botes. autenticao e envio dos e-mails SMTP.
GroupBox(gbAnexo), alterando seu Ao final seu formulrio estar com o Layout As configuraes de suas propriedades
Caption para Anexo e arraste para e semelhante a Figura 3. Veremos a seguir sero realizadas em tempo de execuo
dentro do mesmo um componente os componentes necessrios para envio do e veremos a seguir.
ListView(emailAnexo) da paleta Win32. e-mail e adio dos anexos mensagem. - IdMessage (CompMensagem) da
Ainda abaixo ao gbAnexo, adicione mais um paleta Indy Misc: componente no qual
GroupBox(gbMensagem) e defina seu Cap- Componentes para envio do e-mail criamos o e-mail. Nele que sero adi-
tion para Mensagem. Arraste para dentro e adio de anexos cionados o assunto, mensagem, entre
do gbMensagem um componente RichEdit Veremos a seguir os componentes ne- outras partes do e-mail. Sua configu-
(emailMensagem) da paleta Win32 e re- cessrios a serem adicionados no formu- rao tambm ser realizada em tempo
mova o texto da sua propriedade Lines. lrio para o envio do e-mail. Ao lado de de execuo.
- IdAntiFreeze (AntiGelo) da paleta
Indy Misc: sua utilidade no deixar a
Listagem 1. Adicionando anexos ao e-mail
aplicao congelar enquanto o e-mail
procedure TfrmSendMail.Anexararquivo1Click(Sender: TObject); est sendo enviado. O componente man-
var tm o formulrio atualizado, permitindo
files: TListItem;
que at durante o envio o usurio possa
begin continuar interagindo com o sistema.
if OpenAnexo.Execute then
- OpenDialog (OpenAnexo) da paleta
begin
files := emailAnexo.Items.Add; Dialogs: ser utilizado para localizar os
files.Caption := OpenAnexo.FileName;
end; anexos a serem adicionados ao e-mail.
end; No requer nenhuma configurao es-
pecial, pois ser utilizado apenas para
Listagem 2. Cdigo para excluso de anexo
localizar os arquivos.
procedure TfrmEmails.Excluir1Click(Sender: TObject);
var - PopupMenu (MenuAnexo) da pa-
Arquivo : string; leta Standard: relacione o componente
begin
Arquivo := ExtractFileName(emailAnexo.Items.Item[ propriedade PopupMenu do componente
emailAnexo.ItemIndex].Caption);
if Application.MessageBox(PAnsiChar(Deseja excluir emailAnexo. Ser utilizado no clique do bo-
o arquivo + Arquivo + ?), Excluir anexo,
MB_YESNO) = idYes then
to direito sobre o componente emailAnexo
emailAnexo.Items.Delete(emailAnexo.ItemIndex); para adicionar ou remover arquivos. Com
end;
um duplo clique sobre o componente Me-
nuAnexo, crie dois itens de menu (Anexar
arquivo e Excluir arquivo).
- ImageList (Imagens) da paleta Win32:
componente onde iremos adicionar duas
imagens que sero listadas junto com o
componente MenuAnexo. Com um duplo
clique sobre o componente Imagens utilize
o boto Add e localize dois cones relacio-
nados aos menus criados no PopupMenu.
Por default voc ir encontrar cones para
serem adicionados no caminho C:\Arqui-
vos de programas\Arquivos comuns\Borland
Shared\Images\Buttons.
Aps adicionadas duas imagens, volte
ao componente MenuAnexo e relacione
a propriedade Images ao componente
Imagens. Com um duplo clique sobre
Figura 4. Envio do e-mail o componente, selecione cada um dos

52 ClubeDelphi - Envio de E-mails com componentes da paleta Indy


EASY DELPH I

itens de menu adicionados e na pro- o SMTP como servidor de sada das da formatao do texto a ser enviado.
priedade ImageIndex selecione o cone mensagens. Estando corretas todas as Aplique este recurso ao seu sistema dei-
correspondente. informaes, seu e-mail ser enviado xando-o mais funcional e atrativo para
com sucesso (Figura 4). seu cliente. Abrao e at a prxima.
Anexando arquivos ao E-mail
Com um clique duplo sobre o componen- Concluso D seu feedback sobre esta edio! eu
Feedback

s
te MenuAnexo, selecione o item de menu Neste artigo aprendemos a criar uma

D
A Java Magazine tem que ser feita ao seu

sobre e
Anexar arquivo e adicione a seu evento aplicao de envio de e-mails utilizan-
gosto. Para isso, precisamos saber o que
OnClick o cdigo da Listagem 1, obedecen- do os componentes da paleta Indy do

s
ta
edio
voc, leitor, acha da revista!
do a criao de uma varivel do tipo TLis- Delphi. Com estes cdigos voc poder
tItem para que seja instanciado o arquivo implementar novas funcionalidades, D seu voto sobre este artigo, atravs do link:
selecionado e exibido no emailAnexo. como por exemplo opes de solicitao www.devmedia.com.br/javamagazine/feedback
O cdigo bem simples, apenas cria- de entrega e leitura da mensagem, alm
mos uma varivel do tipo TListItem e
chamamos o mtodo Execute do controle Listagem 3. Enviando o e-mail
OpenAnexo. Aps a seleo de um arqui-
procedure TfrmSendMail.btnEnviarClick(Sender: TObject);
vo na caixa de dilogo, adicionamos um var
i : integer;
novo item ao emailAnexo, componente begin
ListView, e configuramos o seu Caption try
{ Verifica se o campo remetente foi preenchido }
com o nome do arquivo selecionado. if emailDe.Text <> then
begin
J no item de menu Excluir arqui- { Verifica se o campo destinatsio foi preenchido }
if emailPara.Text <> then
vo removemos o arquivo da lista de begin
anexos. Primeiro copiamos o nome do { Verifica se o campo assunto foi preenchido }
if emailAssunto.Text <> then
arquivo selecionado em uma varivel begin
{ Verifica se a mensagem foi preenchida }
do tipo String e em seguida chamamos if emailMensagem.Lines.Text <> then
begin
o mtodo Delete do componente emailA- { Verifica se o servidor de SMTP requer autenticao. De acordo com a
nexo. Veja a Listagem 2. seleo, o tipo de autenticao do componente ser alterada }
if ckSMTP.Checked then
CompSMTP.AuthenticationType := atLogin else

Enviando o e-mail CompSMTP.AuthenticationType := atNone;


{ Configura o Host do servidor de SMTP a ser utilizado para o envio do e-mail }
CompSMTP.Host := edtHost.Text;
Para realizar o envio do e-mail pre- { Configurao do usurio e senha para autenticao no Host de SMTP }
cisamos criar em tempo de execuo CompSMTP.Username := edtUsuario.Text;
CompSMTP.Password := edtSenha.Text;
algumas configuraes relacionadas aos { Faz a conexo ao servidor SMTP }
CompSMTP.Connect;
componentes adicionados. Adicione ao { Verifica se o servidor SMTP foi conectado }
if CompSMTP.Connected then
evento OnClick do btnEnviar o cdigo da begin
Listagem 3, que encontra-se comentado de { Configura a mensagem a ser enviada. Passagem de valores as propriedades }
CompMensagem.Clear;
acordo com cada ao que est ocorrendo CompMensagem.Priority:=mpHighest;
{ Low = baixo / High = alto / mpHighest = urgente }
durante o processo de envio do e-mail. CompMensagem.ContentType := text/html;
muito importante que todo o cdigo CompMensagem.From.Text := emailDe.Text;
CompMensagem.Recipients.EMailAddresses := emailPara.Lines.Text;
seja mantido em um bloco try..finally CompMensagem.Subject := emailAssunto.Text;
CompMensagem.Body.Text := emailMensagem.Text;
sendo que entre o finally..end dever { Anexa os arquivos ao e-mail }
for i := 0 to emailAnexo.Items.Count - 1 do
estar a linha para desconectar ao servi- TIdAttachment.Create(CompMensagem.
dor SMTP. Tanto num caso de sucesso MessageParts, TFileName(emailAnexo.
Items[i].Caption));
do envio do e-mail ou num caso em { Faz o envio do e-mail }
CompSMTP.Send(CompMensagem);
que ocorra uma falha, o componente MessageDlg(E-mail enviado com sucesso!,mtInformation, [mbOK], 0);
end;
desconectado no deixando nenhuma end
porta de ligao aberta. else
ShowMessage(Informe a mensagem do e-mail);
O cancelamento do envio do e-mail na end
else
verdade trata-se de uma sada do for- ShowMessage(Informe o assunto do e-mail!);
end
mulrio. Para tanto adicione ao evento else
OnClick do btnCancelar uma chamada ShowMessage(Informe o destinatrio do e-mail!);
end
ao mtodo Close. else
ShowMessage(Informe o e-mail do remetente!);
Configurados todos os eventos da Finally
{ desconecta do servidor SMTP }
aplicao, execute a mesma e faa o teste CompSMTP.Disconnect;
de envio. Certifique-se antes de que est end;
end;
usando um IP vlido para autentica-

Edio 94 - ClubeDelphi 53
Seo DELPHI Seo EASY DELPHI Seo PHP

Nesta seo voc encontra artigos para iniciantes


na linguagem Delphi

Editor de Textos com RichEdit


Veja como criar seu prprio editor de textos com o componente RichEdit

M
uitas vezes utilizamos em nos- formatao como negrito, sublinhado
sas aplicaes o componente entre outros. Tambm alinhamentos e
RichEdit, que possibilita aos espaamentos de pargrafos. Faremos
programadores aplic-los em inmeras uso tambm, em algumas situaes, de
situaes durante o desenvolvimento de alguns componentes da paleta Dialogs do
suas aplicaes. Entre as diversas utili- Delphi com a funo de definir o Layout
dades esto formulrios de cadastros de impresso, salvar e abrir documentos
como notcias, formulrios de envio de salvos pelo editor de textos ou at mesmo
e-mail ou a criao de seu prprio editor por outros editores.
de textos. Com o componente RichEdit
voc pode criar e aperfeioar muitas das Criando a aplicao
utilidades que o Notepad (Bloco de No- A criao do editor de textos trata-se de
tas) do Windows possui. Pode inovar uma simples aplicao na qual utilizaremos
na criao de um Layout e na aplicao o Delphi 7 para a criao do aplicativo
de ferramentas e configuraes na digi- Win32. No ser necessria a utilizao de
tao de textos, salv-los e reabri-los sem nenhuma espcie de banco de dados ou ins-
perder nenhuma formatao. talao de componentes de terceiros. Sero
Maikel Marcelo Scheid Veja neste artigo a criao de um apenas utilizados componentes nativos das
(maikelscheid@gmail.com) simples editor usando o componente paletas do Delphi. Crie a aplicao no menu
tcnico em Informtica com nfase em An- RichEdit e aprenda maneiras de como File|New>Application e altere a propriedade
lise e Programao de Sistemas. Atua na rea utilizar suas propriedades codificando Caption do formulrio principal para Meu
de Desenvolvimento de Softwares em Delphi
situaes de formatao de textos, tais editor de Textos e em seguida nomeie o
para plataforma Win32 e .NET com banco de
dados Firebird e MS SQL. membro da Equipe como alterao da fonte, tamanho e formulrio para frmEditor. Salve a Unit
Editorial ClubeDelphi. cor da letra, utilizao de estilos de do formulrio como uPrincipal.pas e o

54 ClubeDelphi - Editor de Textos com RichEdit


EASY DELPH I

projeto como TextEditor.dpr. Adicione tamanho da fonte que est utilizando, componente BarraButtons relacione a
ao formulrio principal um componente e para isso adicione barra um novo propriedade Images do mesmo ao AtalhoI-
MainMenu(MainMenu1) da paleta Stan- componente ComboBox(ckTamanho), mages, observando que alguns atalhos j
dard e com duplo clique do mouse crie uma e na sua propriedade Items adicione assumiram de forma automtica alguns
estrutura de menus conforme ilustrado na as variaes de tamanhos que deseja cones de identificao.
Figura 1. Esta estrutura de menus tambm disponibilizar. No editor de itens do Para editar os cones de cada boto e
ser utilizada mais adiante para a criao componente adicione, separados por adequ-los ao cone de sua respectiva
dos atalhos de acesso rpido. linha, os seguintes valores: funcionalidade, clique sobre a propriedade
Definida agora toda a estrutura de me- ImageIndex e na lista de imagens disponveis
6, 8, 10, 11, 12, 14, 16, 18, 20, 22, 24,
nus e opes do nosso editor de textos, 28, 30, 32, 40. selecione qual corresponde sua funo.
vamos adicionar da paleta Win32 um Ao final da edio das imagens, a barra de
componente ToolBar(BarraButtons) A alterao das cores de um texto que se atalhos do sistema dever ficar estruturada
para que possamos criar alguns atalhos est digitando tambm uma caracters- de forma semelhante a Figura 3.
de acesso rpido a algum menus do siste- tica muito importante durante a criao A configurao dos cones de menu
ma. Com o clique do boto direito sobre de um editor. Inclua na barra de atalhos tambm dever ser realizada no compo-
a ToolBar selecione a opo New Button, um componente ColorBox(ckCor) da nente MainMenu1, onde tambm dever
criando assim um novo boto (btNovo) paleta Additional e em seguida insira relacionar sua propriedade Images ao
na barra de atalhos. Crie logo aps mais mais um separador barra. AtalhoImages e com um duplo clique
trs botes utilizando o mesmo mtodo. Para permitir a formatao e aplicao ao abrir o editor de menus, selecione
Nomeie os botes como btAbrir, bt- de estilos de formatao para textos com cada um deles alterando o cone rela-
Salvar e btImprimir, respectivamente. negrito, itlico, sublinhado e riscado, cionado a sua propriedade ImageIndex.
Dessa forma acabamos de criar os botes adicione barra de atalhos quatro botes, Alterados e configurados todos os cones
de atalho para os principais itens do btNegrito, btItalico, btSublinhado de identificao de menus e atalhos do
menu Arquivo e vamos criar agora para e btRiscado. Insira um novo separador. editor, vamos agora adicionar o principal
os itens do menu Editar. Por ltimo, inclua na barra de atalhos mais componente da nossa aplicao ao for-
Antes de criar um novo boto na barra trs botes btEsquerda, btCentro e mulrio. Na paleta Win32 adicione um
de atalhos, vamos adicionar um sepa- btDireita que sero utilizados com a fi- componente RichEdit(TextEditor), de-
rador a fim de organizar melhor e cate- nalidade de alinhar o texto para esquerda, fina sua propriedade Align para alClient
gorizar por grupos de funes na barra centralizar e organizar direita.
de atalhos. Clicando sob a barra com o Nossa aplicao est aparecendo ago-
boto direito do mouse e selecionando ra de uma forma um tanto estranha,
a opo New Separator. temos apenas o menu e uma barra de
Criado um separador logo aps o pri- atalhos com vrios botes, sendo que
meiro grupo de botes, criaremos agora nenhum deles ainda dispe de qualquer
os botes para relacionar atalhos aos itens tipo de identificao visual para sua
do menu Editar. Crie trs botes destinados funcionalidade. Para definir um estilo
a este grupo com os nomes btCopiar, de layout e caracterizar cada boto de
btRecortar e btColar. Logo aps adi- atalho, arraste para o formulrio um
cione um novo separador ao menu. componente ImageList(AtalhoImages)
Sendo nossa idia a de criar um editor da paleta Win32. Com um clique duplo
de textos, interessante que para uma sobre o mesmo abra seu editor e adicione
fcil edio do mesmo o usurio tenha uma srie de imagens de acordo com as
sempre de fcil acesso os tipos de fontes funcionalidades que queremos atribuir ao
para que a qualquer momento possa nosso editor de textos. As imagens a serem
alter-la em trechos do seu texto. Para adicionadas devero estar com formatos
oferecer esta opo ao usurio, adicio- de arquivo como *.bmp ou *.ico e podero
naremos tambm barra de atalhos um ser facilmente localizadas no diretrio de
componente ComboBox(ckFontes) da imagens instaladas pelo prprio Delphi,
paleta Standard que ser povoado logo encontradas no caminho padro em C:\
mais com toda a lista de fontes instaladas Arquivos de programas\Arquivos comuns\
no Windows. Adicionado o componente, Borland Shared\Images\Buttons. Cada ima-
crie um novo separador na barra de ata- gem adicionada para o componente Image-
lhos. Alm da alterao do tipo de fonte mList recebe um nmero de identificao
em um texto, o usurio precisa tambm que usaremos para definir os atalhos nos
ter sempre de fcil acesso a alterao do botes (Figura 2). Selecionando agora o Figura 1. Estrutura de menus do sistema

Edio 94 - ClubeDelphi 55
e remova o texto padro exibido na sua Ao final da adio e configurao de dure que ser referenciada como forma
propriedade Lines. todos os componentes ao formulrio, de ponteiro e referncia a um espao de
Posicionado agora sob a paleta Dialogs, sua aplicao dever estar semelhante memria a ser locado no sistema. Ainda
adicione ao formulrio os componentes aplicao da Figura 5, na qual passare- dentro da procedure criamos uma vari-
PrintDialog(dlgPrint) que ser utiliza- mos a partir deste momento a codificar vel do tipo LongWord que usada para
do para configurao e envio do texto as funes do nosso editor. carregar os nomes das fontes e logo mais
impressora, SaveDialog(dlgSave) so atribudas ao componente ckFontes.
utilizado para salvar e armazenar o Codificando a aplicao No evento OnCreate do formulrio, adi-
texto do editor como um documento em A codificao de todo o processo do cione as seguintes linhas de cdigo, que
qualquer unidade de armazenamento editor de textos no ser muito compli- iro chamar a procedure do carregamento
do computador e tambm adicione um cada, vemos que se trata de pequenos das fontes recm criada e definir nos
OpenDialog(dlgOpen) utilizado para blocos de comandos que sero facilmente componentes ckFontes e ckTamanho o tipo
localizar documentos armazenados no entendidos e podero ser aplicadas a e tamanho das configuraes padro que
computador e reabri-los a fim de ler ou vrias outras situaes que voc poder esto definidas no sistema, trazendo-as
continuar com a edio do texto. se deparar enquanto desenvolver sua selecionadas:
O formato de arquivo que utilizaremos aplicao. A primeira codificao que ObtemFontes;
ser o .rtf, ao qual iremos definir um filtro veremos ser quanto a criao do formu- ckFontes.Text := DefFontData.Name;
ckTamanho.Text :=
para a propriedade Filter dos componen- lrio (evento OnCreate) onde iremos re- IntToStr(-MulDiv(DefFontData.Height, 72,
Screen.PixelsPerInch));
tes dlgSave e dlgOpen. Abrindo o editor alizar algumas configuraes que sero
de filtros dos componentes, defina dois os Default do nosso editor. Acessando o Nas prximas linhas de cdigo, vamos
filtros em linhas diferentes, obedecendo editor de cdigos do formulrio, declare atribuir funcionalidades aos menus do
o Filter Name como Arquivos de Texto na seo private a seguinte procedure que sistema (MainMenu1), e para os casos de
(*.rtf) e Todos os arquivos e na coluna ser responsvel por capturar todas as existir um atalho rpido na barra corres-
Filter obedea *.rft e *.*, respectivamente fontes instaladas no Windows e preen- pondente a um item do menu original
(Figura 4). Essas configuraes iro fazer cher a lista no componente ckFontes. (menu Abrir por exemplo), iremos apenas
com que apenas arquivos com esta exten- relacionar o boto ao item atravs da
procedure ObtemFontes;
so sejam exibidos na hora de salvar ou sua propriedade MenuItem que veremos
localizar documentos nas unidades de Posicionado sobre a declarao da tambm mais a seguir.
armazenamento do computador. Confi- procedure utilize as teclas Ctrl+Shift+C Clique duas vezes no MainMenu1 e com
gure ainda em ambos os componentes a para que o Delphi crie o cabealho do ele aberto navegue ao item Arquivo>Novo.
propriedade DefaultExt, atribuindo-lhes o procedimento, e adicione ao mesmo o Automaticamente o Delphi nos cria o
valor *.rtf que ser a extenso padro que cdigo da Listagem 1, onde criaremos cabealho do evento OnClick desse item
adotamos para nosso sistema. uma function derivada dentro da proce- ao qual digitaremos as seguintes linhas
de comando:

if TextEditor.Modified then
ShowMessage(Deseja salvar arquivo)
else
TextEditor.Lines.Clear;

No cdigo verificamos se houve al-


guma alterao do texto digitado e
perguntamos se o usurio deseja salvar
o contedo ou seno limpamos todos os
valores existentes na linhas.
Repita esse processo e digite o cdigo
da Listagem 2 no evento OnClick do
menu Arquivo>Abrir. Esse evento ir
executar uma caixa de pesquisa do
componente dlgOpen e ao selecionar
um arquivo que o usurio deseja abrir,
verificamos se a extenso do mesmo
Figura 2. Adicionando imagens para ImageList corresponde ao tipo de arquivos com
que estamos trabalhando carregando-
o no editor, caso contrario voc ser
notificado de que o formato do arquivo
Figura 3. Barra de atalhos do Editor de Textos selecionando no corresponde aos ar-

56 ClubeDelphi - Editor de Textos com RichEdit


EASY DELPH I

quivos suportados pelo nosso editor e a CutToClipBoard e PasteToClipBoard que, dado ao seu texto. Antes de adicionar
ao ser ignorada. respectivamente, copiam, recortam e o cdigo, declare nas uses do projeto a
Para salvar o contedo digitado no edi- colam o contedo de ou para a memria Unit Dialogs.
tor, atribua ao evento OnClick do menu (ClipBoard).
Arquivo>Salvar o cdigo da Listagem 3 No menu Recuo do pargrafo adicione //Adicionar uses Dialogs
TextEditor.Paragraph.FirstIndent :=
que ao executar o componente de di- ao evento OnClick as seguintes linhas TextEditor.Paragraph.FirstIndent +
StrToInt(InputBox(Digite o
logo dlgSave ir verificar se o nome do de cdigo, que iro abrir uma caixa de espaamento,Recuo do Texto (em mm),
IntToStr(TextEditor.Paragraph.
arquivo fornecido pelo usurio j existe digitao para que o usurio possa de- FirstIndent)));
na pasta selecionada. Havendo o arquivo finir qual espaamento deseja que seja
ele ser sobrescrito. Em caso contrrio
ser criado um novo arquivo com o nome
fornecido na pasta de destino seleciona- Nota do DevMan
da pelo usurio. Por fim a propriedade
Modified do editor ser repassada como Se voc estiver trabalhando no Windows VISTA, ser
False, fornecendo assim que no existe necessrio executar o Visual Web Developer como
administrador, para que a aplicao tenha direitos
contedo modificado sem ser salvo caso suficientes para gravar no log de Eventos.
deseje criar um novo documento.
Para executar o Visual Web Developer como administrador,
A codificao do menu Salvar Como clique com o boto direito sobre o seu cone no menu, e
tambm se d de forma bastante simples, escolha a opo Executar como administrador ou Run as
pois nenhuma verificao precisa ser re- administrator.
Figura 4. Configurao dos filtros
alizada, necessitando apenas executar o
dilogo do dlgSave e salvar o contedo na
pasta selecionada com o nome fornecido.
O cdigo a seguir dever ser adicionado
ao seu evento OnClick:
if dlgSave.Execute then
begin
TextEditor.Lines.SaveToFile(
dlgSave.FileName);
TextEditor.Modified := false;
end;

Pelo fato de termos adicionado ao for-


mulrio um componente para dilogo
da impressora, a impresso tambm
de forma muito simples. Basta adicionar
ao evento OnClick do menu Imprimir o
cdigo a seguir, que ser responsvel por
chamar o dilogo e enviar a impressora:

if (dlgPrint.Execute) then
TextEditor.Print(Text);

No evento OnClick do menu Sair adi-


Figura 5. Estrutura do Editor de Textos
cione o cdigo da Listagem 4. Aqui
verificamos se houve alteraes no
componente RichText. Em caso positivo Listagem 1. Implementao da procedure ObtemFontes
perguntamos ao usurio se ele deseja procedure TfrmEditor.ObtemFontes;
salvar o arquivo, caso contrrio apenas function EnumFontsProc(var LogFont: TLogFont; var
TextMetric: TTextMetric; FontType: Integer;
fechamos o aplicativo. Data: Pointer): Integer; stdcall;
begin
Para codificao dos trs dos itens do TStrings(Data).Add(LogFont.lfFaceName);
Result := 1;
menu Editar observe na Listagem 5 os end;
cdigos referentes a cada item de menu var
DC: HDC;
digitando os respectivos cdigos para as begin
DC := GetDC(0);
aes de Copiar, Recortar e Colar. EnumFonts(DC, nil, @EnumFontsProc,
Pointer(ckFontes.Items));
O componente RichText possui trs m- ReleaseDC(0, DC);
todos distintos para se tratar mensagens ckFontes.Sorted := True;
end;
em memria que so CopyToClipBoard,

Edio 94 - ClubeDelphi 57
No cdigo anterior atribumos o valor Novo, Abrir e Salvar. as quais ainda no foram mencionadas
digitado pelo usurio propriedade Selecionando o boto correspondente, em nenhuma codificao e que so
FirstIdent do Paragraph. O Paragraph uma v at a propriedade MenuItem e localize indispensveis a um editor de textos.
propriedade do controle RichText res- o nome do item de menu corresponden- Alterao do tipo, tamanho e cor de fon-
ponsvel por alterar as configuraes de te. Repita o mesmo procedimento em tes. Podemos selecionar trechos do texto
pargrafo, como o prprio nome sugere. todos os botes. e facilmente editar qualquer uma das
Finalizada a atribuio dos cdigos aos propriedades apenas mudando o item
itens de menu do componente MainMe- Alterando tipo, tamanho selecionando no ComboBox relacionado
nu1, precisamos relacionar os atalhos e cor da fonte a opo. Os cdigos so simples e aplica-
rpidos queles itens que j foram co- Temos adicionado a nossa barra de dos ao evento OnChange de cada um dos
dificados, como o caso dos atalhos de atalhos rpidos trs funcionalidades, componentes, conforme poder observar
nos cdigos e comentrios relacionados
na Listagem 6 a seguir. Os cdigos esto
Listagem 2. OnClick para o menu Abrir
comentados e no h segredo.
procedure TfrmEditor.Abrir1Click(Sender: TObject); Tambm atalhos que ainda no fo-
begin
if dlgOpen.Execute then ram codificados, temos os botes para
begin
if ExtractFileExt(dlgOpen.FileName) = .rtf then aplicao do estilos de Negrito, Itlico,
begin
TextEditor.Lines.LoadFromFile(dlgOpen.FileName);
Sublinhado e Riscado sobre os trechos
dlgSave.FileName := dlgOpen.FileName; de textos selecionado. Na codificao
TextEditor.Modified := false;
end de todos estes botes, verificamos se o
else
MessageDlg(Formato de arquivo no suportado,mtInformation,[mbOk],0) estilo j se encontra aplicado aos trechos
end;
end;
selecionados, e no caso de j existir,
o mesmo ser removido deixando o
Listagem 3. OnClick do menu Arquivo|Salvar texto sem o estilo clicado. Adicione a
procedure TfrmEditor.Salvar1Click(Sender: TObject); cada um dos botes a linha de cdigo
begin
if FileExists(dlgSave.FileName) then
correspondente que est prevista na
TextEditor.Lines.SaveToFile(dlgSave.FileName) Listagem 7. Em resumo, o que estamos
else
begin fazendo adicionar ou remover o estilo
if dlgSave.Execute then
begin empregado propriedade SelAttributes
TextEditor.Lines.SaveToFile(dlgSave.FileName);
end;
do componente RichText.
end; Temos ainda a codificao dos trs
TextEditor.Modified := false;
end; ltimos botes de acesso rpido do
nosso sistema, correspondentes ao ali-
Listagem 4. Evento ativado ao sair do editor de textos
nhamento do texto ao lado esquerdo,
procedure TfrmEditor.Sair1Click(Sender: Tobject); centralizado e direita do editor. Para
begin
if TextEditor.Modified then alinhar o texto selecionado, modifica-
begin
if Application.MessageBox(Deseja salvar as mos a propriedade Alignment atribuin-
alteraes?, Salvar,MB_YESNO) = IdYes then do os valores taLeftJustify(esquerda),
begin
if dlgSave.Execute then taCemter(centro) ou taRigthJustify
TextEditor.Lines.SaveToFile(dlgSave.FileName);
Close; (direita) ao evento OnClick dos botes
end
else btnEsquerda, btnCentro e btnDireita,
Close; respectivamente. Veja o cdigo do bo-
end
else to btnEsquerda. Repita o cdigo para
Close;
end; os demais botes trocando apenas a
atribuio final:
Listagem 5. Copiar, Recortar e Colar
TextEditor.Paragraph.Alignment :=
procedure TfrmEditor.Copiar1Click(Sender: TObject); taLeftJustify;
begin
TextEditor.CopyToClipboard;
end;
Aps todo esse processo de codificao
procedure TfrmEditor.Recortar1Click(Sender: TObject); dos menus e botes de acesso rpido do
begin
TextEditor.CutToClipboard; sistema, acabamos com a criao do nos-
end;
so prprio editor de textos, que poder
procedure TfrmEditor.Colar1Click(Sender: TObject);
begin
ser testado e utilizado para aplicao de
TextEditor.PasteFromClipboard; diversos estilos.
end;
Execute-o e faa a digitao de valores,

58 ClubeDelphi - Editor de Textos com RichEdit


EASY DELPH I

utilizando todas as propriedades aqui con-


Listagem 6. Alterao do tipo, tamanho e cor da fonte do texto
figuradas. Veja que inmeras aes com o
procedure TfrmEditor.ckFontesChange(Sender: TObject); texto podem ser selecionadas (Figura 6).
begin
{ Altera o tipo da fonte no texto selecionado. }
TextEditor.SelAttributes.Name :=
ckFontes.Items[ckFontes.ItemIndex]; Concluso
end;
procedure TfrmEditor.ckTamanhoChange(Sender: TObject);
Vimos com essa criao do editor de
begin textos que podemos criar nossas pr-
{ Altera o tamanho da fonte no texto selecionado. }
TextEditor.selattributes.Size := prias ferramentas de trabalho. Imagine
StrToInt(ckTamanho.Items[ckTamanho.ItemIndex]);
end; neste caso a substituio do bloco de
procedure TfrmEditor.ckCorChange(Sender: TObject);
notas pelo seu prprio editor de textos
begin e quem sabe com mais funcionalidades.
{ Altera a cor da fonte no texto selecionado. }
TextEditor.selattributes.Color := ckCor.Selected; Crie agora formulrios personalizados
end;
e programe novas utilidades ao editor,
Listagem 7. Aplicao de estilos ao texto. adicione mtodos para marcadores e nu-
meradores de pargrafos, espaamento
procedure TfrmEditor.btNegritoClick(Sender: TObject);
begin do texto entre linhas e letras, pesquisas
if (fsBold in TextEditor.selattributes.Style) then
TextEditor.selattributes.Style := TextEditor.SelAttributes.Style - [fsBold] else por palavras, substituio de textos,
TextEditor.selattributes.Style := TextEditor.SelAttributes.Style + [fsBold]; entre outras inmeras funcionalidades
end;
procedure TfrmEditor.btItalicoClick(Sender: TObject); que podero ser configuradas.
begin
if (fsItalic in TextEditor.selattributes.Style) then Abrao e at a prxima.
TextEditor.selattributes.Style := TextEditor.SelAttributes.Style - [fsItalic]
else
TextEditor.selattributes.Style := TextEditor.SelAttributes.Style + [fsItalic];
end;
procedure TfrmEditor.btSublinhadoClick(Sender: TObject); D seu feedback sobre esta edio! Feedback
begin eu

s
D
if (fsUnderline in TextEditor.selattributes.Style)
then A Java Magazine tem que ser feita ao seu

sobre e
TextEditor.selattributes.Style := TextEditor.SelAttributes.Style - [fsUnderline]
else gosto. Para isso, precisamos saber o que

s
ta
TextEditor.selattributes.Style := TextEditor.SelAttributes.Style + [fsUnderline]
edio
end;
voc, leitor, acha da revista!
procedure TfrmEditor.btRiscadoClick(Sender: TObject);
begin D seu voto sobre este artigo, atravs do link:
if (fsStrikeOut in TextEditor.selattributes.Style)
then www.devmedia.com.br/javamagazine/feedback
TextEditor.selattributes.Style := TextEditor.SelAttributes.Style - [fsStrikeOut]
else
TextEditor.selattributes.Style := TextEditor.SelAttributes.Style + [fsStrikeOut]
end;

Figura 6. Utilizando funcionalidades do Editor de textos

Edio 94 - ClubeDelphi 59
Seo DELPHI Seo EASY DELPHI Seo PHP

Nesta seo voc encontra artigos sobre


a linguagem PHP e a ferramenta Delphi for PHP

Orientao a Objetos no Delphi for PHP


Como aplicar conceitos de POO em aplicaes PHP Parte 2

C
omo prometido em meu primei- de conseguir estender projetos por meios
ro artigo vamos dar continui- da reutilizao de cdigo. Mas se de um
dade a este assunto to extenso lado o polimorfismo um dos assuntos
que a orientao a Objetos. Como dito mais importantes da POO tambm sem
anteriormente toda linguagem dita OO dvida nenhuma um dos mais difceis
deve estar apoiada nos pilares desta de ser compreendido. Isto porque muitos
filosofia que so: Herana, Encapsula- que se aventuram pela primeira vez na
mento, Abstrao e Polimorfismo e o PHP 5 OO entram ainda com uma mentalidade
implementa essas quatro caractersticas procedural e enxergando as classes como
inclusive o polimorfismo que o foco do entidades do banco de dados tornando
nosso artigo. mais difcil a compreenso da POO como
Muitos programadores vem a herana um todo.
como a soluo de seus problemas, po-
rm se usada indiscriminadamente ele Polimorfismo
pode ser um feitio que se vira contra o Teoricamente e a grosso modo entende-
feiticeiro, isto porque se no tomarmos os se por polimorfismo a capacidade que
Rodrigo Carreiro Mouro devidos cuidado acabamos por acoplar um mesmo mtodo tem de se comportar de
(rodrigocarreiro@tdstecnologia.com.br) todo o nosso cdigo atravs da herana. maneira diferente dependendo de qual classe
Consultor da TDS Tecnologia RJ atuando na Porm se h algo que justifique o uso da ele foi chamado. Ns conseguimos isso
rea de desenvolvimento de projetos Orienta- herana este se chama polimorfismo. declarando um mtodo em uma classe
dos a Objetos, Design Patterns, MVC. BDS2006 O polimorfismo um dos assuntos mais base e o sobrescrevemos em uma classe
Win32 Product Certified. Borland Instructor
Certified. Instrutor de treinamento oficiais
importantes na POO. Com o uso de clas- herdada, facilitando assim o desenvolvi-
CodeGear DelphiWin32, Delphi for PHP, Delphi ses e heranas conseguimos facilmente mento e reaproveitamento cdigos.
.Net. Palestrante da Borland Conference 2007. descrever uma situao da vida real alm Antes de mais nada importante dei-

60 ClubeDelphi - Orientao a Objetos no Delphi for PHP

09 - Rodrigo - DelphiforPHP.indd 60 25.03.08 16:48:23


D ELPHI F O R PH P

xar claro que a linguagem que estamos


Listagem 1. Polimorfismo no Delphi Win32
trabalhando o PHP e que o mesmo
unit SeresVivos;
interpretado, fracamente tipado e sendo
assim no h a necessidade de se decla- interface

rar variveis com seus tipos. Mas o que type


TServivo = class
isso tem a ver com polimorfismo? Tudo! procedure ProduzirSom;
end;
Observe o cdigo da Listagem 1.
No cdigo da Listagem 1 ser levan- TCachorro = class(TServivo)
procedure ProduzirSom;
tada uma exceo no evento OnClick do end;

boto com a mensagem Nem todo ser THomem = class(TServivo)


procedure ProduzirSom;
vivo produz som!!! mesmo um objeto end;
do tipo THomem sendo instanciado para
implementation
a varivel Ser. Isso acontece porque no
uses
Delphi os mtodos so estticos por pa- SysUtils, Dialogs;
dro. Isso significa que independente do { TCachorro }
objeto que seja instanciado na varivel
procedure TCachorro.ProduzirSom;
vale para ela o tipo que foi declarado. begin
ShowMessage(Cachorro Latindo !!!);
Para conseguirmos o efeito desejado, end;
ou seja, o mtodo ProduzirSom da classe { TServivo }
THomem seja chamado, preciso de-
procedure TServivo.ProduzirSom;
clarar o mtodo ProduzirSom na classe begin
raise Exception.Create(Nem todo ser vivo produz
TSerVivo como Virtual. som !);
Isso faz com que o Delphi crie uma end;

VMT(Virtual Method Table) uma ta- { THomem }

bela com os ponteiros dos mtodos que procedure THomem.ProduzirSom;


begin
foram declarados como virtuais para ShowMessage(Homem Falando !!!);
que possam ser sobrescritos em tempo end;

de execuo. Na Listagem 2 vemos como end.

ficaria o cdigo. procedure TForm1.Button1Click(Sender: TObject);


var
No PHP nada disso necessrio, como Ser: TSerVivo;
ele e fracamente tipado, ou seja, no begin
Ser := THomem.Create;
Ser.ProduzirSom;
end;

Listagem 2. Mtodos Virtuais


Nota do DevMan unit SeresVivos;

interface
O termo Programao Procedural (ou programao
procedimental) s vezes utilizado como sinnimo de type
TServivo = class
Programao Imperativa (paradigma de programao que procedure ProduzirSom;virtual;
especifica os passos que um programa deve seguir para end;
alcanar um estado desejado), mas o termo pode se referir
TCachorro = class(TServivo)
(como neste artigo) a um paradigma de programao procedure ProduzirSom;override;
baseado no conceito de chamadas a procedimentos. end;
Procedimentos, tambm conhecidos como rotinas, sub-
THomem = class(TServivo)
rotinas, mtodos, ou funes simplesmente contm um procedure ProduzirSom;override;
conjunto de passos computacionais a serem executados. end;
Um dado procedimento pode ser chamado a qualquer
implementation
hora durante a execuo de um programa, inclusive por
outros procedimentos ou por si mesmo. end.

Edio 94 - ClubeDelphi 61
precisamos declarar o tipo de nossas Note que agora criamos uma classe programadores envolvidos no processo
variveis, no h porque os mtodos SerVivo que servir de base para todas definimos esses mtodos como abstratos
serem estticos, e nem podem. Como as outras classes de animais que iremos demonstrando assim a nossa inteno de
no h um tipo definido para o objeto criar e que iro produzir algum som. que ele seja sobrescrito na classe que o
que ser instanciado, por padro ser nesta classe que est declarado o mtodo herdou. Com isso temos um cdigo mais
chamado o mtodo do objeto que foi ins- que ser sobrescrito nas classes descen- organizado, mais coeso. A prpria classe
tanciado para aquela varivel. Por isso dentes porm no h aqui a necessidade nos lembra que precisamos implementar
podemos dizer que no PHP os mtodos de nenhum parmetro ou diretiva para esse mtodo em algum momento. No BDS
so Virtuais e isto facilita a implemen- tornar este mtodo virtual e passvel 2006, quando temos um mtodo abstrato
tao do polimorfismo reduzindo assim de ser sobrescrito. Observe que desta em uma classe e herdamos da mesma, ao
o uso de controles de fluxos como Ifs maneira o nosso cdigo no fica en- utilizarmos o CodeCompletion este mtodo
para tornar nosso cdigo mais robusto gessado. Se por exemplo decidirmos aparece em vermelho indicando que pre-
e expansvel. criar uma classe Gato em nada teremos cisa ser implementado.
Voc deve estar se perguntando: Se que alterar o mtodo GetSom. Basta que Um fato importante a ser lembrado que,
no precisamos declarar o tipo de nossas a classe Gato herde de SerVivo para que no PHP se uma classe possui ao menos um
variveis e de nossos objetos, como saber seja aceita no mtodo GetSom e feito isso mtodo abstrato ela deve ser declarada
se um objeto pertence a uma determinada sobrescrevemos o mtodo ProduzirSom como abstrata diferente de outras lingua-
hierarquia ou possui o mtodo que queremos na classe herdada. gens de programao. Essa dupla definio
chamar?. Perceba que foi utilizado em nosso cdi- existe para permitir a voc declarar uma
Para isto temos no PHP 5 o operador go o operador instanceof para verificar se classe como abstrata mesmo que a mesma
instanceof. Ele verifica se um objeto o objeto passado como parmetro para o no possua mtodos abstratos.
qualquer possui um relacionamento mtodo GetSom pertence classe SerVivo No exemplo dos nossos seres vivos fica
um com uma classe especfica. Ele na ou herda da mesma. Se esta condio for claro que nem todos os seres produzem
verdade uma modificao da j existen- satisfeita podemos ter a certeza que ele som, assim este mtodo nesta classe no
te funo is_a() que foi descontinuada, ter em sua estrutura o mtodo Produzir- deve ter implementao ficando nossa
pois o primeiro um operador binrio Som. Agora qual mensagem ser exibida classe como a da Listagem 5.
lgico permitindo criar sentenas como por este mtodo vai depender do tipo Note na Listagem 5 que a classe SerVivo
a seguir: do objeto que estiver instanciado ali no agora foi declarada como abstract, pois dos
momento. Com isso voltamos definio trs mtodos que a mesma possui um de-
if($c instanceof Cliente) { do incio do nosso artigo: Polimorfismo: a les abstrato e por isso temos que declarar
echo $c um cliente;
} capacidade que um mesmo mtodo tem de se a classe como abstrata tambm. Assim Ser-
comportar de maneira diferente dependendo Vivo no poder ser instanciada e tambm
Para exemplificar essa facilidade ob- de qual classe ele foi chamado. no haver necessidade, pois esta classe
serve o cdigo da Listagem 3. Claro que muito mais pode ser feito apenas uma base para as demais.
Podemos notar facilmente que o cdigo para tornar nosso cdigo mais coeso, Como todo ser vivo nasce, cresce, se re-
escrito no est expansvel. Imagine que por exemplo, se nem todos os seres vivos produz e morre, podemos observar que
voc decida criar em seu modelo mais produzem som no h porque o mtodo temos algumas dessas fases em forma de
cinco animais cada um produzindo ProduzirSom na classe SerVivo tenha mtodos em SerVivo, no como abstratos,
seu respectivo som, isso se tornaria implementao. Neste caso aplica-se um mas passveis de serem sobrescritos.
para voc um tormento, pois teria que mtodo abstrato.
adicionar outros cinco blocos elseif para Mtodos e Propriedades Estticas
fazer a verificao. Isso fere o conceito Mtodos e Classes Abstratas de conhecimento geral que uma
de reaproveitamento de cdigo e pior No PHP5 temos tambm o conceito de classe pode declarar n propriedades e
do que isso imagine o sofrimento que classes e mtodos abstratos. Diz abstrato mtodos. Cada instncia desta classe, ou
seria para dar manuteno em um c- um mtodo que no possui implemen- seja, cada objeto possui uma cpia destas
digo deste porte. Ento esse cdigo est tao ou uma classe que no deve ser propriedades e mtodos. Isso significa
totalmente fora de cogitao. instanciada, que serve apenas de refe- que podem receber valores distintos e
O uso da herana com o polimorfismo rncia para ser herdada e o mtodo para seus mtodos serem chamados de forma
nos ajuda a resolver este problema, a ser sobrescrito. independente. Porm em OO temos um
inteno fazer a mesma coisa, porm de Isto muito comum em OO, pois quando conceito chamado de propriedades est-
uma maneira que nos ajude a expandir trabalhamos com grandes equipes e em ticas e mtodos estticos. So elementos
nosso cdigo, reaproveit-lo e mais do grandes projetos geralmente queremos que pertencem classe e no ao objeto,
que isso que facilite a manuteno do garantir que determinadas classes tenham com isto eles podem ser acessados e
mesmo. Isso aplicado na prtica se torna certos mtodos essenciais ao funciona- invocados a partir da classe sem a neces-
o cdigo descrito na Listagem 4. mento do modelo e como so vrios os sidade de se instanciar o objeto.

62 ClubeDelphi - Orientao a Objetos no Delphi for PHP


D ELPHI F O R PH P

Podemos ter vrios objetos, mas todos Mas voc deve estar se perguntando se um mtodo para obter o valor atual do
eles oriundos de uma nica classe. Como realmente far uso deste tipo de recurso contador da classe. Este mtodo dever
as propriedades e mtodos pertencem e se ele realmente necessrio. Pois en- ser esttico para evitar que se tenha
classe podemos deduzir que essas pro- to observe o cdigo da Listagem 6. que instanciar a classe para invocar
priedades e mtodos so compartilhados O que temos aqui uma classe cliente o mtodo. Veja como ficaria com essa
por todos os objetos. comum e simples, porm com um contador modificao na Listagem 7.
H algumas consideraes sobre o uso que registra a quantidade de objetos desta Observe que adicionamos a nossa
de mtodos e propriedades estticas no classe que foram instanciados. Por isso a classe Cliente um mtodo esttico que
PHP. Por exemplo, para se acessar pro- propriedade esttica $Contador, proprieda- retorna a posio atual do contador. Para
priedades estticas de dentro da prpria de esta que pertence classe e no ao objeto, invoc-lo utilizamos a prpria classe
classe temos que utilizar o operador compartilhada por todas as instncias. sem a necessidade de se instanciar um
Self:: que aqui tem uma funo oposta Observe que no construtor acessamos esta objeto: Cliente::GetCount().
a do Delphi onde o Self usado para propriedade atravs do operador Self e o in-
fazer referncia ao objeto do contexto crementamos em um. Feito isso atribumos Criando um exemplo
enquanto no PHP usamos para acessar a o valor do contador propriedade $id, essa notrio que os exemplos citados aci-
classe. Outro detalhe que para acessar sim pertencente ao objeto. ma servem apenas para exemplificar os
uma propriedade ou mtodo deste tipo O mtodo CriarClientes executa um conceitos abordados aqui. Para que voc
temos que faz-lo atravs da classe de lao for e instancia dez objetos Clientes e possa ter uma noo de como o polimor-
duas maneiras: logo aps mostra no navegador o valor fismo auxilia em tarefas dirias vamos
da propriedade $id. construir um pequeno exemplo abordan-
Classe::Propriedade
Classe::Mtodo() Poderamos incluir nesta classe Cliente do o conceito acima. Abra o Delphi for

Listagem 3. Codigo PHP sem polimorfismo Listagem 5. Classes abstratas no PHP

<?php <?php
class Cachorro{ abstract class SerVivo{
function Latir(){ function Nascer(){
echo Cachorro Latindo !; echo Nascendo !!!;
} }
} function Crescer(){
class Homem{ echo Crescendo !!!;
function Falar{ }
echo Homem Falando !; abstract function ProduzirSom();
} }
}
function ProduzirSom($Obj){ class Cachorro extends SerVivo{
if ($Obj instaceof Cachorro){ function ProduzirSom(){
$Obj->Latir(); echo Cachorro Latindo !;
}elseif($Obj instanceof Homem){ }
$Obj->Falar(); }
}else{
echo O objeto passado no produz som; class Homem extends SerVivo{
} function ProduzirSom{
} echo Homem Falando !;
}
?> }
function GetSom($Obj){
if ($Obj instaceof SerVivo){
Listagem 4. Polimorfismo aplicado no PHP $Obj->ProduzirSom();
}else{
<?php echo O objeto passado no um ser vivo !;
class SerVivo{ }
function ProduzirSom(){ }
echo Nem todo ser vivo produz som !; ?>
}
}
class Cachorro extends SerVivo{ Listagem 6. Propriedade Esttica no PHP
function ProduzirSom(){
echo Cachorro Latindo !; <?php
} class Cliente{
} static $Contador = 0;
class Homem extends SerVivo{ public $id;
function ProduzirSom{ function __construct(){
echo Homem Falando !; self::$Contador++;
} $this->id = self::$Contador;
} }
function GetSom($Obj){ }
if ($Obj instaceof SerVivo){ function CriarClientes(){
$Obj->ProduzirSom(); for($i=0;$i<=9;$i++){
}else{ $cliente = new Cliente();
echo O objeto passado no um ser vivo !; echo $cliente->id.<br>;
} }
} }
?> ?>

Edio 94 - ClubeDelphi 63
PHP e crie uma nova aplicao. Para isso de acordo com cada campo. Adicone classe um campo protegido $_nome com
acesse o menu File|New>Application. tambm dois Buttons(BtnSalvar e os mtodos Get e Set para acesso a este
Sa lve a apl ic a o pre s sion a ndo BtnListar) e um RadioGroup. Adicione Field. Isso far que no Code Completion
Ctrl+Shift+S ou escolha File>Save Pro- ao RadioGroup dois itens a sua proprie- voc possa acessar a propriedade Nome
ject As com o nome PrjPolimorfismo. dade Items. Digite Pessoa Fsica e atravs de Pessoa->Nome embora o GetNo-
phprj e em seguida salve a Unit como Pessoa Jurdica. Altere a propriedade me e o SetNome no sejam invocados.
index.php. Altere a propriedade Name Orientation para orHorizontal. Na Figura Retornando ao exemplo, repita o passo
do formulrio para FrmIndex. Este 1 temos uma sugesto de layout. anterior e faa o mesmo para publicar
formulrio ser utilizado para criar a Concludo o layout passaremos agora em Pessoa a propriedade Telefone. Em
interface visual do nosso exemplo. para a criao de nossas classes. No irei PessoaFisica publique a propriedade CPF
Adicione neste formulrio trs Edits me apronfundar na sintaxe OO no PHP e em PessoaJuridica a propriedade CNPJ.
da paleta Standard. Altere seus nomes pois este foi escopo do primeiro artigo. Observe na Listagem 10 as classes com
para EdtNome, EdtEmail, EdtRe- Acesse o menu File|New>Unit e crie as propriedades publicadas.
gistro, respectivamente. Adicione trs uma nova Unit salvando-a com o nome A princpio voc dever notar que no
Labels, tambm da paleta Standard, um Model.php. Nesta Unit iremos criar foge muito a regra de criao de classe
para cada Edit e troque seus Captions um modelo onde teremos uma classe em comparao com o Delphi Win32.
Pessoa com as propriedades Nome e Temos em Pessoa as propriedades perti-
Telefone comum a todo o tipo de pessoa. nentes a todo tipo de pessoa. PessoaFisica
Faremos um especializao de Pessoa em herda de Pessoa, e por esse motivo traz
PessoaFisica e PessoaJurica cada uma com consigo, devido a herana, as proprieda-
uma propriedade exclusiva CPF e CNPJ des Nome e Telefone. Precisamos apenas
respectivamente. Na Unit criada digite adicionar a propriedade CPF assim como
o cdigo da Listagem 8. acontece em PessoaJuridica, sendo que
nesta temos o CNPJ como diferencial.
No cdigo da Listagem 8 apenas cria- Se notou bem, publicamos o mtodo
mos a estrutura das classes que sero usa- Save() em Pessoa como abstract indicando
das em nosso exemplo. Posicione o cursor assim a inteno que temos em sobres-
na rea da classe Pessoa e pressione Ctrl + crev-lo nas classes descendentes e isso
Shift + Alt + U para publicar as proprie- que faremos agora. Na classe PessoaFisica
dades. No dilogo que se abre preencha sobrescreva a funo Save() conforme a
os campos conforme a Figura 2. Listagem 11. Faa o mesmo para Pessoa-
Figura 1. Exemplo de layout Repare que o Delphi for PHP j adiciona Fisica conforme Listagem 12.

Listagem 7. Mtodo Esttico no PHP

<?php
Nota do DevMan
class Cliente{
static $Contador = 0;
public $id; Para que os mtodos Get e Set possam ser invocados
function __construct(){ automaticamente como no Delphi Win32 suas classes
self::$Contador++;
$this->id = self::$Contador; precisam possuir os mtodos __set() e __get ou
} simplesmente herdar suas classes da classe Object do
static function GetCount(){ Delphi for PHP o que no acontece automaticamente
return self::$Contador;
} como no caso so Delphi Win32. A classe object j intercepta
} o acesso a propriedade e delega a chamada aos respectivos
function CriarClientes(){ gets e sets. Oberve na Listagem 9 a estrutura em Object.
for($i=0;$i<=9;$i++){
$cliente = new Cliente(); Declaramos os mtodos __get() e __set() e preparamos
echo $cliente->id.<br>;
} ambos para que localizem a herana e retornem o
echo Cliente::GetCount(); resultado. Caso no seja encontrada, uma exceo
} levantada informando que o mtodo no existe.
?>

Listagem 8. Estrutura das classes

abstract class Pessoa{


protected abstract function Save();
}
class PessoaFisica extends Pessoa{
}
class PessoaJuridica extends Pessoa{

Figura 2. Publicando a Propriedade Nome

64 ClubeDelphi - Orientao a Objetos no Delphi for PHP


D ELPHI F O R PH P

Esses so os mtodos que sero fruto do evento digite o cdigo da Listagem 14. Listagem 9. Mtodos __get e __set em Object.
polimorfismo. Teremos uma outra classe O procedimento simples. Primeiro
<?php
que servir como lista de pessoas, onde verificamos a opo selecionada no Ra- function __get($nm){
$method=get.$nm;
guardaremos todos os objetos criados na dioGroup atravs da propriedade ItemIn- if (method_exists($this,$method)){
return ($this->$method());
aplicao. O boto listar servir para per- dex. Feito isso criamos o objeto de acordo }else{
correr toda a lista e invocar o mtodo Save() com a opo do usurio e j carregamos $method=read.$nm;
if (method_exists($this,$method)){
dos objetos contidos nela. No sabemos ao o valor do edtRegistro para a propriedade return ($this->$method());
}else{
certo se so pessoas fsicas ou jurdicas. CPF ou CNPJ dependendo do caso. if ($this->inheritsFrom(Component)){
if( isset($this->_childnames[$nm]) )
Apenas sabemos que so pessoas e se so Em seguida carregamos para as pro- return $this->_childnames[$nm];
pessoas possuem o mtodo Save().Na mes- priedades Nome e Email os valores de seus }
throw new EPropertyNotFound(
ma Unit do modelo, model.php, crie a classe respectivos Edits. Por fim verificamos se $this->ClassName()...$nm);
}
ListaPessoa conforme Listagem 13. h na seo uma varivel Obj. Se ela no }
Nesta classe temos um Array Private existir criamos um objeto e o colocamos }
function __set($nm, $val){
onde guardaremos todos os objetos na seo para poder pass-lo para outra $method=set.$nm;
if (method_exists($this,$method)){
criados na aplicao. O mtodo pblico pgina. Se a varivel de seo j existir $this->$method($val);
}else{
AddPessoa serve para que possamos ter ento apenas invocamos de dentro da $method=write.$nm;
uma maneira de adicionarmos itens ao seo a funo AddPessoa passando o ob- if (method_exists($this,$method)){
$this->$method($val);
Array que privado. Repare no parme- jeto criado. Ao final teremos na seo um }else{
throw new
tro da funo que colocamos o tipo do objeto ListaPessoa com todas as pessoas EPropertyNotFound($this->
ClassName()...$nm);
parmetro antes do mesmo. O PHP no criadas a cada clique de boto. }
tipado, porm temos este recurso que Para concluir nosso exemplo no OnClick }
}
chamado de Hint de Classe. do boto Listar Todos chamaremos uma ?>

Com isso um erro ser gerado se ten- pgina (lista.php) e nela exibiremos o
Listagem 10. Classes com propriedades publicadas
tarmos adicionar no Array um objeto contedo de nossa lista de pessoas. Para
que no seja do tipo pessoa. A funo isso codifique o boto em questo fazen- <?php
/* Classe principal Pessoa */
publicar em ListaPessoa apenas faz um do uma chamada ao mtodo redirect do abstract class Pessoa{
protected $_nome=;
loop no Array onde cada interao, ou PHP, conforme a seguir: function getNome(){
return $this->_nome;
seja, cada vez que passa por um objeto o }
redirect(lista.php);
mtodo Save() invocado, publicando no function setNome($value){
$this->_nome=$value;
browser as informaes do objeto. Esta pgina ainda no foi criada ento }
function defaultNome(){
Para testar nosso modelo vamos ao proceda com a criao em File|New>Form. return;
}
evento OnClick do boto Salvar. Neste Salve-a como lista.php e modifique protected $_email=;
function getEmail(){
return $this->_email;
}
function setEmail($value){
$this->_email=$value;
}
function defaultEmail(){
return;
}
protected abstract function Save();
}
/* Classe PessoaFisica */
class PessoaFisica extends Pessoa{
protected $_cpf=;
function getCPF(){
return $this->_cpf;
}
function setCPF($value){
$this->_cpf=$value;
}
function defaultCPF(){
return;
}
}
/* Classe PessoaJuridica */
class PessoaJuridica extends Pessoa{
protected $_cnpj=;
function getCNPJ(){
return $this->_cnpj;
}
function setCNPJ($value){
$this->_cnpj=$value;
}
function defaultCNPJ(){
return;
}
}
?>
Figura 3. Cadastrando Pessoas na Lista

Edio 94 - ClubeDelphi 65
seu Name para FrmLista. No OnShow
Listagem 11. Metodo Save() na classe PessoaFisica
dessa pgina digite o cdigo a seguir:
public function Save(){
echo <font size=6 color=darkblue.
face=Tahoma>.$this->Nome.</font><br>. $L = $_SESSION[Obj];
Email...: .$this->Email.<br>. $L->Publicar();
CPF....: .$this->CPF.<br>.
Tipo...: Pessoa Fisica <hr>;
} Este cdigo apenas invoca o mtodo
Listagem 12. Metodo Save() na classe PessoaJuridica Publicar do objeto ListaPessoa que est na
seo. Este mtodo por sua vez faz um
public function Save(){
echo <font size=6 color=darkblue. loop no Array invocando o mtodo Save()
face=Tahoma>.$this->Nome.</font><br>.
Email...: .$this->Email.<br>. de cada item da lista. Com isso quando
CNPJ...: .$this->CNPJ.<br>.
Tipo...: Pessoa Juridica <hr>;
esta pgina for carregada exibir no
} browser todas as pessoas cadastradas na
lista devidamente formatadas.
Listagem 13. Classe Pessoa Lista
Execute a aplicao. Selecione o tipo de
class ListaPessoa{
static private $instance;
pessoa, informe os dados e clique no bo-
private $_list = array(); to Salvar. Veja a aplicao em execuo
function AddPessoa(Pessoa $Obj){ nas Figuras 3 e 4.
$this->_list[] = $Obj;
}

function Publicar(){
Concluso
for ($i = 0; $i < count($this->_list); $i++){ Com os conceitos aprendidos at o mo-
$this->_list[$i]->Save();
} mento j possvel adicionar aos nossos
}
projetos um aspecto mais profissional, e
Listagem 14. Criando os objetos do modelo claro, facilitar bastante o nosso trabalho.
Confesso que para quem no tem um
function BtnSalvarClick($sender, $params){
certo conhecimento em OO pode parecer
switch ($this->RadioGroup1->ItemIndex) {
case 0: a primeira vista um tanto complicado
$Pessoa = new PessoaFisica; aplicar todos esses conceitos, mas com
$Pessoa->CPF = $this->Edit3->Text;
break; o tempo voc ir perceber que as coisas
case 1:
$Pessoa = new PessoaJuridica; no so to complicadas como parecem.
$Pessoa->CNPJ = $this->Edit3->Text;
} O mundo de programao OO fas-
cinante e requer muita dedicao por
$Pessoa->Nome = $this->Edit1->Text;
$Pessoa->Email = $this->Edit2->Text; parte daqueles que se lanam nele. Por
if (!isset($_SESSION[Obj])){ isso dedique-se. Lembre-se que OO OO
$_SESSION[Obj] = new ListaPessoa;
}
independente da linguagem. Habitue-se
a pensar OO, pois todas as grandes lin-
$_SESSION[Obj]->AddPessoa($Pessoa);
} guagens e por conseqncia ferramentas
esto apoiadas nesta filosofia.
Um grande abrao a todos e at o
prximo artigo, onde trataremos de um
assunto um tanto interessante: Design
Patterns em PHP.
Eu sou Rodrigo Carreiro e pela sua
ateno muito obrigado.

D seu feedback sobre esta edio! Feedback


eu
s
D

A Java Magazine tem que ser feita ao seu


sobre e

gosto. Para isso, precisamos saber o que


s

ta
e
voc, leitor, acha da revista!
d i o

D seu voto sobre este artigo, atravs do link:


www.devmedia.com.br/javamagazine/feedback
Figura 4. Publicando contedo da lista

66 ClubeDelphi - Orientao a Objetos no Delphi for PHP


09 - Rodrigo - DelphiforPHP.indd 67 24.03.08 06:16:40
09 - Rodrigo - DelphiforPHP.indd 68 24.03.08 06:16:44

Você também pode gostar