explorando quickreport0505.pdf

32

Upload: carlosaccorreia

Post on 05-Feb-2016

45 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: Explorando QuickReport0505.pdf
Page 2: Explorando QuickReport0505.pdf
Page 3: Explorando QuickReport0505.pdf

MeGAZINE 3

EDITORIAL

Editorial

Celso Jefferson PaganelliPresidente - The Club

Editorial ............................................................................ 03Gestão de riscos em projetos de software .................... 04Usando o componente TWebBrowser .......................... 08Criando um arquivo PDF a partir do Delphi .................. 12Explorando o QuickReport ............................................. 16Perguntas & Respostas.................................................. 28

THE CLUBAv. Celso Ferreira da Silva, 190

Jd. Europa - Avaré - SP - CEP 18.707-150Informações: (0xx14) 3732-3689

Suporte: (0xx14) 3733-1588 - Fax: (0xx14) 3732-0987

Internethttp://www.theclub.com.br

Cadastro: [email protected]: [email protected]

Informações: [email protected]

DúvidasCorrespondência ou fax com dúvidas devem ser

enviados ao - THE CLUB, indicando "Suporte".

OpiniãoSe você quer dar a sua opinião sobre o clube em

geral, mande a sua correspondência para a seção

"Tire sua dúvida".

ReproduçãoA utilização, reprodução, apropriação,

armazenamento em banco de dados, sob qualquerforma ou meio, de textos, fotos e outras criações

intelectuais em cada publicação da Revista“The Club” são terminantemente proibidos sem

autorização escrita dos titulares dos direitosautorais.

Copyright© The Club® 2005

Impressão e acabamento:GRAFILAR

Tel.: (0xx14) 3841-2587 - Fax: (0xx14) 3841-3346Rua Cel. Amando Simôes, 779 - Cep 18.650-000

São Manuel - SPTiragem: 5.000 exemplares

Diretor - Presidente

Celso Jefferson M. Paganelli

Diretor TécnicoMauro Sant’Anna

Colaboradores

Emerson Facunte, Marcelo Nogueira

Delphi é marca registrada da Borland International, as

demais marcas citadas são registradas pelos seus

respectivos proprietários.

Olá amigos,

Aqui estamos com mais uma edição da The Club Megazine trazendo até vocêmuita informação para facilitar seu dia-a-dia.

Começamos com um excelente artigo do nosso amigo Marcelo Nogueira, onde eletrata sobre a gestão de riscos em projetos de software, não deixe de conferir.

Continuando, nosso consultor Claudinei Rodrigues demonstra em seu artigovárias dicas acerca do componente TWebBrowser o qual encapsula o navegadorMicrosoft Internet Explorer permitindo ao programador adicionar ótimos recursos àsua aplicação.

Na seqüência, nosso consultor André Colavite apresenta uma solução para criararquivos PDFs via Delphi utilizando um componente gratuito o qual também pode serutilizado em conjunto com o QuickReport, e dessa forma exportar seus relatórios paraformato PDF.

Ainda falando em QuickReport, nosso consultor Alessandro Ferreira preparou umartigo especial sobre o QuickReport onde demonstra como criar relatórios não triviaiscom este gerador que ainda é bastante utilizado meio a comunidade Delphi.

E finalizando esta edição, trazemos nossa sessão Perguntas & Respostas ondeapresentamos algumas das solicitações feitas aos nossos consultores neste mês.

Abraço e sucesso à todos,

Page 4: Explorando QuickReport0505.pdf

MeGAZINE4

Delphi

Resumo - As empresas de desenvolvimento de softwarepossuem características especiais, diante da demanda a elassubmetidas. Com a realização de projetos sobre pressão de prazose custos, processos fundamentais são ignorados como porexemplo à gestão de riscos. A falta de foco nos riscos dos projetosde software, bem como a determinação de seu grau de exposição,pode causar transtornos e prejuízos ao projeto. A confiabilidade doproduto de software é influenciada pelo seu processo dedesenvolvimento. Um processo repetitivo, orientado no sentido demonitorar e controlar os riscos, permite que o softwaredesenvolvido, tenha confiabilidade. A não adoção dessas práticasfundamentais da Engenharia de Software por falta de cultura oupor resistência a mudanças, levam projetos de suma relevânciaao insucesso e aumentando os casos de fracassos nodesenvolvimento de software.

Palavras-chave: Desenvolvimento de software, Riscos,Engenharia de Software.

Introdução aos RiscosSegundo Robert Charette [1], a definição de risco é:“Em primeiro lugar, risco afeta acontecimentos futuros.

Presente e passado não preocupam, pois o que colhemos hoje jáfoi semeado por nossas ações anteriores. A questão é mudandonossas ações hoje, podemos criar oportunidade para umasituação diferente e possivelmente melhor para nós amanhã?Isso significa, em segundo lugar, que risco envolve mudança,como por exemplo, mudança de pensamento, opinião, ações oulugares..., e em terceiro lugar, o risco envolve escolha e aincerteza que a própria escolha envolve. Assim, paradoxalmente,o risco, como a morte e os impostos, é uma das poucas certezas davida”.

Quando o risco é considerado no contexto da Engenharia deSoftware, as três fundamentações conceituais de Charette estãosempre em evidência:

1. O futuro é nossa preocupação: Que riscos podem causar oinsucesso do projeto de software?

2. A mudança é nossa preocupação: Como as mudanças derequisitos do cliente, afetam a pontualidade e o sucesso geral?

3. Devemos cuidar das escolhas: Que métodos e ferramentasdevemos usar, quantas pessoas devem ser envolvidas, quantaênfase em qualidade é suficiente?

Peter Drucker disse certa vez, “já que é fútil tentar eliminarriscos e questionável tentar minimizá-los, o essencial é que osriscos considerados sejam os certos”. Antes que possamosidentificar os “riscos certos”, que acontecerão durante um projetode software, é importante identificar todos os demais que sãoóbvios, tanto para gerentes quanto para profissionais.

Segundo Higuera [1], “um risco 100% provável é umarestrição ao projeto de software”.

Um grande volume de dados publicados aponta para os riscosque ocorrem os projetos de software executados se a utilização deprocessos adequados [4]. Um levantamento publicado de umabase de dados de 4.000 projetos, constatou a ocorrência freqüentedos seguintes problemas:

§ 70% dos projetos de grandes aplicativos sofrem instabilidadedos requisitos. Os requisitos crescem tipicamente cerca de 1% aomês, atingindo níveis de mais de 25% de inchaço ao final doprojeto.

§ Pelo menos 50% dos projetos são executados com níveis deprodutividade abaixo do normal.

§ Pelo menos 25% dos softwares de prateleira e 50% dosprodutos feitos por encomenda apresentam níveis de defeitossuperiores ao razoável.

§ Produtos feitos sob pressão de prazos podem quadruplicar onúmero de defeitos.

Por Marcelo Nogueira

Gestão de riscos em projetos de softwareGestão de riscos em projetos de softwareGestão de riscos em projetos de softwareGestão de riscos em projetos de softwareGestão de riscos em projetos de softwareGestão de riscos em projetos de softwareGestão de riscos em projetos de softwareGestão de riscos em projetos de softwareGestão de riscos em projetos de softwareGestão de riscos em projetos de software

Page 5: Explorando QuickReport0505.pdf

MeGAZINE 5

Delphi

§ Pelo menos 50% dos grandes projetos de software estouramseu orçamento e seu prazo.

§ 2/3 dos projetos de software muito grandes são cancelados

Esquema deClassificação de

RiscosDescrição

Alto

A correção de irregularidadesou a implementação demelhorias apresentam risco altode impacto negativo no projeto.

Médio

A correção de irregularidadesou a implementação demelhorias apresentam riscomédio de impacto negativo noprojeto.

Baixo

A correção de irregularidadesou a implementação demelhorias apresentam riscobaixo de impacto negativo noprojeto.

Zero

A correção de irregularidadesou a implementação demelhorias apresentam riscodesprezível de impacto negativono projeto.

Tabela 1Esquema de classificação de riscos - IEEE [3].

Figura 1 - Taxonomia da engenharia de riscos.

antes do final.§ Os usuários não ficam satisfeitos com 25% dos produtos

comerciais para PC, 30% dos produtos comerciais paramainframe e 40% dos produtos feitos por encomenda.

§ Tipicamente, 50% do patrimônio de software das empresasnão são usados.

§ Atritos entre a área de tecnologia da informação e a altagerência ocorrem em mais de 30% das organizações.

§ Atritos com clientes ocorrem, no desenvolvimento deaplicativos, em 50% dos contratos por administração e 65% doscontratos por empreitada.

