Você está na página 1de 32

EDITORIAL

Editorial
Ol amigos,

THE CLUB
Av. Celso Ferreira da Silva, 190
Jd. Europa - Avar - SP - CEP 18.707-150
Informaes: (0xx14) 3732-3689
Suporte: (0xx14) 3733-1588 - Fax: (0xx14) 3732-0987

Internet
http://www.theclub.com.br
Cadastro: cadastro@theclub.com.br
Suporte: suporte@theclub.com.br
Informaes: info@theclub.com.br

Dvidas
Correspondncia ou fax com dvidas devem ser
enviados ao - THE CLUB, indicando "Suporte".

Opinio
Se voc quer dar a sua opinio sobre o clube em
geral, mande a sua correspondncia para a seo
"Tire sua dvida".

Reproduo
A utilizao, reproduo, apropriao,
armazenamento em banco de dados, sob qualquer
forma ou meio, de textos, fotos e outras criaes
intelectuais em cada publicao da Revista
The Club so terminantemente proibidos sem
autorizao escrita dos titulares dos direitos
autorais.

Aqui estamos com mais uma edio da The Club Megazine trazendo at voc
muita informao para facilitar seu dia-a-dia.
Comeamos com um excelente artigo do nosso amigo Marcelo Nogueira, onde ele
trata sobre a gesto de riscos em projetos de software, no deixe de conferir.
Continuando, nosso consultor Claudinei Rodrigues demonstra em seu artigo
vrias dicas acerca do componente TWebBrowser o qual encapsula o navegador
Microsoft Internet Explorer permitindo ao programador adicionar timos recursos
sua aplicao.
Na seqncia, nosso consultor Andr Colavite apresenta uma soluo para criar
arquivos PDFs via Delphi utilizando um componente gratuito o qual tambm pode ser
utilizado em conjunto com o QuickReport, e dessa forma exportar seus relatrios para
formato PDF.
Ainda falando em QuickReport, nosso consultor Alessandro Ferreira preparou um
artigo especial sobre o QuickReport onde demonstra como criar relatrios no triviais
com este gerador que ainda bastante utilizado meio a comunidade Delphi.
E finalizando esta edio, trazemos nossa sesso Perguntas & Respostas onde
apresentamos algumas das solicitaes feitas aos nossos consultores neste ms.
Abrao e sucesso todos,

Copyright The Club 2005


Impresso e acabamento:
GRAFILAR
Tel.: (0xx14) 3841-2587 - Fax: (0xx14) 3841-3346
Rua Cel. Amando Simes, 779 - Cep 18.650-000
So Manuel - SP
Tiragem: 5.000 exemplares

Celso Jefferson Paganelli


Presidente - The Club

Diretor - Presidente

Celso Jefferson M. Paganelli


Diretor Tcnico

Mauro SantAnna
Colaboradores
Emerson Facunte, Marcelo Nogueira

Delphi marca registrada da Borland International, as


demais marcas citadas so registradas pelos seus
respectivos proprietrios.

Editorial ............................................................................
Gesto de riscos em projetos de software ....................
Usando o componente TWebBrowser ..........................
Criando um arquivo PDF a partir do Delphi ..................
Explorando o QuickReport .............................................
Perguntas & Respostas ..................................................

MeGAZINE

03
04
08
12
16
28

Delphi

Gesto
Gesto de
de riscos
riscos em
em projetos
projetos de
de software
software
Por Marcelo Nogueira

Resumo - As empresas de desenvolvimento de software


possuem caractersticas especiais, diante da demanda a elas
submetidas. Com a realizao de projetos sobre presso de prazos
e custos, processos fundamentais so ignorados como por
exemplo gesto de riscos. A falta de foco nos riscos dos projetos
de software, bem como a determinao de seu grau de exposio,
pode causar transtornos e prejuzos ao projeto. A confiabilidade do
produto de software influenciada pelo seu processo de
desenvolvimento. Um processo repetitivo, orientado no sentido de
monitorar e controlar os riscos, permite que o software
desenvolvido, tenha confiabilidade. A no adoo dessas prticas
fundamentais da Engenharia de Software por falta de cultura ou
por resistncia a mudanas, levam projetos de suma relevncia
ao insucesso e aumentando os casos de fracassos no
desenvolvimento de software.
Palavras-chave: Desenvolvimento de software, Riscos,
Engenharia de Software.

Peter Drucker disse certa vez, j que ftil tentar eliminar


riscos e questionvel tentar minimiz-los, o essencial que os
riscos considerados sejam os certos. Antes que possamos
identificar os riscos certos, que acontecero durante um projeto
de software, importante identificar todos os demais que so
bvios, tanto para gerentes quanto para profissionais.
Segundo Higuera [1], um risco 100% provvel uma
restrio ao projeto de software.

Introduo aos Riscos


Segundo Robert Charette [1], a definio de risco :
Em primeiro lugar, risco afeta acontecimentos futuros.
Presente e passado no preocupam, pois o que colhemos hoje j
foi semeado por nossas aes anteriores. A questo mudando
nossas aes hoje, podemos criar oportunidade para uma
situao diferente e possivelmente melhor para ns amanh?
Isso significa, em segundo lugar, que risco envolve mudana,
como por exemplo, mudana de pensamento, opinio, aes ou
lugares..., e em terceiro lugar, o risco envolve escolha e a
incerteza que a prpria escolha envolve. Assim, paradoxalmente,
o risco, como a morte e os impostos, uma das poucas certezas da
vida.
Quando o risco considerado no contexto da Engenharia de
Software, as trs fundamentaes conceituais de Charette esto
sempre em evidncia:

1. O futuro nossa preocupao: Que riscos podem causar o


insucesso do projeto de software?
2. A mudana nossa preocupao: Como as mudanas de
requisitos do cliente, afetam a pontualidade e o sucesso geral?
3. Devemos cuidar das escolhas: Que mtodos e ferramentas
devemos usar, quantas pessoas devem ser envolvidas, quanta
nfase em qualidade suficiente?

Um grande volume de dados publicados aponta para os riscos


que ocorrem os projetos de software executados se a utilizao de
processos adequados [4]. Um levantamento publicado de uma
base de dados de 4.000 projetos, constatou a ocorrncia freqente
dos seguintes problemas:
70% dos projetos de grandes aplicativos sofrem instabilidade
dos requisitos. Os requisitos crescem tipicamente cerca de 1% ao
ms, atingindo nveis de mais de 25% de inchao ao final do
projeto.
Pelo menos 50% dos projetos so executados com nveis de
produtividade abaixo do normal.
Pelo menos 25% dos softwares de prateleira e 50% dos
produtos feitos por encomenda apresentam nveis de defeitos
superiores ao razovel.
Produtos feitos sob presso de prazos podem quadruplicar o
nmero de defeitos.

MeGAZINE

Delphi
Pelo menos 50% dos grandes projetos de software estouram
seu oramento e seu prazo.
2/3 dos projetos de software muito grandes so cancelados
Esquema de
Classificao de
Riscos

Descrio

Alto

A correo de irregularidades
ou a implementao de
melhorias apresentam risco alto
de impacto negativo no projeto.

Mdio

A correo de irregularidades
ou a implementao de
melhorias apresentam risco
mdio de impacto negativo no
projeto.

Baixo

A correo de irregularidades
ou a implementao de
melhorias apresentam risco
baixo de impacto negativo no
projeto.

Zero

A correo de irregularidades
ou a implementao de
melhorias apresentam risco
desprezvel de impacto negativo
no projeto.

antes do final.
Os usurios no ficam satisfeitos com 25% dos produtos
comerciais para PC, 30% dos produtos comerciais para
mainframe e 40% dos produtos feitos por encomenda.
Tipicamente, 50% do patrimnio de software das empresas
no so usados.
Atritos entre a rea de tecnologia da informao e a alta
gerncia ocorrem em mais de 30% das organizaes.
Atritos com clientes ocorrem, no desenvolvimento de
aplicativos, em 50% dos contratos por administrao e 65% dos
contratos por empreitada.
O risco de projeto pode ser estimado qualitativamente. O
principal objetivo da anlise de riscos desenvolver um conjunto
de estratgias de preveno de riscos.

Gesto de Riscos

Tabela 1
Esquema de classificao de riscos - IEEE [3].

Gesto de Riscos composta por atividades coordenadas para


direcionar uma organizao em relao ao risco. A gesto de
riscos, geralmente inclui avaliao, tratamento, aceitao e
comunicao de riscos.
A gesto de riscos envolve cinco atividades principais:
Planejamento, controle, monitorao, direcionamento e
recrutamento [5].
A gesto de riscos particularmente importante para projetos
de software, devido s incertezas inerentes que a maioria dos

Figura 1 - Taxonomia da engenharia de riscos.

MeGAZINE

Delphi
projetos enfrenta.

monitorados:

De modo simplificado, podemos pensar no risco como uma


probabilidade de que alguma circunstncia adversa realmente
venha ocorrer. Os riscos podem ameaar o projeto, o software que
est sendo desenvolvido ou a organizao. Essas categorias de
riscos podem ser definidas como se segue:

A estimativa de riscos uma atividade muito importante e


pouco praticada; um bom planejamento no apenas o que deve
acontecer se tudo correr bem, mas tambm o que pode correr
mal, quais as conseqncias dos problemas e o que pode ser feito
para combat-los. Entre os fatores de riscos que devem ser
considerados podem ser includos:

1. Riscos relacionados ao Projeto: So os riscos que afetam a


programao ou os recursos do projeto.
2. Riscos relacionados ao Produto: So os riscos que afetam a
qualidade ou o desempenho do software que est em
desenvolvimento.
3. Riscos para os negcios: So os riscos que afetam a
organizao que est desenvolvendo ou adquirindo o software.
O processo de gesto de riscos envolve vrios estgios:
1. Identificao dos riscos: So identificados os possveis riscos
de projeto, produto e negcios.
2. Anlise de riscos: So avaliadas as possibilidades e as
conseqncias da ocorrncia desses riscos.
3. Planejamento de riscos: So traados planos para
enfrentar os riscos, seja evitando-os, seja minimizando seus
efeitos sobre o projeto.
4. Monitoramento de riscos: O Risco constantemente
avaliado e os planos para a diminuio dos riscos revisados,
medida que mais informaes sobre eles se tornam disponveis.

Risco

Gravidade

legais;
Tecnolgicos;
devidos ao tamanho e complexidade do produto;
relativos a pessoal;
relativos aceitao pelos usurios;

Sommerville, descreve os tipos de riscos que podem afetar o