O risco de projeto pode ser estimado qualitativamente. Oprincipal objetivo da análise de riscos é desenvolver um conjuntode estratégias de prevenção de riscos.

Gestão de RiscosGestão de Riscos é composta por atividades coordenadas para

direcionar uma organização em relação ao risco. A gestão deriscos, geralmente inclui avaliação, tratamento, aceitação ecomunicação de riscos.

A gestão de riscos envolve cinco atividades principais:Planejamento, controle, monitoração, direcionamento erecrutamento [5].

A gestão de riscos é particularmente importante para projetosde software, devido às incertezas inerentes que a maioria dos

Page 6: Explorando QuickReport0505.pdf

MeGAZINE6

Delphi

Tabela 2Exemplo de Estimativa de Riscos

projetos enfrenta.

De modo simplificado, podemos pensar no risco como umaprobabilidade de que alguma circunstância adversa realmentevenha ocorrer. Os riscos podem ameaçar o projeto, o software queestá sendo desenvolvido ou a organização. Essas categorias deriscos podem ser definidas como se segue:

1. Riscos relacionados ao Projeto: São os riscos que afetam aprogramação ou os recursos do projeto.

2. Riscos relacionados ao Produto: São os riscos que afetam aqualidade ou o desempenho do software que está emdesenvolvimento.

3. Riscos para os negócios: São os riscos que afetam aorganização que está desenvolvendo ou adquirindo o software.

O processo de gestão de riscos envolve vários estágios:

1. Identificação dos riscos: São identificados os possíveis riscosde projeto, produto e negócios.

2. Análise de riscos: São avaliadas as possibilidades e asconseqüências da ocorrência desses riscos.

3. Planejamento de riscos: São traçados planos paraenfrentar os riscos, seja evitando-os, seja minimizando seusefeitos sobre o projeto.

4. Monitoramento de riscos: O Risco é constantementeavaliado e os planos para a diminuição dos riscos revisados, àmedida que mais informações sobre eles se tornam disponíveis.

Segundo Pádua [4], os riscos dever ser estimados e

monitorados:

A estimativa de riscos é uma atividade muito importante epouco praticada; um bom planejamento não apenas o que deveacontecer se tudo correr bem, mas também o que pode corrermal, quais as conseqüências dos problemas e o que pode ser feitopara combatê-los. Entre os fatores de riscos que devem serconsiderados podem ser incluídos:

§ Riscos legais;§ Riscos Tecnológicos;§ Riscos devidos ao tamanho e à complexidade do produto;§ Riscos relativos a pessoal;§ Riscos relativos à aceitação pelos usuários;

Sommerville, descreve os tipos de riscos que podem afetar oprojeto e do ambiente organizacional em que o software estásendo desenvolvido. [3]

Contudo, muitos riscos são considerados universais e elesenvolvem as seguintes áreas:

§ Tecnologia§ Pessoal§ Organizacional§ Ferramentas§ Requisitos

Prioridade Risco Gravidade Probabilidadede ocorrência Impacto Previsto Contramedidas

Previstas

1 Falta de Equipamentospara testes beta.

Alta Média Impossibilidade derealizar os testes beta.

Cobrar providência docliente.

2 Defeitos na Engenharia deSoftware

Média Média Vários dias de atraso poralteração de requisitos.

Incluir na primeira liberaçãoos requisitos maiscomplexos.

3 Falta de Usuáriosresponsáveis por testes.

Alta Baixa Impossibilidade derealizar os testes beta.

Cobrar providência docliente.

4 Falta de inventário dasmercadorias para ocadastramento

Alta Baixa Impossibilidade derealizar os testes beta.

Cobrar providência docliente.

5 Falta de povoamento inicialdas bases de dados.

Alta Baixa Impossibilidade derealizar os testes beta.

Cobrar providência docliente.

6 Mudança de Legislação Média Baixa Pode ser necessáriorefazer partes referentes ànota fiscal.

Isolar as classes e interfacessusceptíveis de mudança delegislação.

Page 7: Explorando QuickReport0505.pdf

MeGAZINE 7

Delphi

§ Estimativa

A estimativa dos riscos compreende as seguintes tarefas:

§ Identificação dos riscos possíveis em relação ao projeto;§ Análise desses riscos, avaliando-lhes a probabilidade e o

provável impacto;§ Previsão de contramedidas curativas ou preventivas;§ Priorização dos riscos, organizando-os de acordo com a

probabilidade e o impacto.

Os riscos não permanecem constantes durante a execução deum projeto. Alguns desaparecem, outros novos surgem, e outrossofrem alterações de probabilidade e impacto, mudando portantoa prioridade. Um relatório de acompanhamento do projetojuntamente com uma tabela atualizada para monitoração dosriscos. A tabela de estimativa deve ser repetida e atualizada pararefletir as modificações ocorridas, até que os riscos sejamconcretizados ou completamente eliminados [4]

As questões a seguir foram derivadas de dados de riscosobtidos por levantamento feito com gerentes de projeto desoftware experientes, em diferentes partes do mundo [1].

As questões estão ordenadas por sua importância relativa emrelação ao sucesso de um projeto:

1. A alta administração do software e do cliente empenhou-seformalmente em apoiar o projeto?

2. Os usuários finais estão entusiasticamente empenhadoscom relação ao projeto?

3. Os requisitos estão plenamente entendidos ?4. Os clientes envolveram-se totalmente na especificação dos

requisitos?5. Os usuários finais têm expectativas realistas ?6. O escopo do projeto é estável?7. A equipe de projeto tem a combinação de aptidões

adequadas?8. Os requisitos do projeto são estáveis?9. A equipe de projeto tem experiência com a tecnologia a ser

implementada?10. A quantidade de pessoal é adequada ao projeto?11. Todos os membros da equipe e usuários envolvidos no

projeto concordam com a importância do projeto e com osrequisitos do sistema?

Se qualquer dessas questões for respondida negativamente,os passos de atenuação, monitoração e gestão devem ser

instituídos imediatamente. O grau em que o projeto está em riscoé diretamente proporcional ao número de respostas negativas aessas questões.

Segundo PMBOK [6], existem ferramentas e técnicas paraidentificação de riscos. São elas:

· Listas de Verificação: Questões do produto, tecnologia epessoas envolvidas no projeto;

· Fluxogramas: Melhor compreensão das causas e efeitos dosriscos do projeto;

· Entrevistas: Entrevistas orientadas aos riscos comparticipação de várias partes envolvidas;

ConclusãoAqui foi possível verificar a importância da gestão de riscos

nos projetos de software. O Fracasso ou o sucesso estãodiretamente ligadas a essas variáveis e contudo serão objetos deestudo e análise para que possam ser monitoradas e controladosdurante os projetos de software.

A partir do estudo do “Estado da Arte”, podemos identificar osriscos e analisá-los diante do seu grau de ocorrência.

Para validar este processo utiliza-se o para-analisador,construído através da Lógica Paraconsistente.

Referências Bibliográficas

[1] PRESSMAN, ROGER S., Engenharia de Software, Rio deJaneiro, Ed. McGraw-Hill, 2002.

[2] REZENDE, DENIS ALCIDES, Engenharia de Software eSistemas de Informações, Rio de Janeiro, Ed. Brasport, 1999.

[3] SOMMERVILLE, IAN, Engenharia de Software, SãoPaulo, Ed. Pearson Education, 2003.

[4] FILHO, WILSON DE PÁDUA PAULA, Engenharia deSoftware, Rio de Janeiro, Ed. LTC, 2003.

[5] PETERS, JAMES F. et al. Engenharia de Software,Rio deJaneiro, Ed. Campus,2001.

[6]PMI, PMBOK, Project Management Institute, 2000.

Sobre o autorMarcelo Nogueira é Mestre em Engenharia de Produção com

ênfase em Gestão da Informação, bacharel em Análise de

Sistemas, Professor Universitário, Instrutor e

Desenvolvedor Delphi desde 1995, Membro fundador do

DUG-BR. e-mail: [email protected]

Page 8: Explorando QuickReport0505.pdf

MeGAZINE8

Delphi

Usando o componenteUsando o componenteUsando o componenteUsando o componenteUsando o componenteTWebBrowserTWebBrowserTWebBrowserTWebBrowserTWebBrowser

Usando o componenteUsando o componenteUsando o componenteUsando o componenteUsando o componenteTWebBrowserTWebBrowserTWebBrowserTWebBrowserTWebBrowser

Por Claudinei Rodrigues

Olá amigos.

Nos últimos dias alguns sócios têm entrado em contato com onosso suporte técnico solicitado informações sobre como utilizar ocomponente TWebBrowser que fica localizado na palhetaInternet. Sendo assim eu reuni algumas dicas beminteressantes, as quais você pode ver a seguir.

Usando o TWebBrowser para visualizar e imprimirdocumentos do Microsoft Word.

Através do componente TWebBrowser nós podemos utilizar oMicrosoft Word como uma ferramenta de impressão para a nossaaplicação.

Aqui está como você pode utilizar o TWebBrowser paracontrolar a tanto a visualização quanto a impressão dosdocumentos do Microsoft Word.

// Evento OnClick do componente Buttonprocedure TForm1.Button1Click(Sender:TObject);begin // Abre um documento do Word no componenteWebBrowser WebBrowser1.Navigate(‘C:\Meusdocumentos\Exemplo.doc’) ;end;

Como verificar se um documento mostrado noTWebBrowser está localizado no seu HD.

Se você precisa saber a localização de um documentomostrado no componente TWebBrowser, você irá precisar acessara propriedade Protocol. Veja abaixo como é a rotina:

// Função que irá localizar o arquivofunction 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 função// ProcuraDocprocedure TForm1.Button2Click(Sender:TObject);begin if ProcuraDoc(WebBrowser1) then ShowMessage(‘O documento está no drivelocal ou em sua rede.’) ;end;

Como localizar e destacar uma informação de umaWebPage mostrada no TWebBrowser.

Veja aqui como você pode localizar uma informação em umdocumento web através do componente TWebBrowser e quandoencontrá-lo, poder destacá-lo para que a visualização fique maisfácil. A função ProcuraTexto irá receber dois parâmetros. Oprimeiro é o próprio componente TWebBrowser e o segundoparâmetro é o texto a ser localizado. Ao executar a função você

Page 9: Explorando QuickReport0505.pdf

MeGAZINE 9

Delphi

notará que o texto que for localizado ficará com o fundo amarelo.Veja abaixo a nossa função ProcuraTexto e também como vocêpode utilizá-la.

// Esta função irá localizar e destacar otextoprocedure 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 ASIHTMLDocument2).body ASIHTMLBodyElement).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 função// ProcuraTextoprocedure TForm1.Button3Click(Sender:TObject);begin ProcuraTexto(WebBrowser1,’Template’) ;end;

Como salvar uma WebPage que está sendomostrada no componente TWebBrowser em umarquivo HTML em seu drive local

Aqui nós vamos mostrar como uma WebPage que está sendomostrada dentro do componente TWebBrowser pode ser salvacomo um arquivo .HTML no seu HD.

// Esta função tem a finalidade de salvar a // página exibida no componente TWebBrowser em// um arquivo .HTML no seu drive localprocedure Salva_Em_HTML(WB:TWebBrowser; const Arquivo : string);var

PersistStream: IPersistStreamInit; Stream: IStream; FileStream: TFileStream;begin if not Assigned(WB.Document) then begin ShowMessage

(‘Documento não foi encontrado!’); Exit; end; PersistStream := WB.Document asIPersistStreamInit; FileStream := TFileStream.Create

(Arquivo, fmCreate); try Stream := TStreamAdapter.

Create(FileStream, soReference) asIStream;

if Failed(PersistStream.Save(Stream, True)) then

ShowMessage(‘Não foi possível salvar oarquivo !’); finally FileStream.Free; end;end;// Aqui é o evento OnClick de um botão que// mostra como você deve utilizar esta funçãoprocedure TForm1.Button4Click(Sender:TObject);begin //Primeiro chame a página desejada WebBrowser1.Navigate

(‘http://www.theclub.com.br’); //Depois basta salvá-la Salva_Em_HTML(WebBrowser1,’c:\theclub.html’);end;

Para que este código funcione corretamente você devedeclarar a unit ActiveX.

Como chamar o FindDialog para localizar um textoem uma WebPage que está sendo mostrada nocomponente TWebBrowser.

Quando você está navegando na internet utilizando umnavegador como o Internet Explorer por exemplo, as vezes vocêquer localizar um texto. Daí você vai ao menu do InternetExplorer e clica em Editar | Localizar ou simplesmente digitaCTRL + F. Daí aparece uma janela de diálogo onde você digita oque quer pesquisar. Esta função que está sendo demonstrada a

Page 10: Explorando QuickReport0505.pdf

MeGAZINE10

Delphi

seguir faz a mesma coisa.

// Esta procedure irá chamar a tela// de dialogo onde você irá digitar// a informação 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 botão// que mostra como você deve utilizar// a função FindDialogprocedure TForm1.Button5Click(Sender:TObject);begin FindDialog(WebBrowser1) ;end;

Como ver o código fonte de uma WebPage que estásendo mostrada no componente TWebBrowser.

Quando você acessa uma Home Page através do InternetExplorer por exemplo, você pode clicar com o botão direito sobre apágina e selecionar o item Exibir código fonte e ver o código fonteutilizado naquela página.

Veja a seguir a rotina que podemos utilizar para obter estemesmo efeito.

// Esta procedure tem a finalidade de// mostrar o código fonte de uma home pageprocedure 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 botão// que mostra como você deve utilizar// a função Mostra_Codigo_Fonteprocedure TForm1.Button6Click(Sender:TObject);begin Mostra_Codigo_Fonte(WebBrowser1);end;

Como imprimir uma WebPage que está sendomostrada no componente TWebBrowser.

Veja a seguir várias formas de imprimir utilizando ocomponente TWebBrowser.

// Manda diretamente para a impressoraprocedure Imprime_Sem_Janela_Dialogo(WB:TWebBrowser) ;var vIn, vOut: OleVariant;begin

Page 11: Explorando QuickReport0505.pdf

MeGAZINE 11

Delphi

WB.ControlInterface.ExecWB(OLECMDID_PRINT, OLECMDEXECOPT_DONTPROMPTUSER, vIn, vOut) ;end;//Imprime depois de chamar a tela de diálogoprocedure Imprime_Com_Janela_Dialogo(WB:TWebBrowser) ;var vIn, vOut: OleVariant;begin WB.ControlInterface.ExecWB(OLECMDID_PRINT, OLECMDEXECOPT_PROMPTUSER, vIn, vOut) ;end;// Chama o previewprocedure Mostra_Preview(WB: TWebBrowser) ;var vIn, vOut: OleVariant;begin WB.ControlInterface.ExecWB(OLECMDID_PRINTPREVIEW, OLECMDEXECOPT_DONTPROMPTUSER, vIn, vOut) ;end;//Chama o Print Setupprocedure 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 umTWebBrowser

Veja abaixo como podemos desabilitar o menu de contexto,que é aquele que você clica com o botão direito do mouse.

// Esta é a função que desabilitafunction 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

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 função que desabilita// o Context Menuprocedure TForm1.FormCreate(Sender: TObject);begin MouseHook := SetWindowsHookEx(WH_MOUSE,MouseProc, 0, GetCurrentThreadId()) ;end;// Aqui é o OnDestroy do form onde// estamos habilidando novamente// o Context Menuprocedure TForm1.FormDestroy(Sender:TObject);begin if MouseHook <> 0 then UnHookWindowsHookEx(MouseHook) ;end;

ConclusãoEstas foram algumas dicas que temos disponíveis a respeito

do componente TWebBrowser. Se você tiver mais alguma dica equiser vê-la publicada em nossa revista, mande um e-mail [email protected] que teremos o maior prazer em publicá-las.

Um abraço a todos e até o próximo mês.

Sobre o autorClaudinei Rodrigues,

Consultor Técnico do The Club

[email protected]

Page 12: Explorando QuickReport0505.pdf

MeGAZINE12

Criando arquivo PDFCriando arquivo PDFCriando arquivo PDFCriando arquivo PDFCriando arquivo PDFa partir do Delphi.a partir do Delphi.a partir do Delphi.a partir do Delphi.a partir do Delphi.

Delphi

IntroduçãoNesta matéria iremos verificar como criar arquivos PDF a

partir do Delphi, esse tópico é bastante abordado pois é muitoimportante que nosso sistema possa exportar dados de umaforma segura e de fácil visualização.

Alguns geradores de relatórios já trazem embutidas essasparticularidades, mas em alguns casos não temos esses gerados adisposição ou a estrutura que iremos montar não se encaixa numgerador de relatório. Sendo assim, temos a possibilidade demontar o PDF via programação, incluindo assim as informaçõesconforme a necessidade.

Componente ExternoPara a criação do arquivo PDF utilizaremos um componente

externo e free chamado TNPDF. Esse componente é bastantesimples composto de apenas uma unit onde o PDF é gerado.

Junto com esse componente temos um outro componentetambém free chamando ZLIB, que será utilizado para fazer acompactação do arquivo PDF gerado.

Antes de iniciar o projeto de exemplo vamos baixar esses doiscomponentes, para isso acesse o seguinte link:

www.theclub.com.br/revista/download/tnpdf.zip

Descompacte o arquivo zip e poderá encontrar os seguintesarquivos:

TNPDF.PAS: Contem a programação do componente paragerar o PDF;

READ_ME.TXT: Contem algumas informações importantes;

PASZLIB.ZIP: Contém os arquivos do componente paracompactação do PDF. Descompacte esse arquivo junto com oarquivo TNPDF.PAS.

Observação:

Não iremos instalar o componente TNPDF no Delphi, poismais adiante ele será instalado junto com outro componente paraexportação a partir do QuickReport. Sendo assim para utilizá-lodeixaremos os arquivos .PAS no mesmo diretório onde o nossoprojeto será criado.

Criando um simples exemploCrie um novo projeto e coloque em seu form os seguintes

componentes:Button1, Image1, Memo1, Label1, SaveDialog1

No componente Memo1 carregue o conteúdo do arquivoreadme.txt e no arquivo Image1 carregue uma imagem deexemplo. Ao término o nosso form ficará parecido com a figura1.

Na seção implementation declare a unit TNPDF.

implementation uses tnpdf;

Em seguida criaremos uma procedure contendo as instruçõespara gerar o arquivo PDF:

procedure TForm1.Relat1(NomeArq: String);var PDF:TPrintPDF;begin

Criando arquivo PDFCriando arquivo PDFCriando arquivo PDFCriando arquivo PDFCriando arquivo PDFa partir do Delphi.a partir do Delphi.a partir do Delphi.a partir do Delphi.a partir do Delphi.

Page 13: Explorando QuickReport0505.pdf

MeGAZINE 13

Delphi

Figura 1:

{ Cria o componente TPrintPDF } PDF := TPrintPDF.Create(self); try { Configurar o título do documento } PDF.TITLE := Label1.Caption; { Usando o componente para compactação doarquivo } PDF.Compress := true; { Configurar o tamanho da página } PDF.PageWidth := 612; PDF.PageHeight := 792; { Indica o nome do arquivo a ser gerado } PDF.FileName := NomeArq; { Inicia a impressão } 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 }