projeto e do ambiente organizacional em que o software est
sendo desenvolvido. [3]
Contudo, muitos riscos so considerados universais e eles
envolvem as seguintes reas:

Tecnologia
Pessoal
Organizacional
Ferramentas
Requisitos
Tabela 2
Exemplo de Estimativa de Riscos

Segundo Pdua [4], os riscos dever ser estimados e

Prioridade

Riscos
Riscos
Riscos
Riscos
Riscos

Probabilidade
de ocorrncia

Impacto Previsto

Contramedidas
Previstas

Falta de Equipamentos
para testes beta.

Alta

Mdia

Impossibilidade de
realizar os testes beta.

Cobrar providncia do
cliente.

Defeitos na Engenharia de
Software

Mdia

Mdia

Vrios dias de atraso por


alterao de requisitos.

Incluir na primeira liberao


os requisitos mais
complexos.

Falta de Usurios
responsveis por testes.

Alta

Baixa

Impossibilidade de
realizar os testes beta.

Cobrar providncia do
cliente.

Falta de inventrio das


mercadorias para o
cadastramento

Alta

Baixa

Impossibilidade de
realizar os testes beta.

Cobrar providncia do
cliente.

Falta de povoamento inicial


das bases de dados.

Alta

Baixa

Impossibilidade de
realizar os testes beta.

Cobrar providncia do
cliente.

Mudana de Legislao

Mdia

Baixa

Pode ser necessrio


refazer partes referentes
nota fiscal.

Isolar as classes e interfaces


susceptveis de mudana de
legislao.

MeGAZINE

Delphi
Estimativa
A estimativa dos riscos compreende as seguintes tarefas:
Identificao dos riscos possveis em relao ao projeto;
Anlise desses riscos, avaliando-lhes a probabilidade e o
provvel impacto;
Previso de contramedidas curativas ou preventivas;
Priorizao dos riscos, organizando-os de acordo com a
probabilidade e o impacto.
Os riscos no permanecem constantes durante a execuo de
um projeto. Alguns desaparecem, outros novos surgem, e outros
sofrem alteraes de probabilidade e impacto, mudando portanto
a prioridade. Um relatrio de acompanhamento do projeto
juntamente com uma tabela atualizada para monitorao dos
riscos. A tabela de estimativa deve ser repetida e atualizada para
refletir as modificaes ocorridas, at que os riscos sejam
concretizados ou completamente eliminados [4]

institudos imediatamente. O grau em que o projeto est em risco


diretamente proporcional ao nmero de respostas negativas a
essas questes.
Segundo PMBOK [6], existem ferramentas e tcnicas para
identificao de riscos. So elas:
Listas de Verificao: Questes do produto, tecnologia e
pessoas envolvidas no projeto;
Fluxogramas: Melhor compreenso das causas e efeitos dos
riscos do projeto;
Entrevistas: Entrevistas orientadas aos riscos com
participao de vrias partes envolvidas;

Concluso
Aqui foi possvel verificar a importncia da gesto de riscos
nos projetos de software. O Fracasso ou o sucesso esto
diretamente ligadas a essas variveis e contudo sero objetos de
estudo e anlise para que possam ser monitoradas e controlados
durante os projetos de software.

As questes a seguir foram derivadas de dados de riscos


obtidos por levantamento feito com gerentes de projeto de
software experientes, em diferentes partes do mundo [1].

A partir do estudo do Estado da Arte, podemos identificar os


riscos e analis-los diante do seu grau de ocorrncia.

As questes esto ordenadas por sua importncia relativa em


relao ao sucesso de um projeto:

Para validar este processo utiliza-se o para-analisador,


construdo atravs da Lgica Paraconsistente.

1. A alta administrao do software e do cliente empenhou-se


formalmente em apoiar o projeto?
2. Os usurios finais esto entusiasticamente empenhados
com relao ao projeto?
3. Os requisitos esto plenamente entendidos ?
4. Os clientes envolveram-se totalmente na especificao dos
requisitos?
5. Os usurios finais tm expectativas realistas ?
6. O escopo do projeto estvel?
7. A equipe de projeto tem a combinao de aptides
adequadas?
8. Os requisitos do projeto so estveis?
9. A equipe de projeto tem experincia com a tecnologia a ser
implementada?
10. A quantidade de pessoal adequada ao projeto?
11. Todos os membros da equipe e usurios envolvidos no
projeto concordam com a importncia do projeto e com os
requisitos do sistema?
Se qualquer dessas questes for respondida negativamente,
os passos de atenuao, monitorao e gesto devem ser

MeGAZINE

Referncias Bibliogrficas
[1] PRESSMAN, ROGER S., Engenharia de Software, Rio de
Janeiro, Ed. McGraw-Hill, 2002.
[2] REZENDE, DENIS ALCIDES, Engenharia de Software e
Sistemas de Informaes, Rio de Janeiro, Ed. Brasport, 1999.
[3] SOMMERVILLE, IAN, Engenharia de Software, So
Paulo, Ed. Pearson Education, 2003.
[4] FILHO, WILSON DE PDUA PAULA, Engenharia de
Software, Rio de Janeiro, Ed. LTC, 2003.
[5] PETERS, JAMES F. et al. Engenharia de Software,Rio de
Janeiro, Ed. Campus,2001.
[6]PMI, PMBOK, Project Management Institute, 2000.

Sobre o autor
Marcelo Nogueira Mestre em Engenharia de Produo com
nfase em Gesto da Informao, bacharel em Anlise de
Sistemas, Professor Universitrio, Instrutor e
Desenvolvedor Delphi desde 1995, Membro fundador do
DUG-BR. e-mail: marcelo@noginfo.com.br

Delphi

Usando
Usando o
o componente
componente
TWebBrowser
TWebBrowser
Por Claudinei Rodrigues

Ol amigos.
Nos ltimos dias alguns scios tm entrado em contato com o
nosso suporte tcnico solicitado informaes sobre como utilizar o
componente TWebBrowser que fica localizado na palheta
Internet. Sendo assim eu reuni algumas dicas bem
interessantes, as quais voc pode ver a seguir.

Usando o TWebBrowser para visualizar e imprimir


documentos do Microsoft Word.
Atravs do componente TWebBrowser ns podemos utilizar o
Microsoft Word como uma ferramenta de impresso para a nossa
aplicao.
Aqui est como voc pode utilizar o TWebBrowser para
controlar a tanto a visualizao quanto a impresso dos
documentos do Microsoft Word.
// Evento OnClick do componente Button
procedure TForm1.Button1Click(Sender:
TObject);
begin
// Abre um documento do Word no componente
WebBrowser
WebBrowser1.Navigate(C:\Meus
documentos\Exemplo.doc) ;
end;

Como verificar se um documento mostrado no


TWebBrowser est localizado no seu HD.
Se voc precisa saber a localizao de um documento
mostrado no componente TWebBrowser, voc ir precisar acessar
a propriedade Protocol. Veja abaixo como a rotina:

// Funo que ir localizar o arquivo


function ProcuraDoc(wb: TWebBrowser):
boolean;
const
fileProtocol = file:;
var
protocol : string;
begin
if Assigned(wb.Document) then
protocol :=
wb.Oleobject.Document.Location.Protocol;
result := protocol = fileProtocol;
end;
// Aqui o evento OnClick do componente
// Button que mostra como utilizar a funo
// ProcuraDoc
procedure TForm1.Button2Click(Sender:
TObject);
begin
if ProcuraDoc(WebBrowser1) then
ShowMessage(O documento est no drive
local ou em sua rede.) ;
end;

Como localizar e destacar uma informao de uma


WebPage mostrada no TWebBrowser.
Veja aqui como voc pode localizar uma informao em um
documento web atravs do componente TWebBrowser e quando
encontr-lo, poder destac-lo para que a visualizao fique mais
fcil. A funo ProcuraTexto ir receber dois parmetros. O
primeiro o prprio componente TWebBrowser e o segundo
parmetro o texto a ser localizado. Ao executar a funo voc

MeGAZINE

Delphi
notar que o texto que for localizado ficar com o fundo amarelo.
Veja abaixo a nossa funo ProcuraTexto e tambm como voc
pode utiliz-la.
// Esta funo ir localizar e destacar o
texto
procedure ProcuraTexto(WB: TWebBrowser;
Texto: string) ;
const
prefix = <span style=color:black;
background-color: yellow;>;
suffix = </span>;
var
tr: IHTMLTxtRange;
begin
if Assigned(WB.Document) then
begin
tr := ((wb.Document AS
IHTMLDocument2).body AS
IHTMLBodyElement).createTextRange;
while tr.findText(Texto, 1, 0) do
begin
tr.pasteHTML(prefix +
tr.htmlText + suffix) ;
tr.scrollIntoView(True) ;
end;
end;
end;
// Aqui o evento OnClick do componente
// Button que mostra como utilizar a funo
// ProcuraTexto
procedure TForm1.Button3Click(Sender:
TObject);
begin
ProcuraTexto(WebBrowser1,Template) ;
end;

Como salvar uma WebPage que est sendo


mostrada no componente TWebBrowser em um
arquivo HTML em seu drive local
Aqui ns vamos mostrar como uma WebPage que est sendo
mostrada dentro do componente TWebBrowser pode ser salva
como um arquivo .HTML no seu HD.
// Esta funo tem a finalidade de salvar a /
/ pgina exibida no componente TWebBrowser em
// um arquivo .HTML no seu drive local
procedure Salva_Em_HTML
(WB:TWebBrowser; const Arquivo : string);
var

MeGAZINE