PDF.LineWidth := 2; { Desenha um retângulo no PDF } PDF.DrawRectangle(12,12,600,780); { Configura a fonte a ser impressa. Essafonte é definida dentro do componente devido ao nome a ser utilizado naestrutura 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 maiorclube de programadores do Brasil’); { Configura a Fonte } PDF.Font.Name := poTimesRoman; PDF.Font.Size := 12; { Imprime o conteúdo de um memo } PDF.MemoOut(15,60, Memo1); { Adiciona nova página }

Page 14: Explorando QuickReport0505.pdf

MeGAZINE14

Delphi

PDF.NewPage; { Imprime um retângulo } PDF.DrawRectangle(12,12,600,780); { Imprime uma imagem } PDF.Draw(15,15,Image1); { Finaliza o documento } PDF.EndDoc; finally { Destroi o componente da memória } PDF.Free; end;end;

No evento onclick do botão coloque a instrução para chamar aprocedure:

procedure TForm1.Button1Click(Sender:TObject);begin if SaveDialog1.Execute then begin Relat1( SaveDialog1.FileName ); end;end;

Pronto agora podemos compilar esse projeto e executar, aoqual irá gerar o arquivo PDF normalmente.

Esse projeto de exemplo está disponível para downloadatravés 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, também externo e Freeware que permitirá apartir do QuickReport gerar o arquivo PDF.

Para gerar o PDF esse componente pega o Metafile que é aimagem do relatório gerada pelo Quickreport e transfere para ocomponente que faz a exportação, podendo através dessecomponente exportar o relatório para os formatos PDF, JPG,BMP, WMF e EMF.

Antes de iniciar-mos os trabalhos devemos baixar esse novocomponente através do seguinte link:

www.theclub.com.br/revista/download/expack12.zip

Observação:Esse componente ExportQR foi criado para trabalhar com o

QuickReport e com o FastReport, mas nesta versão que estoudisponibilizando no site do THE CLUB o componente estarátrabalhando somente com o quickreport. Caso alguém queirapegar a versão que também trabalha com o FastReportrecomendo que acesse o site do fabricante no seguinte link: http://usuarios.lycos.es/isma

A instalação desse componente é bastante simples, abra oarquivo ExPackD6.dpk (Delphi 6) ou ExPackD7.dpk (Delphi 7)através do delphi e em seguida compile e instale. Essecomponente já está trazendo os dois componentes utilizados noprimeiro exemplo, isso é, o componente TNPDV e o componentede compactação.

Após efetuar a instalação acesse o menu Tools, do Delphi, edepois a opção Environment Options. Selecione a aba Library edepois acesse o botão da Library path.

Na janela que será aberta indique o caminho onde estão osarquivos .pas do componente e depois clique em Add e em seguidaem Ok.

Agora estando com o componente instalado podemos colocá-lono form do nosso projeto que contem o relatório criado noQuickReport e depois através de um botão colocar a instrução queirá fazer a exportação. A instrução do botão para exportaçãoficará da seguinte forma:

procedure TMainForm.BtnExportQRClick(Sender:TObject);begin { Liga o componente do QuickReport aocomponente de exportação } EXQR.Report := Rep; { Faz a exportação } EXQR.ExportQR;end;

Este componente também nos permite exportar relatórios apartir do componente QRPreview que é o componente ao qualcriamos preview personalizado no QuickReport.

Para isso podemos colocar um botão no form de preview eneste botão colocar a seguinte instrução:

procedure TFPreviewQR.TBSaveClick(Sender:TObject);begin { Faz a ligação do QRPreview com ocomponente } EXQR.Preview := Preview; { Faz a exportação do relatório }

Page 15: Explorando QuickReport0505.pdf

MeGAZINE 15

Delphi

EXQR.ExportQRFromPreview;end;

Esses códigos acima podem ser encontrados no projeto deExemplo1 que acompanha o componente ExportQR.

Outros formatosA exportação dos relatórios para os demais formatos é

bastante simples também, veja abaixo as sintaxes utilizadas paracada tipo:

PDF com Alta Compressão: EXQR.ExportQRPDF(edFileName.Text, True);PDF com Baixa Compressão 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);

Esses códigos acima podem ser encontrados no projeto deExemplo3 que acompanha o componente ExportQR.

Observação

Não entrei em detalhes sobre a criação dos exemplos, paraque o foco principal que é conhecer o componente não sejaperdido. Os projetos de exemplo aqui apresentados foram criadospelos próprios fabricantes dos componentes e somente sofreramalgumas poucas alterações como, por exemplo, tradução dosforms para o português.

ConclusãoParticularmente gostei muito desses componentes e acredito

que eles irão nos ajudar bastante na criação de arquivos PDFatravés dos projetos em Delphi, sem aquela dependência dosgeradores de relatório.

Um grande abraço a todos e até a próxima.

Sobre o autorAndré Colavite

Consultor Técnico do The Club

[email protected]

Page 16: Explorando QuickReport0505.pdf

MeGAZINE16

Delphi

IntroduçãoEntra e sai versão do Delphi e o QuickReport continua tendo

uma legião de usuários que, por conseguirem atender seusclientes com este gerador, não vêem necessidade de estarmigrando. Particularmente confesso que gosto do QuickReport,apesar de todos os bugs nestes vários anos de caminhada,contudo, até hoje, não tive nenhuma situação onde o QuickReportme deixou na mão e acredito ser este o motivo de muitosprogramadores ainda o utilizarem.

Neste artigo irei demonstrar algumas técnicas nãotriviais na confecção de relatórios com o QuickReport, como porexemplo, a montagem de um relatório de referência cruzada, umrelatório muito utilizado na impressão de etiquetas onde vocêpoderá estar repetindo um mesmo registro por N vezes, etc.

Instalando o QuickReport no Delphi 7A Borland© não traz o QuickReport adicionado a IDE, porém,

traz o pacote dclqrt70.bpl referente o QuickReport na pasta:

C:\Arquivos de programas\Borland\Delphi7\Bin

Para adicionar, acesse o menu Component | Install Packages| Add e adicione o referido pacote. Após adicionar, recomendoefetuar atualização do QuickReport que está disponível paradownload no site do fabricante no endereço:

Delphi 7http://www.qusoft.com/

getfile.asp?level=0&Filename=QRSTD351D7.EXE

Delphi 6http://www.qusoft.com/

getfile.asp?level=0&Filename=qr351sd6.exe

O evento OnNeedData

Antes de começarmos, gostaria de explicar o eventoOnNeedData do QuickReport, pois, este evento será muitoutilizado nestes exemplos. Por padrão, quando ligamos umcomponente DataSet na propriedade DataSet do QuickReport, eleautomaticamente assume o controle e vai movendo o ponteiro doDataSet até atingir o último registro e mostrando os dados emuma banda DetailBand, por exemplo. Em muitas situações não éeste o resultado que necessitamos e poderemos precisar assumir ocontrole da navegação nos registros e, é exatamente isso que oevento OnNeedData nos possibilita. A seguir, veja o escopo desteevento:

procedure TForm1.QuickRep1NeedData(Sender:TObject; var MoreData: Boolean);begin //end;

Observe que temos um parâmetro chamado MoreData. Nomomento da impressão, o QuickReport dispara este evento everifica o valor do parâmetro MoreData e caso este sejaverdadeiro (true) irá forçar a impressão de mais umaDetailBand, ou seja, irá gerar mais uma linha em nosso relatórioe no momento que encontrar esta variável falsa, irá encerrar orelatório.

Banco de DadosIremos utilizar o Firebird 1.5.2 onde a princípio vamos criar

duas tabelas, sendo uma contendo os dados dos clientes e outracontendo as compras efetuadas por estes clientes. Sugiro utilizaro IBExpert (www.ibexpert.com) que é uma ferramenta gratuita

Sobre o autorAlessandro Ferreira, Consultor Técnico do The Club

[email protected]

Explorando o QuickReportExplorando o QuickReportExplorando o QuickReportExplorando o QuickReportExplorando o QuickReportExplorando o QuickReportExplorando o QuickReportExplorando o QuickReportExplorando o QuickReportExplorando o QuickReportCriando relatórios não triviaisCriando relatórios não triviaisCriando relatórios não triviaisCriando relatórios não triviaisCriando relatórios não triviais

Page 17: Explorando QuickReport0505.pdf

MeGAZINE 17

Delphi

para manutenção em bancos Interbase/Firebird para criar obanco de dados e suas tabelas. (Poderá encontrar referênciasobre o IBExpert em nossa revista de Dezembro/2004).

Vamos criar as estrutura da tabela Clientes, veja o código nalistagem 1.

CREATE TABLE CLIENTES ( ID INTEGER NOT NULL PRIMARY KEY, NOME VARCHAR(70), ENDERECO VARCHAR(70), BAIRRO VARCHAR(30), CIDADE VARCHAR(30), UF CHAR(2), CEP CHAR(10), CNPJ_CPF VARCHAR(18), RG_IE VARCHAR(18), TELEFONE VARCHAR(18), EMAIL VARCHAR(80));

Listagem 1 – Tabela Clientes

Agora vamos criar uma tabela chamada Vendas, a qual teráuma estrutura bem simples apenas para ilustrar nosso relatório,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 CONSTRAINTFK_VENDAS_CLIENTES FOREIGN KEY (CLIENTE_ID) REFERENCESCLIENTES (ID);

Listagem 2 – Tabela Vendas

Para podermos testar nosso relatório, vamos acionar algunsregistros em ambas as tabelas… Para isso, poderá utilizar a aba“Data” do IBExpert e vamos inserir alguns clientes, veja a figura1.

Figura 1 – Clientes

Agora vamos adicionar alguns registros que irão representaras compras destes clientes, veja a figura 2.

Figura 2 – Vendas

Obs. Adicione dados para todos os clientes alternandovalores e datas. Se preferir, poderá baixar o projeto deexemplo apresentado neste artigo no qual já adicionamosdados nas tabelas para testes, veja o endereço no final desteartigo.

1. Construindo um relatório de referência cruzada(CrossTab)

Nosso primeiro exemplo será a construção de um relatório decruzamento de dados, ou seja, um relatório CrossTab.

Diferente de outros gerados de relatórios que trazem esterecurso embutido, no QuickReport teremos que fazer tudo ‘nobraço’ utilizando entre outros, o eventos OnNeedDataanteriormente descrito.

Primeiro, vamos criar um projeto no Delphi 7 onde iremosatravés da dbExpress acessar o banco de dados e gerar umaconsulta SQL para agrupar os dados de acordo com nossasnecessidades e depois utilizá-los em nosso relatório.

Adicione um componente SQLConnection (dbExpress), alteresua propriedade Name para cnxCrossTab, a propriedade

Page 18: Explorando QuickReport0505.pdf

MeGAZINE18

Delphi

LoginPrompt para False, dê um duplo clique no componente eadicione uma conexão apontando para nosso banco de dados deexemplo, conforme sugere a figura 3.

Figura 3 – Conexão dbExpress.

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

SelectCLI.NOME AS CLIENTE, EXTRACT(MONTH FROMVEN.DATA) AS MES,SUM(VEN.VALOR_TOTAL) AS TOTALFrom VENDAS VENLeft Outer Join CLIENTES CLI on CLI.ID = VEN.CLIENTE_IDWhere EXTRACT(YEAR FROM VEN.DATA) = :ANOGroup By CLI.NOME, EXTRACT(MONTH FROM VEN.DATA)

Listagem 3 – Sentença SQL.

Adicione um componente DataSetProvider, configure Namepara dspCrossTab e DataSet para sdsCrossTab. Após isso,adicione um componente ClientDataSet, configure Name para

cdsCrossTab, ProviderName para dspCrossTab edepois clique com o botão direito no mesmo eselecione a opção: ‘Fetch Params’.

Para testes, se executar esta sentença SQL noIBExpert, terá o resultado apresentado na figura 4.

Figura 4 – Select executado

Observe que os dados ficam arranjados contendo mês/totallinha a linha para cada cliente. Contudo, um relatório dereferência cruzada consiste em arranjar os dados na estruturaapresentada na tabela 1.

Cliente Jan Fev Mar Abr Mai Jun Jul Ago Set Out Nov Dez Total

Alessand... 420,00 180,00 420,00 280,00 500,00 420,00 180,00 100,00 320,00 180,00 100,00 500,00 3.600,00

Emerson... 1267,00 487,00 1850,00 1190,00 1190,00 530,00 650,00 540,00 221,00 311,00 123,00 1205,00 9.564,00

Total 13.164,00

Tabela 1Dados arranjados emcross-tab

Dando continuidade a implementação do relatório, adicioneum componente QuickReport, altere Name para QR_CrossTab.Em cima deste QuickReport, adicione três componentes QRBand,configurando a propriedade BandType para rbPageHeader,rbDetail e rbSummary, respectivamente. Devido a estruturadeste relatório, vamos necessitar de mais espaço na transversal,por isso, selecione o QuickReport e altere a propriedade Page |Orientation para poLandscape.

Page 19: Explorando QuickReport0505.pdf

MeGAZINE 19

Delphi

Tendo como base de layout a tabela 1 anteriormenteapresentada, vamos adicionar componentes QRLabel os quaisserão responsáveis pela apresentação dos dados. Na bandareferente o cabeçalho, adicione 14 QRLabels ajustando o primeirocom o Caption ‘Nome do Cliente’, os próximos 12 deverão conter onome de cada mês começando por ‘Janeiro’ e o último QRLabelterá como Caption ‘Total’;

Agora vamos adicionar os QRLabel na banda detalhe(DetailBand) a qual será responsável pela apresentação dosdados. Mais uma vez iremos necessitar de 14 QRLabels, seguindoa mesma lógica da banda anterior, sendo o primeiro paraapresentação do nome do cliente, os 12 subseqüentes paraapresentação dos valores respectivos à cada mês e o último parauma totalização dos meses. Vale ressaltar que iremos utilizaruma nomenclatura específica para estes componentes, pois, maisadiante na codificação iremos implementar uma rotina genéricapara facilitar a implementação, assim sendo, nomeie oscomponentes 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.

E para finalizar, vamos novamente adicionar mais 14QRLabels, agora em cima da banda sumário, seguindo a mesmaestrutura utilizada nas bandas anteriores e tendo o cuidado denomear 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 código ao nosso relatórioAntes de iniciarmos a codificação de nosso relatório, adicione

um componente Bitbtn e um MaskEdit ajustando o layout doformulário como apresenta a figura 5.

Figura 5 – Formulário para chama do QuickReport

Obs. Apenas a título de informação, o QuickReportestá neste mesmo formulário, porém encontra-seescondido e para visualizá-lo bastará aumentar otamanho do formulário.

Iniciando a codificação, faça as seguintes declarações abaixoda sessão Private do objeto Form, conforme apresenta a listagem 4.

private { Private declarations }

TotColunas: Array[1..12] of Extended; TotCliente, TotGeral: Extended; NomeDoCliente: String; ImpTitulo: Boolean;

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