PersistStream: IPersistStreamInit;
Stream: IStream;
FileStream: TFileStream;
begin
if not Assigned(WB.Document) then
begin
ShowMessage
(Documento no foi encontrado!);
Exit;
end;
PersistStream := WB.Document as
IPersistStreamInit;
FileStream := TFileStream.Create
(Arquivo, fmCreate);
try
Stream := TStreamAdapter.
Create(FileStream, soReference) as
IStream;
if Failed(PersistStream.Save
(Stream, True)) then
ShowMessage(No foi possvel salvar o
arquivo !);
finally
FileStream.Free;
end;
end;
// Aqui o evento OnClick de um boto que
// mostra como voc deve utilizar esta funo
procedure TForm1.Button4Click(Sender:
TObject);
begin
//Primeiro chame a pgina desejada
WebBrowser1.Navigate
(http://www.theclub.com.br);
//Depois basta salv-la
Salva_Em_HTML(WebBrowser1,c:\theclub.html);
end;
Para que este cdigo funcione corretamente voc deve
declarar a unit ActiveX.

Como chamar o FindDialog para localizar um texto


em uma WebPage que est sendo mostrada no
componente TWebBrowser.
Quando voc est navegando na internet utilizando um
navegador como o Internet Explorer por exemplo, as vezes voc
quer localizar um texto. Da voc vai ao menu do Internet
Explorer e clica em Editar | Localizar ou simplesmente digita
CTRL + F. Da aparece uma janela de dilogo onde voc digita o
que quer pesquisar. Esta funo que est sendo demonstrada a

Delphi
seguir faz a mesma coisa.
// Esta procedure ir chamar a tela
// de dialogo onde voc ir digitar
// a informao a ser pesquisada.
procedure FindDialog
(WB: TWebbrowser) ;
const
CGID_WebBrowser: TGUID =
{ED016940-BD5B-11cf-BA4E-00C04FD70816};
HTMLID_FIND = 1;
var
CmdTarget : IOleCommandTarget;
vaIn, vaOut: OleVariant;
PtrGUID: PGUID;
begin
New(PtrGUID) ;
PtrGUID^ := CGID_WebBrowser;
if WB.Document <> nil then
try
WB.Document.QueryInterface
(IOleCommandTarget, CmdTarget) ;
if CmdTarget <> nil then
try
CmdTarget.Exec(PtrGUID,
HTMLID_FIND, 0, vaIn, vaOut) ;
finally
CmdTarget._Release;
end;
except
end;
Dispose(PtrGUID) ;
end;
// Aqui o evento OnClick de um boto
// que mostra como voc deve utilizar
// a funo FindDialog
procedure TForm1.Button5Click(Sender:
TObject);
begin
FindDialog(WebBrowser1) ;
end;

Como ver o cdigo fonte de uma WebPage que est


sendo mostrada no componente TWebBrowser.
Quando voc acessa uma Home Page atravs do Internet
Explorer por exemplo, voc pode clicar com o boto direito sobre a
pgina e selecionar o item Exibir cdigo fonte e ver o cdigo fonte
utilizado naquela pgina.
Veja a seguir a rotina que podemos utilizar para obter este
mesmo efeito.

10

// Esta procedure tem a finalidade de


// mostrar o cdigo fonte de uma home page
procedure Mostra_Codigo_Fonte
(WB: TWebbrowser) ;
const
CGID_WebBrowser: TGUID =
{ED016940-BD5B-11cf-BA4E-00C04FD70816};
HTMLID_VIEWSOURCE = 2;
var
CmdTarget : IOleCommandTarget;
vaIn, vaOut: OleVariant;
PtrGUID: PGUID;
begin
New(PtrGUID) ;
PtrGUID^ := CGID_WebBrowser;
if WB.Document <> nil then
try
WB.Document.QueryInterface
(IOleCommandTarget, CmdTarget) ;
if CmdTarget <> nil then
try
CmdTarget.Exec(PtrGUID,
HTMLID_VIEWSOURCE, 0, vaIn, vaOut) ;
finally
CmdTarget._Release;
end;
except
end;
Dispose(PtrGUID) ;
end;
// Aqui o evento OnClick de um boto
// que mostra como voc deve utilizar
// a funo Mostra_Codigo_Fonte
procedure TForm1.Button6Click(Sender:
TObject);
begin
Mostra_Codigo_Fonte(WebBrowser1);
end;

Como imprimir uma WebPage que est sendo


mostrada no componente TWebBrowser.
Veja a seguir vrias formas de imprimir utilizando o
componente TWebBrowser.
// Manda diretamente para a impressora
procedure Imprime_Sem_Janela_Dialogo(WB:
TWebBrowser) ;
var
vIn, vOut: OleVariant;
begin

MeGAZINE

Delphi
WB.ControlInterface.ExecWB(OLECMDID_PRINT,
OLECMDEXECOPT_DONTPROMPTUSER, vIn, vOut) ;
end;
//Imprime depois de chamar a tela de dilogo
procedure Imprime_Com_Janela_Dialogo(WB:
TWebBrowser) ;
var
vIn, vOut: OleVariant;
begin
WB.ControlInterface.ExecWB(OLECMDID_PRINT,
OLECMDEXECOPT_PROMPTUSER, vIn, vOut) ;
end;
// Chama o preview
procedure Mostra_Preview(WB: TWebBrowser) ;
var
vIn, vOut: OleVariant;
begin
WB.ControlInterface.ExecWB(OLECMDID_PRINTPREVIEW,
OLECMDEXECOPT_DONTPROMPTUSER, vIn, vOut) ;
end;
//Chama o Print Setup
procedure Chama_PrintSetup(WB: TWebBrowser) ;
var
vIn, vOut: OleVariant;
begin
WB.ControlInterface.ExecWB(OLECMDID_PAGESETUP,
OLECMDEXECOPT_PROMPTUSER, vIn, vOut) ;
end;

Como desabilitar o Context Menu em um


TWebBrowser
Veja abaixo como podemos desabilitar o menu de contexto,
que aquele que voc clica com o boto direito do mouse.
// Esta a funo que desabilita
function MouseProc(nCode: Integer; wParam,
lParam: Longint): LongInt; stdcall;
var
classbuf: array[0..255] of Char;
const
ie = Internet Explorer_Server;
begin
case nCode < 0 of
True:
Result := CallNextHookEx
(MouseHook, nCode, wParam, lParam);
False:
case wParam of
WM_RBUTTONDOWN, WM_RBUTTONUP:
begin

MeGAZINE

GetClassName(PMOUSEHOOKSTRUCT(lParam)^.
HWND, classbuf, SizeOf(classbuf)) ;
if lstrcmp(@classbuf[0],
@ie[1]) = 0 then
Result := HC_SKIP
else
Result := CallNextHookEx
(MouseHook, nCode,
wParam, lParam) ;
end
else
begin
Result := CallNextHookEx
(MouseHook, nCode,
wParam, lParam) ;
end;
end;
end;
end;
// Aqui o evento OnCreate do form onde
// estamos chamando a funo que desabilita
// o Context Menu
procedure TForm1.FormCreate(Sender: TObject);
begin
MouseHook := SetWindowsHookEx(WH_MOUSE,
MouseProc, 0, GetCurrentThreadId()) ;
end;
// Aqui o OnDestroy do form onde
// estamos habilidando novamente
// o Context Menu
procedure TForm1.FormDestroy(Sender:
TObject);
begin
if MouseHook <> 0 then
UnHookWindowsHookEx(MouseHook) ;
end;

Concluso
Estas foram algumas dicas que temos disponveis a respeito
do componente TWebBrowser. Se voc tiver mais alguma dica e
quiser v-la publicada em nossa revista, mande um e-mail para
suporte@theclub.com.br que teremos o maior prazer em publiclas.
Um abrao a todos e at o prximo ms.

Sobre o autor
Claudinei Rodrigues,
Consultor Tcnico do The Club
nei@theclub.com.br

11

Delphi

Criando
Criando arquivo
arquivo PDF
PDF
aa partir
partir do
do Delphi.
Delphi.

Introduo
Nesta matria iremos verificar como criar arquivos PDF a
partir do Delphi, esse tpico bastante abordado pois muito
importante que nosso sistema possa exportar dados de uma
forma segura e de fcil visualizao.
Alguns geradores de relatrios j trazem embutidas essas
particularidades, mas em alguns casos no temos esses gerados a
disposio ou a estrutura que iremos montar no se encaixa num
gerador de relatrio. Sendo assim, temos a possibilidade de
montar o PDF via programao, incluindo assim as informaes
conforme a necessidade.

Componente Externo
Para a criao do arquivo PDF utilizaremos um componente
externo e free chamado TNPDF. Esse componente bastante
simples composto de apenas uma unit onde o PDF gerado.
Junto com esse componente temos um outro componente
tambm free chamando ZLIB, que ser utilizado para fazer a
compactao do arquivo PDF gerado.

PASZLIB.ZIP: Contm os arquivos do componente para


compactao do PDF. Descompacte esse arquivo junto com o
arquivo TNPDF.PAS.
Observao:
No iremos instalar o componente TNPDF no Delphi, pois
mais adiante ele ser instalado junto com outro componente para
exportao a partir do QuickReport. Sendo assim para utiliz-lo
deixaremos os arquivos .PAS no mesmo diretrio onde o nosso
projeto ser criado.

Criando um simples exemplo


Crie um novo projeto e coloque em seu form os seguintes
componentes:
Button1, Image1, Memo1, Label1, SaveDialog1
No componente Memo1 carregue o contedo do arquivo
readme.txt e no arquivo Image1 carregue uma imagem de
exemplo. Ao trmino o nosso form ficar parecido com a figura1.
Na seo implementation declare a unit TNPDF.

Antes de iniciar o projeto de exemplo vamos baixar esses dois


componentes, para isso acesse o seguinte link:
www.theclub.com.br/revista/download/tnpdf.zip
Descompacte o arquivo zip e poder encontrar os seguintes
arquivos:
TNPDF.PAS: Contem a programao do componente para
gerar o PDF;
READ_ME.TXT: Contem algumas informaes importantes;

12

implementation
uses tnpdf;
Em seguida criaremos uma procedure contendo as instrues
para gerar o arquivo PDF:
procedure TForm1.Relat1(NomeArq: String);
var PDF:TPrintPDF;
begin

MeGAZINE

Delphi

Figura 1:
{ Cria o componente TPrintPDF }
PDF := TPrintPDF.Create(self);
try
{ Configurar o ttulo do documento }
PDF.TITLE := Label1.Caption;
{ Usando o componente para compactao do
arquivo }
PDF.Compress := true;
{ Configurar o tamanho da pgina }
PDF.PageWidth := 612;
PDF.PageHeight := 792;
{ Indica o nome do arquivo a ser gerado }
PDF.FileName := NomeArq;
{ Inicia a impresso }
PDF.BeginDoc;
{ Configura o tamanho da linha }
PDF.LineWidth := 1;
{ Desenha uma linha no PDF }
PDF.DrawLine(12,50,600,50);
{ Configura o tamanho da linha }

MeGAZINE

PDF.LineWidth := 2;
{ Desenha um retngulo no PDF }
PDF.DrawRectangle(12,12,600,780);
{ Configura a fonte a ser impressa. Essa
fonte definida dentro do componente
devido ao nome a ser utilizado na
estrutura do PDF }
PDF.Font.Name := poHelveticaBold;
PDF.Font.Size := 20;
{ Imprime Texto no corpo do PDF }
PDF.TextOut(15,30,Label1.Caption);
PDF.Font.Size := 10;
PDF.TextOut(15,45,THE CLUB, O maior
clube de programadores do Brasil);
{ Configura a Fonte }
PDF.Font.Name := poTimesRoman;
PDF.Font.Size := 12;
{ Imprime o contedo de um memo }
PDF.MemoOut(15,60, Memo1);
{ Adiciona nova pgina }

13

Delphi
QuickReport e com o FastReport, mas nesta verso que estou
disponibilizando no site do THE CLUB o componente estar
trabalhando somente com o quickreport. Caso algum queira
pegar a verso que tambm trabalha com o FastReport
recomendo que acesse o site do fabricante no seguinte link: http://
usuarios.lycos.es/isma

PDF.NewPage;
{ Imprime um retngulo }
PDF.DrawRectangle(12,12,600,780);
{ Imprime uma imagem }
PDF.Draw(15,15,Image1);
{ Finaliza o documento }
PDF.EndDoc;
finally
{ Destroi o componente da memria }
PDF.Free;
end;
end;
No evento onclick do boto coloque a instruo para chamar a
procedure:
procedure TForm1.Button1Click(Sender:
TObject);
begin
if SaveDialog1.Execute then
begin
Relat1( SaveDialog1.FileName );
end;
end;

Agora estando com o componente instalado podemos coloc-lo


no form do nosso projeto que contem o relatrio criado no
QuickReport e depois atravs de um boto colocar a instruo que
ir fazer a exportao. A instruo do boto para exportao
ficar da seguinte forma:

Pronto agora podemos compilar esse projeto e executar, ao


qual ir gerar o arquivo PDF normalmente.
Esse projeto de exemplo est disponvel para download
atravs do seguinte link:
www.theclub.com.br/revista/download/Exemplo.zip

Gerando PDF a partir do QuickReport.


Neste segundo caso iremos utilizar outro componente
chamado ExportQR, tambm externo e Freeware que permitir a
partir do QuickReport gerar o arquivo PDF.
Para gerar o PDF esse componente pega o Metafile que a
imagem do relatrio gerada pelo Quickreport e transfere para o
componente que faz a exportao, podendo atravs desse
componente exportar o relatrio para os formatos PDF, JPG,
BMP, WMF e EMF.
Antes de iniciar-mos os trabalhos devemos baixar esse novo
componente atravs do seguinte link:
www.theclub.com.br/revista/download/expack12.zip
Observao:
Esse componente ExportQR foi criado para trabalhar com o

14

A instalao desse componente bastante simples, abra o


arquivo ExPackD6.dpk (Delphi 6) ou ExPackD7.dpk (Delphi 7)
atravs do delphi e em seguida compile e instale. Esse
componente j est trazendo os dois componentes utilizados no
primeiro exemplo, isso , o componente TNPDV e o componente
de compactao.
Aps efetuar a instalao acesse o menu Tools, do Delphi, e
depois a opo Environment Options. Selecione a aba Library e
depois acesse o boto da Library path.
Na janela que ser aberta indique o caminho onde esto os
arquivos .pas do componente e depois clique em Add e em seguida
em Ok.

procedure TMainForm.BtnExportQRClick(Sender:
TObject);
begin
{ Liga o componente do QuickReport ao
componente de exportao }
EXQR.Report := Rep;
{ Faz a exportao }
EXQR.ExportQR;
end;
Este componente tambm nos permite exportar relatrios a
partir do componente QRPreview que o componente ao qual
criamos preview personalizado no QuickReport.
Para isso podemos colocar um boto no form de preview e
neste boto colocar a seguinte instruo:
procedure TFPreviewQR.TBSaveClick(Sender:
TObject);
begin
{ Faz a ligao do QRPreview com o
componente }
EXQR.Preview := Preview;
{ Faz a exportao do relatrio }

MeGAZINE

Delphi
Esses cdigos acima podem ser encontrados no projeto de
Exemplo3 que acompanha o componente ExportQR.

EXQR.ExportQRFromPreview;
end;
Esses cdigos acima podem ser encontrados no projeto de
Exemplo1 que acompanha o componente ExportQR.

Outros formatos
A exportao dos relatrios para os demais formatos
bastante simples tambm, veja abaixo as sintaxes utilizadas para
cada tipo:
PDF com Alta Compresso:
EXQR.ExportQRPDF(edFileName.Text, True);
PDF com Baixa Compresso
EXQR.ExportQRPDF(edFileName.Text, False);
JPG
EXQR.ExportQRJPG(edFileName.Text);
BMP
EXQR.ExportQRBMP(edFileName.Text);
WMF
EXQR.ExportQRWMF(edFileName.Text);
EMF
EXQR.ExportQREMF(edFileName.Text);

MeGAZINE

Observao
No entrei em detalhes sobre a criao dos exemplos, para
que o foco principal que conhecer o componente no seja
perdido. Os projetos de exemplo aqui apresentados foram criados
pelos prprios fabricantes dos componentes e somente sofreram
algumas poucas alteraes como, por exemplo, traduo dos
forms para o portugus.

Concluso
Particularmente gostei muito desses componentes e acredito
que eles iro nos ajudar bastante na criao de arquivos PDF
atravs dos projetos em Delphi, sem aquela dependncia dos
geradores de relatrio.
Um grande abrao a todos e at a prxima.

Sobre o autor
Andr Colavite
Consultor Tcnico do The Club
colavite@theclub.com.br

15

Delphi

Explorando
Explorando oo QuickReport
QuickReport
Criando relatrios no triviais

Sobre o autor
Alessandro Ferreira, Consultor Tcnico do The Club
alessandro@theclub.com.br

Introduo

O evento OnNeedData

Entra e sai verso do Delphi e o QuickReport continua tendo


uma legio de usurios que, por conseguirem atender seus
clientes com este gerador, no vem necessidade de estar
migrando. Particularmente confesso que gosto do QuickReport,
apesar de todos os bugs nestes vrios anos de caminhada,
contudo, at hoje, no tive nenhuma situao onde o QuickReport
me deixou na mo e acredito ser este o motivo de muitos
programadores ainda o utilizarem.
Neste artigo irei demonstrar algumas tcnicas no
triviais na confeco de relatrios com o QuickReport, como por
exemplo, a montagem de um relatrio de referncia cruzada, um
relatrio muito utilizado na impresso de etiquetas onde voc
poder estar repetindo um mesmo registro por N vezes, etc.

Instalando o QuickReport no Delphi 7


A Borland no traz o QuickReport adicionado a IDE, porm,
traz o pacote dclqrt70.bpl referente o QuickReport na pasta:

Antes de comearmos, gostaria de explicar o evento


OnNeedData do QuickReport, pois, este evento ser muito
utilizado nestes exemplos. Por padro, quando ligamos um
componente DataSet na propriedade DataSet do QuickReport, ele
automaticamente assume o controle e vai movendo o ponteiro do
DataSet at atingir o ltimo registro e mostrando os dados em
uma banda DetailBand, por exemplo. Em muitas situaes no
este o resultado que necessitamos e poderemos precisar assumir o
controle da navegao nos registros e, exatamente isso que o
evento OnNeedData nos possibilita. A seguir, veja o escopo deste
evento:
procedure TForm1.QuickRep1NeedData(Sender:
TObject; var MoreData: Boolean);
begin
//
end;

C:\Arquivos de programas\Borland\Delphi7\Bin
Para adicionar, acesse o menu Component | Install Packages
| Add e adicione o referido pacote. Aps adicionar, recomendo
efetuar atualizao do QuickReport que est disponvel para
download no site do fabricante no endereo:
Delphi 7
http://www.qusoft.com/
getfile.asp?level=0&Filename=QRSTD351D7.EXE

Observe que temos um parmetro chamado MoreData. No


momento da impresso, o QuickReport dispara este evento e
verifica o valor do parmetro MoreData e caso este seja
verdadeiro (true) ir forar a impresso de mais uma
DetailBand, ou seja, ir gerar mais uma linha em nosso relatrio
e no momento que encontrar esta varivel falsa, ir encerrar o
relatrio.

Banco de Dados
Iremos utilizar o Firebird 1.5.2 onde a princpio vamos criar
duas tabelas, sendo uma contendo os dados dos clientes e outra
contendo as compras efetuadas por estes clientes. Sugiro utilizar
o IBExpert (www.ibexpert.com) que uma ferramenta gratuita

Delphi 6
http://www.qusoft.com/
getfile.asp?level=0&Filename=qr351sd6.exe

16

MeGAZINE

Delphi
para manuteno em bancos Interbase/Firebird para criar o
banco de dados e suas tabelas. (Poder encontrar referncia
sobre o IBExpert em nossa revista de Dezembro/2004).
Vamos criar as estrutura da tabela Clientes, veja o cdigo na
listagem 1.
CREATE TABLE
ID
NOME
ENDERECO
BAIRRO
CIDADE
UF
CEP
CNPJ_CPF
RG_IE
TELEFONE
EMAIL
);

Agora vamos adicionar alguns registros que iro representar


as compras destes clientes, veja a figura 2.

CLIENTES (
INTEGER NOT NULL PRIMARY KEY,
VARCHAR(70),
VARCHAR(70),
VARCHAR(30),
VARCHAR(30),
CHAR(2),
CHAR(10),
VARCHAR(18),
VARCHAR(18),
VARCHAR(18),
VARCHAR(80)

Listagem 1 Tabela Clientes


Agora vamos criar uma tabela chamada Vendas, a qual ter
uma estrutura bem simples apenas para ilustrar nosso relatrio,
veja a listagem 2.
CREATE TABLE VENDAS (
NF CHAR(6) NOT NULL PRIMARY KEY,
DATA DATE NOT NULL,
CLIENTE_ID INTEGER NOT NULL,
VALOR_TOTAL NUMERIC(15,2) NOT NULL
);
ALTER TABLE VENDAS ADD CONSTRAINT
FK_VENDAS_CLIENTES
FOREIGN KEY (CLIENTE_ID) REFERENCES
CLIENTES (ID);
Listagem 2 Tabela Vendas
Para podermos testar nosso relatrio, vamos acionar alguns
registros em ambas as tabelas Para isso, poder utilizar a aba
Data do IBExpert e vamos inserir alguns clientes, veja a figura
1.

Figura 2 Vendas

Obs. Adicione dados para todos os clientes alternando


valores e datas. Se preferir, poder baixar o projeto de
exemplo apresentado neste artigo no qual j adicionamos
dados nas tabelas para testes, veja o endereo no final deste
artigo.

1. Construindo um relatrio de referncia cruzada


(CrossTab)
Nosso primeiro exemplo ser a construo de um relatrio de
cruzamento de dados, ou seja, um relatrio CrossTab.
Diferente de outros gerados de relatrios que trazem este
recurso embutido, no QuickReport teremos que fazer tudo no
brao utilizando entre outros, o eventos OnNeedData
anteriormente descrito.
Primeiro, vamos criar um projeto no Delphi 7 onde iremos
atravs da dbExpress acessar o banco de dados e gerar uma
consulta SQL para agrupar os dados de acordo com nossas
necessidades e depois utiliz-los em nosso relatrio.
Adicione um componente SQLConnection (dbExpress), altere
sua propriedade Name para cnxCrossTab, a propriedade

Figura 1 Clientes

MeGAZINE

17

Delphi
Adicione um componente DataSetProvider, configure Name
para dspCrossTab e DataSet para sdsCrossTab. Aps isso,
adicione um componente ClientDataSet, configure Name para
cdsCrossTab, ProviderName para dspCrossTab e
depois clique com o boto direito no mesmo e
selecione a opo: Fetch Params.

LoginPrompt para False, d um duplo clique no componente e


adicione uma conexo apontando para nosso banco de dados de
exemplo, conforme sugere a figura 3.

Para testes, se executar esta sentena SQL no


IBExpert, ter o resultado apresentado na figura 4.

Figura 3 Conexo dbExpress.


Prosseguindo, adicione um componente SQLDataSet,
configure a propriedade SQLConnection para cnxCrossTab,
Name para sdsCrossTab e na propriedade CommandText
adicione a sentena SQL apresentada na listagem 3.

Figura 4 Select executado

Select
CLI.NOME AS CLIENTE, EXTRACT(MONTH FROM
VEN.DATA) AS MES,SUM(VEN.VALOR_TOTAL) AS TOTAL
From
VENDAS VEN
Left Outer Join CLIENTES CLI
on CLI.ID = VEN.CLIENTE_ID
Where
EXTRACT(YEAR FROM VEN.DATA) = :ANO
Group By
CLI.NOME,
EXTRACT(MONTH FROM VEN.DATA)

Observe que os dados ficam arranjados contendo ms/total


linha a linha para cada cliente. Contudo, um relatrio de
referncia cruzada consiste em arranjar os dados na estrutura
apresentada na tabela 1.
Dando continuidade a implementao do relatrio, adicione
um componente QuickReport, altere Name para QR_CrossTab.
Em cima deste QuickReport, adicione trs componentes QRBand,
configurando a propriedade BandType para rbPageHeader,
rbDetail e rbSummary, respectivamente. Devido a estrutura
deste relatrio, vamos necessitar de mais espao na transversal,
por isso, selecione o QuickReport e altere a propriedade Page |
Orientation para poLandscape.

Listagem 3 Sentena SQL.


Cliente

Jan

Fev

Mar

Abr

Mai

Jun

Jul

Ago

Set

180,00

420,00

280,00

500,00

420,00

180,00

100,00

320,00

180,00 100,00

Emerson... 1267,00 487,00 1850,00 1190,00 1190,00 530,00

650,00

540,00

221,00

311,00

Alessand... 420,00

Total

Out

Nov

Dez

Total

500,00

3.600,00

123,00 1205,00

9.564,00
13.164,00

18

MeGAZINE

Tabela 1
Dados arranjados em
cross-tab

Delphi
Tendo como base de layout a tabela 1 anteriormente
apresentada, vamos adicionar componentes QRLabel os quais
sero responsveis pela apresentao dos dados. Na banda
referente o cabealho, adicione 14 QRLabels ajustando o primeiro
com o Caption Nome do Cliente, os prximos 12 devero conter o
nome de cada ms comeando por Janeiro e o ltimo QRLabel
ter como Caption Total;

private
{ Private declarations }

Agora vamos adicionar os QRLabel na banda detalhe


(DetailBand) a qual ser responsvel pela apresentao dos
dados. Mais uma vez iremos necessitar de 14 QRLabels, seguindo
a mesma lgica da banda anterior, sendo o primeiro para
apresentao do nome do cliente, os 12 subseqentes para
apresentao dos valores respectivos cada ms e o ltimo para
uma totalizao dos meses. Vale ressaltar que iremos utilizar
uma nomenclatura especfica para estes componentes, pois, mais
adiante na codificao iremos implementar uma rotina genrica
para facilitar a implementao, assim sendo, nomeie os
componentes QRLabels da banda detalhe: qr_Nome, qr_01,
qr_02, qr_03, qr_04, qr_05, qr_06, qr_07, qr_08, qr_09,
qr_10, qr_11, qr_12, qr_13, respectivamente.

procedure ZeraTotColunas;
procedure LimpaValores;
procedure PreencheValores;
procedure LimpaSumario;
procedure PreencheSumario;
public
{ Public declarations }
end;

E para finalizar, vamos novamente adicionar mais 14


QRLabels, agora em cima da banda sumrio, seguindo a mesma
estrutura utilizada nas bandas anteriores e tendo o cuidado de
nomear os QRLabels para: tot_01, tot_02, tot_03, tot_04, tot_05,
tot_06, tot_07, tot_08, tot_09, tot_10, tot_11, tot_12, tot_13.

Adicionando cdigo ao nosso relatrio


Antes de iniciarmos a codificao de nosso relatrio, adicione
um componente Bitbtn e um MaskEdit ajustando o layout do
formulrio como apresenta a figura 5.

TotColunas: Array[1..12] of Extended;


TotCliente, TotGeral: Extended;
NomeDoCliente: String;
ImpTitulo: Boolean;

Listagem 4 Declaraes.
Dica: Aps efetuar estas declaraes, tecle a combinao
CTRL+SHIFT+C e automaticamente o editor ir criar o
cabealho dos procedimentos abaixo da sesso implementation.
Observe que declaramos um Array o qual ser responsvel
em armazenar a totalizao de cada coluna (ms) o qual iremos
apresentar no final do relatrio, na banda sumrio e para no ter
que fazer referncia a cada elemento do Array, implementamos
um mtodo para inicializar este Array, acompanhe a listagem 5.
{ Limpa Array que ir armazenar a totalizao
das colunas. }
procedure TForm1.ZeraTotColunas;
var
i: Integer;
begin
for i := Low(TotColunas) to
High(TotColunas) do
TotColunas[i] := 0;
end;
Listagem 5 Iniciar Array

Figura 5 Formulrio para chama do QuickReport


Obs. Apenas a ttulo de informao, o QuickReport
est neste mesmo formulrio, porm encontra-se
escondido e para visualiz-lo bastar aumentar o
tamanho do formulrio.
Iniciando a codificao, faa as seguintes declaraes abaixo
da sesso Private do objeto Form, conforme apresenta a listagem 4.

MeGAZINE

Prosseguindo, na listagem 6 apresentamos outros dois mtodos:


LimpaValores e LimpaSumario. O primeiro, ser responsvel em
limpar o contedo dos QRLabels existentes na banda detalhe
atribuindo 0,00 ao seu caption e veja que no fazemos referncia
direta ao nome dos QRLabels e sim dentro de um lao FOR
pesquisamos o componentes pelo seu nome, por isso a
importncia da nomenclatura anteriormente sugerida. O mtodo
LimpaSumario tem a mesma finalidade, contudo, aplica-se aos

19

Delphi
QRLabels existentes na banda sumrio.
{ Limpar os QRLabel da banda detalhe }
procedure TForm1.LimpaValores;
var
i: Integer;
C: TComponent;
begin
for i := 1 to 13 do
begin
C := FindComponent(qr_ +
FormatFloat(00, i));
if (C <> nil) and (C is TQRLabel) then
TQRLabel(C).Caption := 0,00;
end;
TotCliente := 0;
end;
{ Limpar os QRLabel da banda sumrio }
procedure TForm1.LimpaSumario;
var
i: Integer;
C: TComponent;
begin
for i := 1 to 13 do
begin
C := FindComponent(tot_ +
FormatFloat(00, i));
if (C <> nil) and (C is TQRLabel) then
TQRLabel(C).Caption := 0,00;
end;
TotGeral := 0;
end;
Listagem 6 Mtodos para limpar os QRLabels
O mtodo seguinte apresentado na listagem 7 um dos mais
importantes dentro deste contexto, pois, ser o responsvel em
preencher os QRLabels (da banda detalhe) com os valores
advindos do ClientDataSet:
{ Preenche os QRLabel da banda detalhe }
procedure TForm1.PreencheValores;
var
C: TComponent;
Mes: Integer;
begin
ImpTitulo := False;
while (NomeDoCliente =
cdsCrossTabCLIENTE.AsString) and not
(cdsCrossTab.EOF) do

20

begin
Mes := cdsCrossTabMES.AsInteger;
// Totaliza por coluna.
TotColunas[Mes] := TotColunas[Mes] +
cdsCrossTabTOTAL.AsFloat;
// Totaliza por cliente.
TotCliente := TotCliente +
cdsCrossTabTOTAL.AsFloat;
C := FindComponent(qr_ +
FormatFloat(00, cdsCrossTabMES.AsInteger));
if (C <> nil) and (C is TQRLabel) then
TQRLabel(C).Caption :=
FormatFloat(###,##0.00,
cdsCrossTabTOTAL.AsFloat);
qr_Nome.Caption :=
cdsCrossTabCLIENTE.AsString;
cdsCrossTab.Next;
end;
// Mostra total do Cliente.
qr_13.Caption := FormatFloat(###,##0.00,
TotCliente);
// Acumula total geral.
TotGeral := TotGeral + TotCliente;
ImpTitulo := True;
end;
Listagem 7 Mtodo que alimenta os QRLabels
Vamos explicar o mtodo PreencheValores, o qual comea
atribuindo false para a varivel ImpTitulo. Esta varivel ser
responsvel em controlar quando a banda detalhe dever ser
impressa, pois a mesma dever ser impressa apenas quando
todos os meses do referido cliente estiverem preenchidos. Voc
deve estar lembrando que o controle de navegao dos registros
por nossa conta e a fim de obtermos todos os registros referente o
cliente atual, efetuamos um lao enquanto o cliente permanecer o
mesmo e enquanto no atingir o final do arquivo. Dentro deste
lao, vamos acumulando o valor de cada coluna (ms) e o valor
referente ao cliente corrente. Mais uma vez recorremos ao
FindComponent para pesquisar e retornar os QRLabels
existentes na banda detalhe atravs do seu nome e caso seja
encontrado, alimentamos sua propriedade caption.
Ao trmino do while, verificamos que todos os dados cliente
armazenado na varivel NomeDoCliente foram obtidos e nos
resta efetuar a totalizao deste cliente e armazenar seu total na
varivel TotaGeral que ir ser apresentada na banda sumrio, e
atribuir true varivel ImpTitulo a qual ir liberar a impresso
da banda detalhe com todos os dados j carregados para o
respectivo cliente.

MeGAZINE

Delphi
Bem, estamos agora quase concluindo a codificao de nosso
relatrio, contudo, necessitamos alimentar os totais para cada
ms e um total geral em nossa banda sumrio.
Para isso, seguindo a mesma lgica do mtodo anterior,
porm, lendo os dados do Array TotColunas que representa o total
de cada coluna (ms), acompanhe a listagem 8.
{ Preenche os componentes da banda sumrio }
procedure TForm1.PreencheSumario;
var
C: TComponent;
i: Integer;
begin
for i := 1 to 12 do
begin
C := FindComponent(tot_ +
FormatFloat(00, i));
if (C <> nil) and (C is TQRLabel) then
TQRLabel(C).Caption :=
FormatFloat(###,##0.00, TotColunas[i]);
end;
tot_13.Caption := FormatFloat(###,##0.00,
TotGeral);
end;
Listagem 8 Alimentando os componentes da banda
sumrio.
Dando continuidade, d um duplo clique no Bitbtn que
ser responsvel em chamar o relatrio e adicione o cdigo
apresentado na listagem 9.
{ Chamar o relatrio }
procedure TForm1.btnVisualizarClick(Sender:
TObject);
begin
with cdsCrossTab do
begin
Close;
Params.ParamByName(ANO).AsInteger :=
StrToInt(MEdit_Ano.Text);
Open;
end;
QR_Titulo.Caption := QR_Titulo.Caption +
MEdit_Ano.Text;
QR_CrossTab.Preview;
end;
Listagem 9 Boto visualizar

MeGAZINE

No mencionei anteriormente, contudo, adicione um


componente QRLabel em cima da banda de cabealho
(PageHeader) e em seu caption escreva: Demonstrativo de
Vendas por Cliente Referente o Ano de: .
At aqui, apenas implementamos mtodos para vrias
funcionalidades dentro de nosso relatrio. Vamos agora efetuar a
chamada destes mtodos, os quais sero chamados em alguns
eventos do prprio QuickReport. Como primeiro evento, acesse o
BeforePrint do QuickReport e faa a seguinte codificao:
{ BeforePrint do QuickReport }
procedure
TForm1.QR_CrossTabBeforePrint(Sender:
TCustomQuickRep;
var PrintReport: Boolean);
begin
{ Manda CDS para o primeiro registro }
cdsCrossTab.First;
{ Guarda o nome do primeiro cliente }
NomeDoCliente :=
cdsCrossTabCLIENTE.AsString;
{ Inicializao }
LimpaValores;
LimpaSumario;
ZeraTotColunas;
end;
Na listagem 10 apresentamos as demais chamadas serem
efetuadas:
{ BeforePrint da banda detalhe }
procedure
TForm1.DetailBand1BeforePrint(Sender:
TQRCustomBand;
var PrintBand: Boolean);
begin
{ Alimenta os QRLabel }
PreencheValores;
{ Indica o momento que a banda dever ser
impressa }
PrintBand := ImpTitulo;
end;
{ Aps imprimir a banda detalhe }
procedure
TForm1.DetailBand1AfterPrint(Sender:
TQRCustomBand;
BandPrinted: Boolean);
begin

21

Delphi
{ Se a banda detalhe foi impressa, limpa os
QRLabel }
if BandPrinted then
LimpaValores;
NomeDoCliente :=
cdsCrossTabCLIENTE.AsString;
end;

Tudo pronto?! Bem, tambm espero que sim! Compile e rode


clique no boto visualizar e se no saiu nada errado o resultado
ser semelhante a figura 6.
Obs. Por questes de espao tivemos que cortar nosso
preview ao meio, mas possvel se ter uma idia de como ir
ficar.

{ BeforePrint da banda sumrio }


procedure
TForm1.SummaryBand1BeforePrint(Sender:
TQRCustomBand;
var PrintBand: Boolean);
begin
{ Alimenta os QRLabel do sumrio }
PreencheSumario;
end;

2. Imprimindo um mesmo registro N vezes


Voc j deve ter passado pela necessidade de imprimir um
mesmo registro por N vezes, como por exemplo, um cadastro de
produtos onde voc necessita imprimir vrias etiquetas para um
mesmo produto.

Listagem 10 Chamada dos mtodos


Tudo pronto? Se voc respondeu que sim, est enganado. Mas
calma, falta apenas um pequeno detalhe, porm muito
importante sem o qual nosso relatrio no ir funcionar. Lembra
que comentei do evento OnNeedData?! Bem, ser este evento que
ir fazer nosso relatrio funcionar, veja a listagem 11.
procedure TForm1.QR_CrossTabNeedData(Sender:
TObject; var MoreData: Boolean);
begin
{ Enquanto no for final de arquivo,
continua imprimindo }
MoreData := not (cdsCrossTab.EOF);
end;
Listagem 11 OnNeedData

Neste evento estamos atribuindo true ao parmetro


MoreData enquanto o ClientDataSet no atingir o final do
arquivo.

Via programao, bastaria efetuar um lao FOR ou WHILE e


enquanto a quantidade no fosse satisfeita, continuar a
impresso. E no QuickReport, como fazer? Isso bem simples e
iremos implementar um exemplo agora mesmo!
Mos a obra, crie um novo projeto Delphi ou se preferir utilize
o projeto anterior onde podemos aproveitar o mesmo banco de
dados, contudo, altere o SELECT no componente SQLDataSet
para Select * From CLIENTES, pois iremos utilizar os dados
apenas desta tabela. Adicione tambm um componente
DataSource ligado ao ClientDataSet e um componente DBGrid
ligado ao DataSource. A figura 7 sugere um layout para este
formulrio:

Figura 7
Layout sugerido

Adicione um componente QuickReport o


qual iremos nomear como QR_Etiqueta e sobre
este uma banda detalhe (rbDetail) e sobre esta
trs componentes QRDBText ligados ao
ClientDataSet e fazendo referncia aos campos:
NOME, ENDERECO e CIDADE,
respectivamente (figura 8).

Figura 6 Preview do relatrio

22

MeGAZINE

Delphi
Visualizar (listagem 12).

Figura 8 QR_Etiquetas

Codificando o Relatrio
Mais uma vez vamos utilizar o evento OnNeedData do
QuickReport para efetuar o controle da quantidade de etiquetas
imprimir. Lembre-se que a propriedade DataSet do QuickReport
deve ficar em branco, pois o controle ser manual.
Na listagem 11 apresentamos o evento OnNeedData do
QuickReport e o evento AfterPrint da banda detalhe.
procedure TForm1.QR_EtiquetaNeedData(Sender:
TObject;
var MoreData: Boolean);
begin
{ Enquanto a propriedade TAG estiver maior
que zero porque tem que imprimir mais uma
etiqueta }
MoreData := (QR_Etiqueta.Tag > 0);
end;
procedure
TForm1.DetailBand1AfterPrint(Sender:
TQRCustomBand;
BandPrinted: Boolean);
begin
{ A cada etiqueta impressa, vai
decrementando o contador }
QR_Etiqueta.Tag := QR_Etiqueta.Tag - 1;
end;
Listagem 11 Eventos
No evento OnNeedData atribumos verdadeiro ao parmetro
MoreData enquanto o valor da propriedade TAG do QuickReport
for maior que zero. No evento AfterPrint da banda detalhe,
vamos decrementando o valor da propriedade TAG aps cada
etiqueta impressa.

procedure TForm1.btnVisualizarClick(Sender:
TObject);
var
Quantidade: Integer;
begin
{ pega a quantidade de etiquetas }
TryStrToInt(MEdit_Quant.Text, Quantidade);
{
A propriedade TAG do QR ser utilizada
para efetuar o controle da quantidade de
etiquetas serem impressas.
}
QR_Etiqueta.Tag := Quantidade;
QR_Etiqueta.Preview;
end;
Listagem 12 Boto visualizar.
Compile e rode o preview e se tudo estiver OK ser
apresentado o nmero de etiquetas informadas para o registro
corrente.

3. Pintando uma imagem de fundo no relatrio


Dois fatores so fundamentais na apresentao de um
relatrio: O primeiro relevncia e confiabilidade das
informaes nele contidas e a segunda, o layout, o qual sem
dvidas ajuda a vender seu peixe. Neste exemplo, vou
demonstrar como desenhar uma imagem de fundo no
QuickReport, ou seja, uma marca dgua.
Crie um novo projeto no Delphi, adicione um boto, uma
Query e aponte sua propriedade DatabaseName para o alias
DBDEMOS e na propriedade SQL adicione a seguinte instruo:
Select * From Employee. Adicione um componente QuickReport
e sobre ele quatro QRBand sendo: rbTitle, rbColumnHeader,
rbDetail e rbPageFooter. Aponte a propriedade DataSet do
QuickReport para a Query e adicione QRDBText para
apresentao dos dados.
A figura 9 sugere a configurao do QuickReport.

Obs. A propriedade TAG dos objetos uma propriedade do tipo


INTEGER que poder ser utilizada para qualquer finalidade.
Neste exemplo, ela funciona como um contador e economizamos a
declarao de uma varivel para isso.
E para finalizar, vamos efetuar a codificao do boto

MeGAZINE

Figura 9 QuickReport

23

Delphi
Estando tudo configurado, vamos efetuar a codificao para
chamada e apresentao do Preview com a imagem de fundo. Na
listagem 13 apresentamos o procedimento que ser responsvel em
pintar a imagem no fundo do QuickReport.
procedure ImprimeBitmap(Cnv: TCanvas; Bitmap:
TBitmap; R: TRect);
var
Info: PBitmapInfo;
InfoSize: DWORD;
Image: Pointer;
ImageSize: DWORD;
begin
with Bitmap do
begin
GetDIBSizes(Handle, InfoSize, ImageSize);
GetMem(Info, InfoSize);
try
GetMem(Image, ImageSize);
try
GetDIB(Handle, Palette, Info^,
Image^);
with Info^.bmiHeader do
StretchDIBits(Cnv.Handle, R.Left,
R.Top, R.Right - R.Left,
R.Bottom - R.Top, 0, 0, biWidth,
biHeight, Image, Info^,
DIB_RGB_COLORS, SRCAND);
finally
FreeMem(Image, ImageSize);
end;
finally
FreeMem(Info, InfoSize);
end;
end;
end;

{
AfterPrint do rodap
Chamar a rotina que ir imprimir a imagem no
fundo do QReport.
}
procedure
TForm1.PageFooterBand1AfterPrint(Sender:
TQRCustomBand;
BandPrinted: Boolean);
var
M: TBitmap;
R: TRect;
X, Y: integer;
begin
M := TBitmap.Create;
try
M.LoadFromFile(pato.bmp);
with QuickRep1.QRPrinter do
begin
Y := YPos(PaperLengthValue) div 6;
X := XPos(PaperWidthValue) div 4;
R := Rect(X, 2 * Y, 3 * X, 4 * Y);
ImprimeBitmap(Canvas, M, R);
end;
finally
M.Free;
end;
end;
Listagem 14 Evento AfterPrint
Verifique que carregamos uma imagem em disco, contudo,
esta imagem poderia estar em um componente Image ou arquivo
de recursos. Outro aspecto relevante, que passado o objeto
Canvas a partir do objeto QRPrinter implcito no QuickReport.
Para finalizar, vamos efetuar a chamada do relatrio no
evento OnClick do boto (listagem 15).

Listagem 13 Procedimento para pintar a imagem no QR


O procedimento ImprimeBitmap recebe como parmetro um
objeto TCanvas que indica onde a imagem dever ser
apresentada, um objeto TBitmap que ir conter a imagem ser
apresentada e um objeto TRect que indica a rea onde a imagem
dever ser apresentada. (Mais informaes sobre a manipulao
de imagens via Delphi podero ser encontradas no artigo:
Desenhos e Bitmaps publicado em nossa revista de Outubro/
2000, tambm disponvel em nosso site, www.theclub.com.br)
Estando o procedimento definido, iremos efetuar sua
chamada no evento AfterPrint da banda de rodap
(rbPageFooter), acompanhe a listagem 14.

24

procedure TForm1.Button1Click(Sender:
TObject);
begin
Button1.Enabled := false;
try
QuickRep1.Preview;
finally
Button1.Enabled := true;
end;
end;

MeGAZINE

Listagem 15 OnClick.

Delphi
Ao chamar o preview do relatrio, o mesmo dever conter
uma imagem de fundo assim como demonstra a figura 10.

Figura 10 Fragmento do Preview.

4. Imprimindo Etiquetas Lado a Lado


O QuickReport possui mecanismo para impresso de dados
em formato de colunas bastando para isso configurar a
propriedade Page | Columns, contudo, quando utilizamos este
artifcio ele faz uma impresso vertical, ou seja, preenche a
primeira coluna at o final, depois para a segunda coluna at o
final e assim sucessivamente, o que no pode ser uma boa
alternativa quando trabalhamos com formulrios de etiquetas e
no vamos preench-lo totalmente.
Este exemplo ir demonstrar como efetuar uma impresso
horizontal, ou seja, iremos trabalhar com trs colunas as quais
sero preenchidas linha a linha. Dessa forma, se tivermos 9
registros em nossa tabela, por exemplo, a impresso ir ocupar as
3 colunas x 3 linhas de etiquetas, podendo cortar o formulrio e
utiliz-lo novamente para uma impresso posterior.s
Para comear, crie um novo projeto no Delphi e adicione os
seguintes componentes: uma TTable/BDE (Name: tbCustomer,
DatabaseName: DBDemos, TableName: Customer); um
DataSource (Name: dsCustomer, DataSet: tbCustomer); um
DBGrid (DataSource: dsCustomer); um BitBtn; um QuickReport
(Name: QR_LadoALado) e em cima deste QuickReport um
QRBand (BandType: rbDetail) e em cima deste QRBand 3
componentes QRMemo ajustando a propriedade AutoSize para
False e ajustando sua altura de forma a comportar as
informaes que iremos adicionar na etiqueta (Nome, endereo,
cidade, etc...) e sua largura de forma a suprir a largura da
etiqueta, lembrando que posicionaremos um QRMemo ao lado do
outro, veja a figura 11.
Mais uma vez iremos efetuar o controle do ponteiro do
DataSet a mo e por isso a propriedade DataSet do QuickReport
dever ficar em branco.

Codificando nosso relatrio


Basicamente, todo o cdigo ficar concentrado no evento
BeforePrint da banda detalhe (rbDetail) conforme apresenta a
listagem 15.
procedure TForm1.
DetailBand1BeforePrint
(Sender: TQRCustomBand;
var PrintBand: Boolean);
var
i: Integer;
Memo: TQRMemo;
begin
for i := 1 to 3 do
begin
Memo := TQRMemo(FindComponent
(QRMemo+IntToStr(i)));
with Memo.Lines do
begin
Clear;
if not (tbCustomer.EOF) then
begin
Add(tbCustomerCompany.AsString);
Add(tbCustomerAddr1.AsString);
Add(tbCustomerAddr2.AsString);
Add(tbCustomerCity.AsString++tbCustomerState.AsString);
Add(tbCustomerZip.AsString);
end;
end;
tbCustomer.Next;
end;
end;
Listagem 15 BeforePrint da banda detalhe.
Explicando o evento BeforePrint: Para no necessitarmos
repetir o mesmo cdigo trs vezes (pois so 3 QRMemos)
executamos um lao FOR para acessar o componente, efetuando
a pesquisa pelo nome e retornando o objeto TQRMemo. Sempre
antes de adicionarmos qualquer informao iremos chamar o
mtodo Clear do QRMemo para limpar qualquer informao que
exista no mesmo. Prosseguindo, verificamos se a tabela
tbCustomer no atingiu final de arquivo e adicionamos os
campos que desejamos mostrar em cada linha do QRMemo e
Figura 11
QuickReport

MeGAZINE

25

Delphi
ainda dentro deste lao FOR, executamos um Next para mover
para o prximo registro.
E para finalizar a codificao, vamos programar o evento
BeforePrint e OnNeedData do QuickReport e a chamada do
relatrio no evento OnClick do boto, acompanhe a listagem 16.
procedure TForm1.QR_LadoALadoNeedData(Sender:
TObject;
var MoreData: Boolean);
begin
{ Gera mais uma linha enquanto no for
final de arquivo }
MoreData := not (tbCustomer.EOF);
end;
procedure TForm1.btnVisualizarClick(Sender:
TObject);
begin
QR_LadoALado.Preview;
end;
procedure
TForm1.QR_LadoALadoBeforePrint(Sender:
TCustomQuickRep;
var PrintReport: Boolean);
begin
tbCustomer.First;
end;
Listagem 16 Finalizando a codificao
Estando tudo OK, compile e execute a aplicao e o resultado
dever ser parecido com o fragmento apresentado na imagem 12.

5. Imprimindo Arquivo Texto


Com base nas dicas anteriores voc j deve ter notado que
podemos utilizar o QuickReport para imprimir utilizando
praticamente qualquer fonte de dados, sendo esta vinda de um
DataSet, de um Memo ou mesmo de um arquivo texto existente

em disco e exatamente isso que iremos demonstrar nesta dica.


Ento, crie um novo projeto Delphi e nele adicione um
componente Edit (Name: EdArquivo); um SpeedButton (Name:
sbtnProcurar); um OpenDialog (aba Dialogs, Name: dlgTexto);
um Button (Name: btnPreview); um QuickReport (Name:
QR_ImpTexto) e sobre o QuickReport um QRBand (BandType:
rbDetail) e sobre esta QRBand um QRLabel (Name: QRTexto,
AutoSize: False) e ajuste sua largura para a mesma largura da
banda detalhe. A figura 13 sugere o layout para este formulrio.

Figura 13 Layout sugerido

Codificando o relatrio
A idia aqui ser carregar o arquivo texto em um objeto do
tipo TStringList e depois ir lendo linha a linha este TStrings e
transferindo o contedo da linha ao QRLabel. Assim sendo,
detalhe uma varivel chamada Texto abaixo da sesso var de
nossa unit, veja a listagem 17.
var
Form1: TForm1;
Texto: TStringList;
implementation
{$R *.DFM}
Listagem 17 declarao do TStringList.
Prosseguindo, vamos efetuar a codificao do sbtnProcurar o
qual ter como finalidade abrir uma caixa de dilogo para que o
usurio possa escolher o arquivo ser impresso e atribuir seu
caminho/nome ao Edit, veja a listagem 18.
procedure TForm1.sbtnProcurarClick
(Sender: TObject);
begin
if dlgTexto.Execute then
EdArquivo.Text :=
dlgTexto.FileName;
end;
Listagem 18 sbtnProcurar.
O prximo passo ser codificar o boto btnPreview
que ir efetuar a carga do arquivo texto e a chamada do
nosso relatrio, acompanhe a listagem 19.

Figura 12 Parte do preview

26

MeGAZINE

Delphi
procedure TForm1.btnPreviewClick(Sender:
TObject);
begin
if FileExists(EdArquivo.Text) then
begin
Texto := TStringList.Create;
try
Texto.LoadFromFile(EdArquivo.Text);
QR_ImpTexto.Tag := 0;
QR_ImpTexto.Preview;
finally
Texto.Free;
end;
end
else
raise Exception.Create(Selecione um
arquivo!);
end;

var PrintBand: Boolean);


begin
QRTexto.Caption := Texto[QR_ImpTexto.Tag];
end;
procedure
TForm1.DetailBand1AfterPrint(Sender:
TQRCustomBand;
BandPrinted: Boolean);
begin
QR_ImpTexto.Tag := QR_ImpTexto.Tag + 1;
end;
procedure TForm1.QuickRep1BeforePrint(Sender:
TQuickRep;
var PrintReport: Boolean);
begin
QR_ImpTexto.Tag := 0;
end;
Listagem 20 Eventos.

Listagem 19 OnClick btnPreview.


No evento OnClick do btnPreview, primeiro confirmamos a
existncia do arquivo anteriormente selecionado, depois
instanciamos o objeto TStringList e carregamos o arquivo no
mesmo. Novamente iremos utilizar a propriedade TAG do
QuickReport a qual ser nosso contador de linhas impressas,
iniciando-a em zero e finalizando, chamamos o preview do
QuickReport.
At este ponto, apenas carregamos o arquivo texto no objeto
TStringList, contudo, necessitamos ir lendo linha a linha e
transferindo seu contedo ao QRLabel existente em nossa banda
detalhe. Isso ser feito no evento BeforePrint da prpria banda
detalhe. Como estamos efetuando a impresso linha a linha, no
evento AfterPrint da banda detalhe iremos incrementar nosso
contador (propriedade TAG do QuickReport) e no evento
BeforePrint do QuickReport iremos zerar nosso contador (isso
necessrio, pois ao clicar em imprimir o relatrio ser processado
novamente e o contador deve estar no incio), acompanhe estes
eventos na listagem 20.
procedure TForm1.QR_ImpTextoNeedData(Sender:
TObject; var MoreData: Boolean);
begin
MoreData := (QR_ImpTexto.Tag <
Texto.Count);
end;
procedure
TForm1.DetailBand1BeforePrint(Sender:
TQRCustomBand;

MeGAZINE

Com isso conclumos nosso relatrio de impresso de arquivo


texto, compile e rode o exemplo e o arquivo texto escolhido dever
aparecer no preview.

Concluso
A partir do Delphi 7 o QuickReport deixou de ser distribudo
como ferramenta oficial de relatrios no Delphi, sendo substitudo
pelo Rave Report. Contudo, como mencionamos no incio deste
artigo, o QuickReport ainda um dos geradores de relatrios
mais utilizados na comunidade Delphi. Procurei demonstrar aqui
algumas tcnicas que possibilitam explorar muitas
funcionalidades do QuickReport permitindo a voc utiliz-lo em
situaes que aparentemente teramos que recorrer outros
artifcios, como exemplo o TPrinter, podendo dessa forma seguir
uma padronizao em seus relatrios.
Vale ressaltar que o fabricante do QuickReport lanou
recentemente a verso 4.0 que d suporte at o Delphi 2005 e,
dessa forma, se voc necessitar converter suas aplicaes para o
Delphi 2005 e no pretendo migrar para outro gerador de
relatrios, poder adquirir o QuickReport juntamente ao
fabricante, lembrando que ele no mais gratuito.

Forte abrao e sucesso todos.

Download
Os exemplos apresentados neste artigo esto disponveis para
download no endereo:
http://www.theclub.com.br/revista/download/QREspecial.zip

27

Perguntas & Respostas

Pergunta: Ao tentar compilar um programa exemplo


ASP.NET, o Delphi 2005 traz a seguinte mensagem: Unable to
start debugging on the web server. Unable to attach to ASP.NET
worker process (typically aspnet_wp.exe or w3wp.exe). Como
resolver este problema?

begin
Inc(Result);
N := N.Parent;
end;
end;

Resposta: Unable to attach to ASP.NET worker process


(typically aspnet_ wp.exe or w3wp.exe)

procedure TWinForm.Button1_Click(sender:
System.Object; e: System.EventArgs);
begin
MessageBox.Show(
Level(TreeView1.SelectedNode).ToString );
end;

Caso voc instale o IIS aps a instalao do .Net Framework,


e tente rodar uma aplicao Asp.Net, ir receber o erro acima, e
para solucionar, basta executar o seguinte comando:
c:\windows\ microsoft.net\framework\v1.1.4322\
aspnet_regiis.exe -i

Dvida enviada por Wisys Produtos Inteligentes Ltda, Rio de


Janeiro/RJ.

http://support.microsoft.com/default.aspx?scid=kb;ENUS;q306005
Dvida enviada por Wagner Araujo Mesquita, Franca/SP.

Pergunta: Gostaria de saber se a propriedade Level do


TTreeNode do Delphi 7 possui algum correspondente no TreeNode
do Delphi 2005 (Windows Forms).
Resposta: No encontramos nenhum mtodo que
retornasse esta informao, contudo, simples ser
implementado, confira:
function Level(N: TreeNode): Integer;
begin
Result := 0;
while (N.Parent <> nil) do

28

Pergunta: Aps deletar um registro no ClientDataSet


chamando o mtodo delete, se eu fechar e abrir a aplicao o
registro aparece novamente.
O que pode estar errado?
Resposta: Quando voc apaga um registro via mtodo
delete do ClientDataSet, voc apenas esta apagando no cache e
para que a instruo de delete seja efetivada no banco, chame o
mtodo ApplyUpdates(0) no evento AfterDelete, por exemplo.
Dvida enviada por Kleyton Smentkoski, Santo Antonio da
Platina/PR.

Pergunta: Existe alguma possibilidade do Delphi abrir um


determinado documento do Word, modificar algumas variveis e
exibir em tela apenas para impresso?

MeGAZINE

Perguntas & Respostas


Resposta: Isso possvel utilizando programao OLE
atravs dos componentes da palheta Servers. Em nossa revista
de Fevereiro/2000 publicamos um artigo a este respeito. Caso no
possua a revista poder acessar em nosso site,
www.theclub.com.br.
Dvida enviada por Ricardo Cerqueira, Caruaru/PE.

Pergunta: Gostaria de uma rotina que me retornasse as


pastas compartilhadas de todas as mquinas na rede, como devo
proceder?
Resposta: Existem APIs do Windows que possibilitam obter
estas informaes, acompanhe o exemplo a seguir:
{
Procedure que ir percorrer as mquinas da
rede e retornar compartilhamento
}
procedure GetNetworkedDrives
( strings: TStrings);
procedure EnumNetworkDrives
( pnr : PNetResource);
var
hEnum: THandle;
i, enumRes, count, BufferSize: DWORD;
buffer: pointer;
begin
BufferSize := $4000; { buffer de 16kb }
buffer := nil; { para garantir alocao
de memria.}
if WNetOpenEnum(RESOURCE_GLOBALNET,
RESOURCETYPE_DISK, 0, pnr, hEnum) =
ERROR_SUCCESS then
try
GetMem(buffer, BufferSize);
while true do
begin
count := dword(-1); { pega todos os
tens possveis.}
enumRes := WNetEnumResource
(hEnum, count, buffer, BufferSize);
{caso ocorra algum problema,
cancela.}
if (enumRes <> ERROR_SUCCESS) then
break;
pnr := buffer; { reutiliza o

MeGAZINE

ponteiro. }
for i := 1 to count do
begin
if (pnr.dwDisplayType =
RESOURCEDISPLAYTYPE_DOMAIN or
RESOURCEDISPLAYTYPE_SERVER)
and
(pnr.dwType = RESOURCETYPE_DISK)
then
strings.Add(pnr.lpRemoteName);
{ chamada recursiva da funo. }
if (pnr.dwUsage and
RESOURCEUSAGE_CONTAINER) > 0 then
EnumNetworkDrives(pnr);
inc(longint(pnr),sizeof(TNetResource));
end;
end;
finally
FreeMem(buffer);
WNetCloseEnum(hEnum);
end;
end;
begin
if strings = nil then
exit;
EnumNetworkDrives(nil);
end;
Para utilizar a procedure, adicione um componente Button e
um componente ListBox e faa a chamada assim:
procedure TForm1.Button1Click
(Sender: TObject);
begin
GetNetworkedDrives(ListBox1.Items);
end;
Dvida enviada por Vagner Martins, Rafard/SP.

Pergunta: Gostaria de mostrar uma mensagem na tela por


N segundos e que a mesma fechasse automaticamente aps o
tempo pr-determinado. Isso possvel?
Resposta: Sim, existe uma API do Windows chamada
MessageBoxTimeOut que tem esta finalidade. Para utiliz-la,
crie uma nova unit e salve como MsgBoxTimeOut e nela efetue
as seguintes declaraes:

29

Perguntas & Respostas


MessageBoxTimeout(Application.Handle, Ir
fechar em 2 segundos,
MessageBoxTimeout Test, iFlags, 0,
2000);

unit MsgBoxTimeOut;
interface
uses Windows;

iFlags := MB_YESNO or MB_SETFOREGROUND or


MB_SYSTEMMODAL or
MB_ICONINFORMATION;

const
MB_TIMEDOUT = 32000;

{ Chamada com boto Sim/No }


iRet :=
MessageBoxTimeout(Application.Handle, Ir
fechar em 5 segundos,
MessageBoxTimeout Test, iFlags, 0,
5000);

function MessageBoxTimeOut(hWnd: HWND;


lpText: PChar; lpCaption: PChar;
uType: UINT; wLanguageId: WORD;
dwMilliseconds: DWORD): Integer; stdcall;
function MessageBoxTimeOutA(hWnd: HWND;
lpText: PChar; lpCaption: PChar;
uType: UINT; wLanguageId: WORD;
dwMilliseconds: DWORD): Integer; stdcall;

case iRet of
IDYES: { Boto sim. }
ShowMessage(Sim);
IDNO: { boto no }
ShowMessage(No);
MB_TIMEDOUT: { TimeOut }
ShowMessage(Voc no selecionou Sim/
No, tempo esgotado!);
end;
end;

function MessageBoxTimeOutW(hWnd: HWND;


lpText: PWideChar; lpCaption: PWideChar;
uType: UINT; wLanguageId: WORD;
dwMilliseconds: DWORD): Integer; stdcall;
implementation
function MessageBoxTimeOut; external user32
name MessageBoxTimeoutA;
function MessageBoxTimeOutA; external user32
name MessageBoxTimeoutA;
function MessageBoxTimeOutW; external user32
name MessageBoxTimeoutW;

Dvida enviada por Almir Rodrigues Borges, Araatuba/SP.

Pergunta: Gostaria de saber se vocs tm algum


componente boto que ao clicar tenha vrias opes, como clicar
em um menu, de preferncia, que seja descendente da classe
TBitBtn ou TSpeedButton.

end.
Pronto, agora bastar declarar esta unit onde
desejar chamar a funo MessageBoxTimeOut,
veja um exemplo a seguir:
procedure TForm1.Button1Click(Sender:
TObject);
var
iRet: Integer;
iFlags: Integer;
begin
iFlags := MB_OK or MB_SETFOREGROUND or
MB_SYSTEMMODAL or MB_ICONINFORMATION;

Resposta: Voc poder implementar esta funcionalidade


utilizando prprio BitBtn e um componente PopupMenu,
abrindo-o exatamente abaixo do boto que recebeu click. Para
isso, adicione um componente PopUpMenu e nele adicione as
opes que desejar. Aps isso, adicione um BitBtn e no evento
OnClick do mesmo codifique:
var
P: TPoint;
begin
P :=
BitBtn1.ClientToScreen(BitBtn1.ClientRect.BottomRight);
PopupMenu1.Popup(P.x-BitBtn1.Width, P.y);
end;

{ Chama com boto OK }


iRet :=

Dvida enviada por Maicon Csar Loffi, Laurentino/SC.

30

MeGAZINE

Você também pode gostar