Listagem 4 – Declarações.

Dica: Após efetuar estas declarações, tecle a combinaçãoCTRL+SHIFT+C e automaticamente o editor irá criar ocabeçalho dos procedimentos abaixo da sessão implementation.

Observe que declaramos um Array o qual será responsávelem armazenar a totalização de cada coluna (mês) o qual iremosapresentar no final do relatório, na banda sumário e para não terque fazer referência a cada elemento do Array, implementamosum método para inicializar este Array, acompanhe a listagem 5.

{ Limpa Array que irá armazenar a totalizaçãodas colunas. }procedure TForm1.ZeraTotColunas;var i: Integer;begin for i := Low(TotColunas) toHigh(TotColunas) do TotColunas[i] := 0;end;

Listagem 5 – Iniciar Array

Prosseguindo, na listagem 6 apresentamos outros dois métodos:LimpaValores e LimpaSumario. O primeiro, será responsável emlimpar o conteúdo dos QRLabels existentes na banda detalheatribuindo ‘0,00’ ao seu caption e veja que não fazemos referênciadireta ao nome dos QRLabels e sim dentro de um laço FORpesquisamos o componentes pelo seu nome, por isso aimportância da nomenclatura anteriormente sugerida. O métodoLimpaSumario tem a mesma finalidade, contudo, aplica-se aos

Page 20: Explorando QuickReport0505.pdf

MeGAZINE20

Delphi

QRLabels existentes na banda sumário.

{ 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 sumário }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 – Métodos para limpar os QRLabels

O método seguinte apresentado na listagem 7 é um dos maisimportantes dentro deste contexto, pois, será o responsável empreencher os QRLabels (da banda detalhe) com os valoresadvindos 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

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 – Método que alimenta os QRLabels

Vamos explicar o método PreencheValores, o qual começaatribuindo false para a variável ImpTitulo. Esta variável seráresponsável em controlar quando a banda detalhe deverá serimpressa, pois a mesma deverá ser impressa apenas quandotodos os meses do referido cliente estiverem preenchidos. Vocêdeve estar lembrando que o controle de navegação dos registros épor nossa conta e a fim de obtermos todos os registros referente ocliente atual, efetuamos um laço enquanto o cliente permanecer omesmo e enquanto não atingir o final do arquivo. Dentro destelaço, vamos acumulando o valor de cada coluna (mês) e o valorreferente ao cliente corrente. Mais uma vez recorremos aoFindComponent para pesquisar e retornar os QRLabelsexistentes na banda detalhe através do seu nome e caso sejaencontrado, alimentamos sua propriedade caption.

Ao término do while, verificamos que todos os dados clientearmazenado na variável NomeDoCliente foram obtidos e nosresta efetuar a totalização deste cliente e armazenar seu total navariável TotaGeral que irá ser apresentada na banda sumário, eatribuir true à variável ImpTitulo a qual irá ‘liberar’ a impressãoda banda detalhe com todos os dados já carregados para orespectivo cliente.

Page 21: Explorando QuickReport0505.pdf

MeGAZINE 21

Delphi

Bem, estamos agora quase concluindo a codificação de nossorelatório, contudo, necessitamos alimentar os totais para cadamês e um total geral em nossa banda sumário.

Para isso, seguindo a mesma lógica do método anterior,porém, lendo os dados do Array TotColunas que representa o totalde cada coluna (mês), acompanhe a listagem 8.

{ Preenche os componentes da banda sumário }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 bandasumário.

Dando continuidade, dê um duplo clique no Bitbtn queserá responsável em chamar o relatório e adicione o códigoapresentado na listagem 9.

{ Chamar o relatório }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 – Botão visualizar

Não mencionei anteriormente, contudo, adicione umcomponente QRLabel em cima da banda de cabeçalho(PageHeader) e em seu caption escreva: ‘Demonstrativo deVendas por Cliente Referente o Ano de: ’.

Até aqui, apenas implementamos métodos para váriasfuncionalidades dentro de nosso relatório. Vamos agora efetuar achamada destes métodos, os quais serão chamados em algunseventos do próprio QuickReport. Como primeiro evento, acesse oBeforePrint do QuickReport e faça a seguinte codificação:

{ BeforePrint do QuickReport }procedureTForm1.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; { Inicialização } LimpaValores; LimpaSumario; ZeraTotColunas;end;

Na listagem 10 apresentamos as demais chamadas à seremefetuadas:

{ BeforePrint da banda detalhe }procedureTForm1.DetailBand1BeforePrint(Sender:TQRCustomBand; var PrintBand: Boolean);begin { Alimenta os QRLabel } PreencheValores; { Indica o momento que a banda deverá serimpressa } PrintBand := ImpTitulo;end;

{ Após imprimir a banda detalhe }procedureTForm1.DetailBand1AfterPrint(Sender:TQRCustomBand; BandPrinted: Boolean);begin

Page 22: Explorando QuickReport0505.pdf

MeGAZINE22

Delphi

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

{ BeforePrint da banda sumário }procedureTForm1.SummaryBand1BeforePrint(Sender:TQRCustomBand; var PrintBand: Boolean);begin { Alimenta os QRLabel do sumário } PreencheSumario;end;

Listagem 10 – Chamada dos métodos

Tudo pronto? Se você respondeu que sim, está enganado. Mascalma, falta apenas um pequeno detalhe, porém muitoimportante sem o qual nosso relatório não irá funcionar. Lembraque comentei do evento OnNeedData?! Bem, será este evento queirá fazer nosso relatório funcionar, veja a listagem 11.

procedure TForm1.QR_CrossTabNeedData(Sender:TObject; var MoreData: Boolean);begin { Enquanto não for final de arquivo,continua imprimindo } MoreData := not (cdsCrossTab.EOF);end;

Listagem 11 – OnNeedData

Neste evento estamos atribuindo true ao parâmetroMoreData enquanto o ClientDataSet não atingir o final doarquivo.

Tudo pronto?! Bem, também espero que sim! Compile e rodeclique no botão visualizar e se não saiu nada errado o resultadoserá semelhante a figura 6.

Figura 6 – Preview do relatório

Obs. Por questões de espaço tivemos que cortar nossopreview ao meio, mas é possível se ter uma idéia de como iráficar.

2. Imprimindo um mesmo registro N vezesVocê já deve ter passado pela necessidade de imprimir um

mesmo registro por N vezes, como por exemplo, um cadastro deprodutos onde você necessita imprimir várias etiquetas para ummesmo produto.

Via programação, bastaria efetuar um laço FOR ou WHILE eenquanto a quantidade não fosse satisfeita, continuar aimpressão. E no QuickReport, como fazer? Isso é bem simples eiremos implementar um exemplo agora mesmo!

Mãos a obra, crie um novo projeto Delphi ou se preferir utilizeo projeto anterior onde podemos aproveitar o mesmo banco dedados, contudo, altere o SELECT no componente SQLDataSetpara “Select * From CLIENTES”, pois iremos utilizar os dadosapenas desta tabela. Adicione também um componenteDataSource ligado ao ClientDataSet e um componente DBGridligado ao DataSource. A figura 7 sugere um layout para esteformulário:

Figura 7Layout sugerido

Adicione um componente QuickReport oqual iremos nomear como QR_Etiqueta e sobreeste uma banda detalhe (rbDetail) e sobre estatrês componentes QRDBText ligados aoClientDataSet e fazendo referência aos campos:NOME, ENDERECO e CIDADE,respectivamente (figura 8).

Page 23: Explorando QuickReport0505.pdf

MeGAZINE 23

Delphi

Figura 8 – QR_Etiquetas

Codificando o RelatórioMais 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 QuickReportdeve ficar em branco, pois o controle será manual.

Na listagem 11 apresentamos o evento OnNeedData doQuickReport e o evento AfterPrint da banda detalhe.

procedure TForm1.QR_EtiquetaNeedData(Sender:TObject; var MoreData: Boolean);begin { Enquanto a propriedade TAG estiver maiorque zero é porque tem que imprimir mais umaetiqueta } MoreData := (QR_Etiqueta.Tag > 0);end;

procedureTForm1.DetailBand1AfterPrint(Sender:TQRCustomBand; BandPrinted: Boolean);begin { A cada etiqueta impressa, vaidecrementando o contador } QR_Etiqueta.Tag := QR_Etiqueta.Tag - 1;end;

Listagem 11 – Eventos

No evento OnNeedData atribuímos verdadeiro ao parâmetroMoreData enquanto o valor da propriedade TAG do QuickReportfor maior que zero. No evento AfterPrint da banda detalhe,vamos decrementando o valor da propriedade TAG após cadaetiqueta impressa.

Obs. A propriedade TAG dos objetos é uma propriedade do tipoINTEGER que poderá ser utilizada para qualquer finalidade.Neste exemplo, ela funciona como um contador e economizamos adeclaração de uma variável para isso.

E para finalizar, vamos efetuar a codificação do botão

‘Visualizar’ (listagem 12).

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á utilizadapara efetuar o controle da quantidade deetiquetas à serem impressas. } QR_Etiqueta.Tag := Quantidade; QR_Etiqueta.Preview;end;

Listagem 12 – Botão visualizar.

Compile e rode o preview e se tudo estiver OK seráapresentado o número de etiquetas informadas para o registrocorrente.

3. Pintando uma imagem de fundo no relatórioDois fatores são fundamentais na apresentação de um

relatório: O primeiro é relevância e confiabilidade dasinformações nele contidas e a segunda, o layout, o qual semdúvidas ajuda a ‘vender seu peixe’. Neste exemplo, voudemonstrar como desenhar uma imagem de fundo noQuickReport, ou seja, uma marca d’água.

Crie um novo projeto no Delphi, adicione um botão, umaQuery e aponte sua propriedade DatabaseName para o aliasDBDEMOS e na propriedade SQL adicione a seguinte instrução:“Select * From Employee”. Adicione um componente QuickReporte sobre ele quatro QRBand sendo: rbTitle, rbColumnHeader,rbDetail e rbPageFooter. Aponte a propriedade DataSet doQuickReport para a Query e adicione QRDBText paraapresentação dos dados.

A figura 9 sugere a configuração do QuickReport.

Figura 9 – QuickReport

Page 24: Explorando QuickReport0505.pdf

MeGAZINE24

Delphi

Estando tudo configurado, vamos efetuar a codificação parachamada e apresentação do Preview com a imagem de fundo. Nalistagem 13 apresentamos o procedimento que será responsável empintar 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;

Listagem 13 – Procedimento para pintar a imagem no QR

O procedimento ImprimeBitmap recebe como parâmetro umobjeto TCanvas que indica “onde” a imagem deverá serapresentada, um objeto TBitmap que irá conter a imagem à serapresentada e um objeto TRect que indica a área onde a imagemdeverá ser apresentada. (Mais informações sobre a manipulaçãode imagens via Delphi poderão ser encontradas no artigo:Desenhos e Bitmaps publicado em nossa revista de Outubro/2000, também disponível em nosso site, www.theclub.com.br)

Estando o procedimento definido, iremos efetuar suachamada no evento AfterPrint da banda de rodapé(rbPageFooter), acompanhe a listagem 14.

{ AfterPrint do rodapé Chamar a rotina que irá imprimir a imagem nofundo do QReport.}procedureTForm1.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 arquivode recursos. Outro aspecto relevante, é que passado o objetoCanvas a partir do objeto QRPrinter implícito no QuickReport.

Para finalizar, vamos efetuar a chamada do relatório noevento OnClick do botão (listagem 15).

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

Listagem 15 – OnClick.

Page 25: Explorando QuickReport0505.pdf

MeGAZINE 25

Delphi

Ao chamar o preview do relatório, o mesmo deverá conteruma imagem de fundo assim como demonstra a figura 10.

Figura 10 – Fragmento do Preview.

4. Imprimindo Etiquetas Lado a LadoO QuickReport possui mecanismo para impressão de dados

em formato de colunas bastando para isso configurar apropriedade Page | Columns, contudo, quando utilizamos esteartifício ele faz uma impressão vertical, ou seja, preenche aprimeira coluna até o final, depois para a segunda coluna até ofinal e assim sucessivamente, o que não pode ser uma boaalternativa quando trabalhamos com formulários de etiquetas enão vamos preenchê-lo totalmente.

Este exemplo irá demonstrar como efetuar uma impressãohorizontal, ou seja, iremos trabalhar com três colunas as quaisserão preenchidas linha a linha. Dessa forma, se tivermos 9registros em nossa tabela, por exemplo, a impressão irá ocupar as3 colunas x 3 linhas de etiquetas, podendo cortar o formulário eutilizá-lo novamente para uma impressão posterior.s

Para começar, crie um novo projeto no Delphi e adicione osseguintes componentes: uma TTable/BDE (Name: tbCustomer,DatabaseName: DBDemos, TableName: Customer); umDataSource (Name: dsCustomer, DataSet: tbCustomer); umDBGrid (DataSource: dsCustomer); um BitBtn; um QuickReport(Name: QR_LadoALado) e em cima deste QuickReport umQRBand (BandType: rbDetail) e em cima deste QRBand 3componentes QRMemo ajustando a propriedade AutoSize paraFalse e ajustando sua altura de forma a comportar asinformações que iremos adicionar na etiqueta (Nome, endereço,cidade, etc...) e sua largura de forma a suprir a largura daetiqueta, lembrando que posicionaremos um QRMemo ao lado dooutro, veja a figura 11.

Figura 11QuickReport

Codificando nosso relatórioBasicamente, todo o código ficará concentrado no evento

BeforePrint da banda detalhe (rbDetail) conforme apresenta alistagem 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 não necessitarmosrepetir o mesmo código três vezes (pois são 3 QRMemos)executamos um laço FOR para acessar o componente, efetuandoa pesquisa pelo nome e retornando o objeto TQRMemo. Sempreantes de adicionarmos qualquer informação iremos chamar ométodo Clear do QRMemo para limpar qualquer informação queexista no mesmo. Prosseguindo, verificamos se a tabelatbCustomer não atingiu final de arquivo e adicionamos oscampos que desejamos mostrar em cada linha do QRMemo e

Mais uma vez iremos efetuar o controle do ponteiro doDataSet ‘a mão’ e por isso a propriedade DataSet do QuickReportdeverá ficar em ‘branco’.

Page 26: Explorando QuickReport0505.pdf

MeGAZINE26

Delphi

ainda dentro deste laço FOR, executamos um Next para moverpara o próximo registro.

E para finalizar a codificação, vamos programar o eventoBeforePrint e OnNeedData do QuickReport e a chamada dorelatório no evento OnClick do botão, acompanhe a listagem 16.

procedure TForm1.QR_LadoALadoNeedData(Sender:TObject; var MoreData: Boolean);begin { Gera mais uma linha enquanto não forfinal de arquivo } MoreData := not (tbCustomer.EOF);end;procedure TForm1.btnVisualizarClick(Sender:TObject);begin QR_LadoALado.Preview;end;procedureTForm1.QR_LadoALadoBeforePrint(Sender:TCustomQuickRep; var PrintReport: Boolean);begin tbCustomer.First;end;

Listagem 16 – Finalizando a codificação

Estando tudo OK, compile e execute a aplicação e o resultadodeverá ser parecido com o fragmento apresentado na imagem 12.

Figura 12 – Parte do preview

em disco e é exatamente isso que iremos demonstrar nesta dica.Então, crie um novo projeto Delphi e nele adicione umcomponente 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 dabanda detalhe. A figura 13 sugere o layout para este formulário.

Figura 13 – Layout sugerido

Codificando o relatórioA idéia aqui será carregar o arquivo texto em um objeto do

tipo TStringList e depois ir lendo linha a linha este TStrings etransferindo o conteúdo da linha ao QRLabel. Assim sendo,detalhe uma variável chamada Texto abaixo da sessão var denossa unit, veja a listagem 17.

var Form1: TForm1; Texto: TStringList;implementation{$R *.DFM}

Listagem 17 – declaração do TStringList.Prosseguindo, vamos efetuar a codificação do sbtnProcurar o

qual terá como finalidade abrir uma caixa de diálogo para que ousuário possa escolher o arquivo à ser impresso e atribuir seucaminho/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 próximo passo será codificar o botão btnPreviewque irá efetuar a carga do arquivo texto e a chamada do

nosso relatório, acompanhe a listagem 19.

5. Imprimindo Arquivo TextoCom base nas dicas anteriores você já deve ter notado que

podemos utilizar o QuickReport para imprimir utilizandopraticamente qualquer fonte de dados, sendo esta vinda de umDataSet, de um Memo ou mesmo de um arquivo texto existente

Page 27: Explorando QuickReport0505.pdf

MeGAZINE 27

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 umarquivo!’);end;

Listagem 19 – OnClick btnPreview.

No evento OnClick do btnPreview, primeiro confirmamos aexistência do arquivo anteriormente selecionado, depoisinstanciamos o objeto TStringList e carregamos o arquivo nomesmo. Novamente iremos utilizar a propriedade TAG doQuickReport a qual será nosso contador de linhas impressas,iniciando-a em zero e finalizando, chamamos o preview doQuickReport.

Até este ponto, apenas carregamos o arquivo texto no objetoTStringList, contudo, necessitamos ir lendo linha a linha etransferindo seu conteúdo ao QRLabel existente em nossa bandadetalhe. Isso será feito no evento BeforePrint da própria bandadetalhe. Como estamos efetuando a impressão linha a linha, noevento AfterPrint da banda detalhe iremos incrementar nossocontador (propriedade TAG do QuickReport) e no eventoBeforePrint do QuickReport iremos zerar nosso contador (isso énecessário, pois ao clicar em imprimir o relatório será processadonovamente e o contador deve estar no início), acompanhe esteseventos na listagem 20.

procedure TForm1.QR_ImpTextoNeedData(Sender:TObject; var MoreData: Boolean);begin MoreData := (QR_ImpTexto.Tag <Texto.Count);end;procedureTForm1.DetailBand1BeforePrint(Sender:TQRCustomBand;

var PrintBand: Boolean);begin QRTexto.Caption := Texto[QR_ImpTexto.Tag];end;procedureTForm1.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.

Com isso concluímos nosso relatório de impressão de arquivotexto, compile e rode o exemplo e o arquivo texto escolhido deveráaparecer no preview.

ConclusãoA partir do Delphi 7 o QuickReport deixou de ser distribuído

como ferramenta oficial de relatórios no Delphi, sendo substituídopelo Rave Report. Contudo, como mencionamos no início desteartigo, o QuickReport ainda é um dos geradores de relatóriosmais utilizados na comunidade Delphi. Procurei demonstrar aquialgumas técnicas que possibilitam explorar muitasfuncionalidades do QuickReport permitindo a você utilizá-lo emsituações que aparentemente teríamos que recorrer à outrosartifícios, como exemplo o TPrinter, podendo dessa forma seguiruma padronização em seus relatórios.

Vale ressaltar que o fabricante do QuickReport lançourecentemente a versão 4.0 que dá suporte até o Delphi 2005 e,dessa forma, se você necessitar converter suas aplicações para oDelphi 2005 e não pretendo migrar para outro gerador derelatórios, poderá adquirir o QuickReport juntamente aofabricante, lembrando que ele não é mais gratuito.

Forte abraço e sucesso à todos.

DownloadOs exemplos apresentados neste artigo estão disponíveis para

download no endereço:http://www.theclub.com.br/revista/download/QREspecial.zip

Page 28: Explorando QuickReport0505.pdf

MeGAZINE28

Perguntas & Respostas

Pergunta: Ao tentar compilar um programa exemploASP.NET, o Delphi 2005 traz a seguinte mensagem: Unable tostart debugging on the web server. Unable to attach to ASP.NETworker process (typically aspnet_wp.exe or w3wp.exe). Comoresolver este problema?

Resposta: “Unable to attach to ASP.NET worker process(typically aspnet_ wp.exe or w3wp.exe)”

Caso você instale o IIS após a instalação do .Net Framework,e tente rodar uma aplicação Asp.Net, irá receber o erro acima, epara solucionar, basta executar o seguinte comando:

c:\windows\ microsoft.net\framework\v1.1.4322\aspnet_regiis.exe -i

http://support.microsoft.com/default.aspx?scid=kb;EN-US;q306005

Dúvida enviada por Wagner Araujo Mesquita, Franca/SP.

Pergunta: Gostaria de saber se a propriedade Level doTTreeNode do Delphi 7 possui algum correspondente no TreeNodedo Delphi 2005 (Windows Forms).

Resposta: Não encontramos nenhum método queretornasse esta informação, contudo, é simples serimplementado, confira:

function Level(N: TreeNode): Integer;begin Result := 0; while (N.Parent <> nil) do

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

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

Dúvida enviada por Wisys Produtos Inteligentes Ltda, Rio deJaneiro/RJ.

Pergunta: Após deletar um registro no ClientDataSetchamando o método delete, se eu fechar e abrir a aplicação oregistro aparece novamente.

O que pode estar errado?

Resposta: Quando você apaga um registro via métododelete do ClientDataSet, você apenas esta apagando no cache epara que a instrução de delete seja efetivada no banco, chame ométodo ApplyUpdates(0) no evento AfterDelete, por exemplo.

Dúvida enviada por Kleyton Smentkoski, Santo Antonio daPlatina/PR.

Pergunta: Existe alguma possibilidade do Delphi abrir umdeterminado documento do Word, modificar algumas variáveis eexibir em tela apenas para impressão?

Page 29: Explorando QuickReport0505.pdf

MeGAZINE 29

Perguntas & Respostas

Resposta: Isso é possível utilizando programação OLEatravés dos componentes da palheta Servers. Em nossa revistade Fevereiro/2000 publicamos um artigo a este respeito. Caso nãopossua a revista poderá acessar em nosso site,www.theclub.com.br.

Dúvida enviada por Ricardo Cerqueira, Caruaru/PE.

Pergunta: Gostaria de uma rotina que me retornasse aspastas compartilhadas de todas as máquinas na rede, como devoproceder?

Resposta: Existem APIs do Windows que possibilitam obterestas informações, acompanhe o exemplo a seguir:

{Procedure que irá percorrer as máquinas darede 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 alocaçãode memória.} 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 possíveis.} enumRes := WNetEnumResource

(hEnum, count, buffer, BufferSize);

{caso ocorra algum problema, cancela.}

if (enumRes <> ERROR_SUCCESS) thenbreak;

pnr := buffer; { reutiliza o

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 função. } 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 eum componente ListBox e faça a chamada assim:

procedure TForm1.Button1Click(Sender: TObject);

begin GetNetworkedDrives(ListBox1.Items);

end;

Dúvida enviada por Vagner Martins, Rafard/SP.

Pergunta: Gostaria de mostrar uma mensagem na tela porN segundos e que a mesma fechasse automaticamente após otempo pré-determinado. Isso é possível?

Resposta: Sim, existe uma API do Windows chamadaMessageBoxTimeOut que tem esta finalidade. Para utilizá-la,crie uma nova unit e salve como MsgBoxTimeOut e nela efetueas seguintes declarações:

Page 30: Explorando QuickReport0505.pdf

MeGAZINE30

Perguntas & Respostas

unit MsgBoxTimeOut;

interface

uses Windows;

const MB_TIMEDOUT = 32000;

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;

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

implementation

function MessageBoxTimeOut; external user32name ‘MessageBoxTimeoutA’;function MessageBoxTimeOutA; external user32name ‘MessageBoxTimeoutA’;function MessageBoxTimeOutW; external user32name ‘MessageBoxTimeoutW’;

end.

Pronto, agora bastará declarar esta unit ondedesejar chamar a função MessageBoxTimeOut,veja um exemplo a seguir:

procedure TForm1.Button1Click(Sender:TObject);var iRet: Integer; iFlags: Integer;begin iFlags := MB_OK or MB_SETFOREGROUND orMB_SYSTEMMODAL or MB_ICONINFORMATION;

{ Chama com botão OK } iRet :=

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

iFlags := MB_YESNO or MB_SETFOREGROUND orMB_SYSTEMMODAL or MB_ICONINFORMATION;

{ Chamada com botão Sim/Não } iRet :=MessageBoxTimeout(Application.Handle, ‘Iráfechar em 5 segundos’, ‘MessageBoxTimeout Test’, iFlags, 0,5000);

case iRet of IDYES: { Botão ‘sim’. } ShowMessage(‘Sim’); IDNO: { botão ‘não’ } ShowMessage(‘Não’); MB_TIMEDOUT: { TimeOut } ShowMessage(‘Você não selecionou Sim/Não, tempo esgotado!’); end;end;

Dúvida enviada por Almir Rodrigues Borges, Araçatuba/SP.

Pergunta: Gostaria de saber se vocês têm algumcomponente “botão” que ao clicar tenha várias opções, como clicarem um menu, de preferência, que seja descendente da classeTBitBtn ou TSpeedButton.

Resposta: Você poderá implementar esta funcionalidadeutilizando próprio BitBtn e um componente PopupMenu,abrindo-o exatamente abaixo do botão que recebeu click. Paraisso, adicione um componente PopUpMenu e nele adicione asopções que desejar. Após isso, adicione um BitBtn e no eventoOnClick do mesmo codifique:

varP: TPoint;beginP :=BitBtn1.ClientToScreen(BitBtn1.ClientRect.BottomRight);PopupMenu1.Popup(P.x-BitBtn1.Width, P.y);end;

Dúvida enviada por Maicon César Loffi, Laurentino/SC.

Page 31: Explorando QuickReport0505.pdf
Page 32: Explorando QuickReport0505.pdf