editorial - the club · gerar via quickreport, de preferência, no formato que aparece no preview....

32

Upload: vuongxuyen

Post on 09-Feb-2019

215 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: EDITORIAL - The Club · gerar via QUICKREPORT, de preferência, no formato que aparece no PREVIEW. Resposta: ... usando os componentes da paleta indy ? Usando o componente da paleta
Page 2: EDITORIAL - The Club · gerar via QUICKREPORT, de preferência, no formato que aparece no PREVIEW. Resposta: ... usando os componentes da paleta indy ? Usando o componente da paleta
Page 3: EDITORIAL - The Club · gerar via QUICKREPORT, de preferência, no formato que aparece no PREVIEW. Resposta: ... usando os componentes da paleta indy ? Usando o componente da paleta

3

THE CLUBAv. Profº Celso Ferreira da Silva, 190

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

Suporte: (14) 3733-1588 - Fax: (14) 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 aseção "Tire sua dúvida".

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

armazenamento em banco de dados, sobqualquer forma ou meio, de textos, fotos e

outras criações intelectuais em cada publicaçãoda revista “The Club Megazine” são

terminantemente proibidos sem autorizaçãoescrita dos titulares dos direitos autorais.

Impressão e acabamento:GRAFILAR

Tel.: (14) 3841-2587 - Fax: (14) 3841-3346Rua Cel. Amando Simôes, 779

Cep 18.650-000 - São Manuel - SPTiragem: 5.000 exemplares

Copyright The Club Megazine 2006

Diretor TécnicoMauro Sant’Anna

ColaboradoresMarcelo Nogueira, Mário Bohm,

Aguinaldo P. Silva, Alexandre Tarifa

EDITORIAL

Editorial

Editorial .................................................................................. 03Perguntas & Respostas ......................................................... 04Winforms - Expandindo controles .......................................... 09Validando controles com Error Provider ................................. 12Dicas rápidas para Delphi 7 ................................................... 16Novas características do Delphi 2006 .................................... 27Delphi é marca registrada da Borland International,

as demais marcas citadas são registradaspelos seus respectivos proprietários.

Olá amigos,

Estamos começando mais um ano e gostaríamos desejar a todos vocês um excelente2006 com muita saúde e sucesso.

Também gostaríamos de dar as boas vindas ao nosso mais novo colaborador,Alexandre Tarifa.

Ele é MVP (Most Valuable Professional), MCAD (Microsoft Certified ApplicationDeveloper) e MCT (Microsoft Certified Trainer). Bacharel pela UMESP e pós-graduando pela Universidade Federal de São Carlos em Ciência da Computação.Analista de Sistemas. A partir deste mês estaremos publicando seus artigos.

Nesta primeira edição de 2006 estamos começando com a nossa sessão Perguntas& Respostas com algumas das solicitações atendidas neste mês.

Estamos trazendo também diversas dicas sobre o Delphi 7 que com certeza irão lheauxiliar muito no seu dia a dia.

E finalizando estamos trazendo mais novidades sobre o Delphi 2006.

Um grande abraço a todos e boa leitura.

Page 4: EDITORIAL - The Club · gerar via QUICKREPORT, de preferência, no formato que aparece no PREVIEW. Resposta: ... usando os componentes da paleta indy ? Usando o componente da paleta

4

Pergunta: Preciso enviar via email um relatório que vougerar via QUICKREPORT, de preferência, no formato queaparece no PREVIEW.

Resposta: O QuickReport gera um arquivo .QRP com orelatório. Para salvar em arquivo faça da seguinte forma:

QuickRep1.QRPrinter.Save(‘c:\relatorio.qrp’);

Dúvida enviada por José Léo, Saudades - SC

Pergunta: Preciso verificar se um diretório existe. Seexistir, devo mostrar uma mensagem ao usuário perguntando seexclui ou não o diretório. O diretório será passado por parâmetro.Preciso também de renomear um diretório.

Como faço estas duas coisas, pois tentei de várias maneirassem sucesso.

Resposta: Para verificar se o diretório existe, você podeutilizar a função DirectoryExists, o exemplo abaixo verifica se odiretório existe. Caso contrário o diretório é criado.

uses FileCtrl;

procedure TForm1.Button1Click(Sender: TObject);

begin if not DirectoryExists(‘c:\temp’) then if not CreateDir(‘C:\temp’) then raise Exception.Create

(‘Cannot create c:\temp’);end;

Para deletar o diretório, você pode utilizar a funçãoRemoveDir, por exemplo:

RemoveDir(‘c:\temp’);

Para renomear um diretório você pode utilizar a rotinaabaixo:

procedure TForm1.Button1Click(Sender:TObject); var f : file;begin AssignFile(f, ‘C:\2’); Canvas.TextOut(5, 10, ‘Renomeando C:\2para C:\3’); Rename(f, ‘C:\3’);end;

Dúvida enviada por Bruno, Três Pontas - MG

Pergunta: Eu gostaria de saber se existe uma função quepreencha com espaço até o final da string.

Por exemplo: ‘José da Silva ‘ .

Resposta: Você pode utilizar o exemplo abaixo.

Var S: String;Begin S := Format(‘%-30s’, [Table.FieldByName

(‘Campo’).AsString])’;End;

* 30 é o tamanho total do campo, dados + espaços.

Dúvida enviada por Luis, Santo Antonio da Platina – PR

Perguntas & Respostas

Page 5: EDITORIAL - The Club · gerar via QUICKREPORT, de preferência, no formato que aparece no PREVIEW. Resposta: ... usando os componentes da paleta indy ? Usando o componente da paleta

5

Pergunta: Existe alguma forma, de pegar o valor docomponente QRExpression do QuickReport. Pois tenho estecomponente para somatório, e estou necessitando utilizar o valorgerado por ele.

Resposta: Para pegar o valor de um QRExpression vocêpode utilizar a instrução QRExpr1.Value.dblResult. Veja oexemplo abaixo pegando o valor e atribuindo a um QRLabel.

procedure TForm1.QRLabel4Print(sender: TObject; var Value: String);

begin Value :=FloatTostr(QRExpr1.Value.dblResult);end;

Dúvida enviada por Alessandro, Araras - SP

Pergunta: Vocês possuem algum exemplo de um webbrowser para que eu possa inserir na minha aplicação, usando oscomponentes da paleta indy ? Usando o componente da paletaInternet eu já possuo. Mas este requer que exista o InternetExplorer instalado.

Resposta: Existe um componente Freeware que você podeutilizar. Veja em http://www.pbear.com/htmlviewers.html#thtmllite.

Dúvidas enviada por Nirlan, São Matheus - ES

Pergunta: Gostaria de ver um exemplo para a criação deaplicações em pacotes. Há alguma matéria publicada?

Resposta: Nós temos uma matéria a este respeito que podeser acessada no link http://www.theclub.com.br/revista/pacotes.doc.

Dúvida enviada por Rafael, Belo Horizonte - MG

Pergunta: Gostaria de saber como faço para criar umarotina dentro em minha aplicação onde o próprio usuário rode osscript de atualização do sistema. Gostaria de saber também seexiste algum componente que faça este tipo de execução, eu colocoos script sql num arquivo e o componente executa o mesmo.

Resposta: Para rodar scripts no banco de dados você podeutilizar um componente chamado SQLScript que pertence ao

DBExpressPlus.O DBExpressPlus é uma suíte de componentes gratuitos que

facilitam a execução de tarefas comuns no dia-a-dia doprogramador Delphi.

Você poderá fazer o download do DBExpressPlus no seguinteendereço:

http://sourceforge.net/projects/dbexpressplusA instalação é bastante simples, basta descompactar o

arquivo baixado preferencialmente criando uma pasta em$(Delphi)\Source\dbExpressPlus, onde “$(Delphi)” indica apasta de instalação de seu Delphi.

Após isso, abra o pacote dbExprPlus_r?0.dpk (?=versão doDelphi, 6 ou 7) e clique no botão “Compile”. Continuando, abra opacote dbExprPlus_d?0.dpk, clique em “Compile” e depois em“Install”.

Para concluir, acesso o menu “Tools | Environment Options| Library | Library Path” e adicione o path onde os arquivosforam descompactados, ou seja,$(Delphi)\Source\dbExpressPlus e com isso finalizamos ainstalação do dbExpressPlus.

Se tudo ocorreu sem problemas, você poderá visualizar osnovos componentes na paleta de componentes dbExpress.

Para conhecer as funcionalidades de todos os componentes,você poderá abrir o projeto de exemplo que acompanha odbExpressPlus, podendo ser encontrado na pasta Demo($(Delphi)\Source\dbExpressPlus\Demo).

Dúvida enviada por Sebastião Nóbrega, Salvador - BA

Pergunta: Como faço para trocar o valor (resultado) deuma Query, no DBGrid? Eu trago um campo boolean (true oufalse) e quero mostrar (sim ou não) Gostaria de fazer tudo istoem tempo de execução. É possível?

Resposta: O SQL Server não tem campo do tipo boolean,então suponho que esteja utilizando um campo do tipo varcharou algo semelhante. Neste caso você pode utilizar o comando Casedisponível no SQL Server, por exemplo:

SELECT Codigo, Nome,

CASE Campo WHEN ‘true’ THEN ‘sim’ WHEN ‘false’ THEN ‘não’ END AS NovoCampo

FROM Tabela

Dúvida enviada por Amauri, São Paulo - SP

Perguntas & Respostas

Page 6: EDITORIAL - The Club · gerar via QUICKREPORT, de preferência, no formato que aparece no PREVIEW. Resposta: ... usando os componentes da paleta indy ? Usando o componente da paleta

6

Pergunta: Pode ser usado o comando for in para varrer umcomponente ClientDataSet e atribuir, por exemplo, os nomes doscampos para um componente ListBox?

Resposta: Isto pode ser feito da seguinte forma:

procedure TForm2.Button1Click(Sender: TObject);

var Item: TField;begin for Item in ClientDataSet1.Fields do begin ListBox1.Items.Add(Item.FieldName); end;end;

Dúvida enviada por Paulo, Assis - SP

Pergunta: Gostaria de saber se vocês têm alguma rotinapara instalação de minha aplicação comercial.

Resposta: Para instalação de programas nós aconselhamosa utilização do InnoSetup. Nos links a seguir você encontraráinformações mais detalhadas sobre este utilitário, http://www.theclub.com.br/revista/cria0803%5Fb.aspx, http://www.theclub.com.br/revista/inst0604.aspx e http://www.theclub.com.br/revista/inst0605.aspx.

Dúvida enviada por Israel, Três Pontas - MG

Pergunta: Tenho um software que abre outros softwaresatravés dele. Como faço para saber se um desses softwares jáestá sendo executado?

Resposta: Você pode trabalhar com o título da janela. Oexemplo a seguir mostra como fechar uma aplicação a partir deoutra.

procedure TForm1.Button1Click(Sender: TObject); var

Win : THandle;begin Win := FindWindow(nil,’Form1'); if Win <> 0 then PostMessage(Win,WM_QUIT,0,0) else ShowMessage(‘Programa não encontrado’);

end;

// No exemplo acima foi utilizado oPOSTMESSAGE para enviar uma mensagem WM_CLOSEpara a janela principal.

Dúvida enviada por Gustavo, Vitória – ES

Pergunta: Tenho como fazer uma numeração de página dotipo 1 de 10, onde 10 é a quantidade de páginas do relatório.

Resposta: Você pode fazer este tipo de trabalho, mas eleterá que ser manual. O primeiro passo é pegar o total de páginase jogar para uma variável. Para pegar o total de páginas vocêpode executar o código abaixo antes de chamar o relatório.

QuickRep1.Prepare;TotalPaginas := QuickRep1.PageNumber;

TotalPaginas mostrada anteriormente é uma variável do tipointeiro.

Para mostrar isto no QuickReport você pode utilizar umcomponente QRSysData alterando a propriedade Data paraPageNumber e colocar a rotina a seguinte no evento OnPrint.

procedure TForm1.QRSysData1Print(sender: TObject; var Value: String);

begin Value := Value + ‘/’ +IntToStr(TotalPaginas) end;

Dúvida enviada por Haroldo, Rio de Janeiro - RJ

Pergunta: É possível gerar um documento do WORD apartir de um relatório do QuickReport?

Resposta: Isto é possível de ser feito, mas apenas utilizandocomponentes de terceiros. Para maiores informações veja emwww.waler.com.

Dúvida enviada por Haroldo, Rio de Janeiro - RJ

Pergunta: Gostaria de saber como faço para saber onúmero de registros afetados por um comando update dentro deum programa.

Por exemplo:

Perguntas & Respostas

Page 7: EDITORIAL - The Club · gerar via QUICKREPORT, de preferência, no formato que aparece no PREVIEW. Resposta: ... usando os componentes da paleta indy ? Usando o componente da paleta

7

Q.Active:=False;

Q.Sql.Text:=’update bancodados setcampoA =’B’ where campoA = ‘C’ frombancodados’

Q.ExecSQL;

edit.text:= q.(registros afetados);

Resposta: Isto pode ser feito, pois o componente Query temuma propriedade chamada RowsAffected que retorna aquantidade de linhas afetadas no comando Update.

Dúvida enviada por Celina, Santos - SP

Pergunta: Estou querendo mudar minhas aplicações deDelphi 4 para Delphi 2005 e gostaria de saber se essa migraçãoseria muito complexa, se teria que reescrever todos os programase aprender o Delphi 2005 ou o ambiente é parecido no que dizrespeito a programação win32 e não Web.

Resposta: No que diz respeito a programação Win32, vocênão precisa se preocupar. Os comandos são os mesmos. Oambiente do Delphi 2005 realmente mudou bastante, mas podeter certeza que foi para melhor. O que você deve tomar muitocuidado é em relação aos componentes de terceiros. Se você utilizacomponentes de terceiros verifique se já existem versões destescomponentes para o Delphi 2005.

Dúvida enviada por Junior, São José do Rio Preto – SP

Pergunta: Estou mudando para o Delphi 7 e também estouutilizando o Rave Reports. Como posso configurar o Rave Reportspara que ele abra o preview do relatório final maximizado,ou seja,em tela cheia.

Resposta: Você deve utilizar o componente RVSystem.Neste componente vá até a propriedade SystemPreview e altere asubpropriedade FormState para wsMaximized. Depois disso, váaté o componente RvProject e ligue o componente componenteRvSystem na propriedade Engine.

Dúvida enviada por Edivaldo, RioBranco - AC

Pergunta: Gostaria de saber se é possível alinhar peladireita valores, usando Printer.Canvas.Textout. Se for possível,

como posso fazer isto?

Resposta: Para fazer o controle de posicionamento devalores durante a impressão, faça o seguinte:

uses ......type .....privatepublicend; //Definição da função function Tam_Coluna(coluna:integer;valor:

Double; mascara:string):integer; var Form1: TForm1;implementationUses Printers;procedure .........begin..........{Ao imprimir o valor a ser formatado chame afunção de Tam_Coluna.Esta função vai retornar o numero da colunaonde deverá ser impresso o valor jáformatado.Informe na variavel Coluna o numero da colunaa ser impressa. Na variável Total informevalor a ser impresso. No terceiro parametroda função Tam_Coluna a mascara desejada}

Printer.Canvas.TextOut( Tam_Coluna( Coluna,Total , ‘###,##0.00’ ), Linha,FormatFloat(‘###,##0.00’, Total ) );..........end;function Tam_Coluna( coluna:integer;

valor:Double; mascara:string):integer;var Masc : string; Tam1,Tam2 : integer;begin Masc := FormatFloat(mascara,valor); Tam1 := Printer.Canvas.TextWidth(Masc); Tam2 := Printer.Canvas.TextWidth(mascara); Tam_Coluna := coluna + (Tam2-Tam1);end;

Dúvida enviada por André Junior, São Paulo – SP

Perguntas & Respostas

Page 8: EDITORIAL - The Club · gerar via QUICKREPORT, de preferência, no formato que aparece no PREVIEW. Resposta: ... usando os componentes da paleta indy ? Usando o componente da paleta

8

Pergunta: Eu tenho uma conexão com o Firebird usando aPaleta Interbase. Ou seja, uso os componentes IBDatabase,IBTransaction, IBDataset. Tenho 15 IBDatasets e em todos euadicionei os Fields.

Acontece que quando dou um Open no IBDatabase eledemora cerca de 30 segundos pra abrir, quando não trava. Fizvários testes (faz 2 meses que estou fazendo testes) e descobri queessa demora acontece só no Windows XP.

Agora no Win2000 e Win98 executa em 1 segundo, jáadicionei nas Exceções do Firewall o FBServer e num adiantounada. O que pode ter acontecido ? Será incompatibilidade com oWindows XP?

Resposta: Realmente existe um problema de lentidão. Nosite da Borland existe uma documentação a este respeito. Vocêpode ver no link http://bdn.borland.com/article/0,1410,28142,00.html

Dúvida enviada por Evandro, São Paulo - SP

Pergunta: Fiz um projeto. Para cadastrar grava normal,mas ao fechar o programa as informações que gravei não sãogravadas.

Resposta: Eu suponho que você não esteja trabalhandocom o componente ClienteDataSet e não esteja confirmando agravação do registro. Sendo assim vá até o evento AfterPost docomponente ClientDataSet e inclua o seguinte comando:

ClientDataSet1.ApplyUpdates(-1);

Dúvida enviada por Rui, Paulo Afonso - BA

Pergunta: Tenho um componente TPopupmenu numaclasse ancestral, nesta classe gostaria de implementar umdeterminado código, mas para tanto preciso descobrir em cima deque objeto o menu foi acionado. Como faço isso? Obrigado!

Resposta: Você pode utilizar o seguinte comando.

(PopupMenu1.PopupComponent asTWinControl).Name;

Dúvida enviada por Vicente, Bauru - SP

Pergunta: Como eu posso instalar TeeChart com as novasversões do QuickReport ?

Resposta: Para instalar o Teechart para o QuickReport, váaté o menu do Delphi em Components | Install Packages. Cliqueno botão Add... e localize no subdiretório \Bin do Delphi 7 oarquivo dcltqr70.bpl, clique em Abrir e depois em Ok. Pronto,está instalado.

Dúvida enviada por Dennis, São Paulo - SP

Pergunta: Em uma rede composta de 1 servidor e 2estações, uma das estações leva um tempo considerável para seconectar ao banco de dados no servidor Firebird. A máquina emquestão chegou a ser formatada, mas o problema persiste. Qualpoderia ser o motivo desta anomalia?

Resposta: A primeira conexão infelizmente é um poucolenta, mas existe uma saída neste caso que pode melhorar a suavelocidade. A primeira é na linha de conexão utilizar sempre o IPda máquina e uma outra é localizar um arquivo chamadoHOSTS.

Este arquivo fica no diretórioc:\windows\system32\drivers\etc. Inclua neste arquivo o IP e onome do servidor como está sendo mostrado neste mesmoarquivo.

Dúvida enviada por Paulo, Porto Alegre - RS

Pergunta: Estou tentando compilar a minha aplicação eestou recebendo o erro:

[Fatal Error] Unit StdActns was compiled with a differentversion of StrUtils. TStringSearchOptions

Qual será o motivo deste erro?

Resposta: Por algum motivo o arquivo StrUtils.dcu deve tersido substituído por uma versão mais antiga.

Uma saída é você criar um projeto novo, adicionar o arquivoStrUtils.pas que está no diretório: c:\arquivos de programas\Borland\Delphi7\ Source\Rtl\Common, e compilar o projeto.

Com isto será criado um novo arquivo StrUtils.dcu. Pegueeste novo .DCU e copie para o diretório c:\arquivos deprogramas\Borland\Delphi7\Lib.

Isto resolverá o seu problema.

Dúvida enviada por Áurea, Capivari - SP

Perguntas & Respostas

Page 9: EDITORIAL - The Club · gerar via QUICKREPORT, de preferência, no formato que aparece no PREVIEW. Resposta: ... usando os componentes da paleta indy ? Usando o componente da paleta

9

Por Alexandre Tarifa

WinformsWinformsWinformsWinformsWinformsExpandindo Expandindo Expandindo Expandindo Expandindo controlescontrolescontrolescontrolescontroles

WinformsWinformsWinformsWinformsWinformsExpandindo controlesExpandindo controlesExpandindo controlesExpandindo controlesExpandindo controles

Nem sempre os controles disponíveis pelo Visual Studio nostrazem todas as funcionalidades que necessitamos. Algumasvezes ampliar os recursos dos controles ou até mesmo criar umcontrole em cima de uma já existente pode se tornar um grandenegócio.

Neste artigo estarei mostrando como expandir um controleTextBox criando algumas funcionalidades e propriedades novas.

Criando a aplicaçãoCrie um novo projeto no Visual Studio (File > New > Project),

selecione o project type Visual Basic Project, o template WindowsApplication, nome Controles e clique em OK.

Após a criação da aplicação, vamos adicionar o novo controle.No Solution Explorer , clique com o botão direito do mouse sobre oprojeto Controles, Add, Add New Item. Selecione o templateCustom Control e o nome NovoTextBox.

Uma janela de design é aberta, porém nada é exibido. Nãotemos acesso ao design do TextBox, portanto somente o código éalterado. Para ver o código precione F7.

Nossa primeira implementação no controle será adicionaruma propriedade para definir se o TextBox receberá somentevalores numéricos.

O primeiro passo é alterar no topo do código a herança que éfeita no início do código, devemos alterar InheritsSystem.Windows.Forms.Control para InheritsSystem.Windows.Forms.TextBox. Esta alteração é feita porquevamos ampliar as funcionalidades de um controle específico. Nocaso, um TextBox.

Para criar uma nova propriedade do controle é simples, temosque declarar uma propriedade chamada Numérico do tipo boleano,

Visual Studio

Page 10: EDITORIAL - The Club · gerar via QUICKREPORT, de preferência, no formato que aparece no PREVIEW. Resposta: ... usando os componentes da paleta indy ? Usando o componente da paleta

10

conforme abaixo:

Private _Numerico As Boolean Public Property Numerico() As Boolean Get Return _Numerico End Get Set(ByVal Value As Boolean) _Numerico = Value End Set End Property

O próximo passo é sobrescrever a sub OnKeyPress, conformeabaixo:

Protected Overrides Sub OnKeyPress(ByVal e AsSystem.Windows.Forms.KeyPressEventArgs) If _Numerico = True Then If e.KeyChar >= “0” And

e.KeyChar <= “9” Then e.Handled = False Else e.Handled = True End If End IfEnd Sub

O evento OnKeyPress (quando é digitado algo no TextBox)quando tiver a propriedade Numérico como True, somentecaracteres numéricos são aceitos.

Para testar a aplicação, devemos compilar a aplicação(Ctrl+Shift+B). Abra o Form1, abra a janela ToolBox (Ctrl + Alt+ X), clique com o botão direito do mouse, Add/Remove Items,Browse, selecione o arquivo Controles.exe na pasta Bin do seuprojeto, selecione o NovoTextBox e clique em OK.

Foi adicionado na ToolBox o novo controle, arraste o novocontrole para o formulário. Selecione as propriedades do controle(F4), vá na propriedade Numérico e selecione True. Adicioneoutro NovoTextBox e não altera nenhuma propriedade. Executea aplicação (F5). Teste com letras o primeiro TextBox e note quenenhum caractere é digitado, digite números, e somentenúmeros são adicionados.

Vamos alterar nosso controle, delete toda a implementação doEvento OnKeyPress e a propriedade numérico.

Vamos criar um Enumerador com todas as possibilidades deformatação:

Public Enum TipoFormatacao Nenhum ForCep ForData forTelefone forHora End Enum

Também crie uma nova propriedade que receberá o valor doEnumerador:

Private Formatacao As TipoFormatacao Public Property Formatacao() As TipoFormatacao Get Return _Formatacao End Get Set(ByVal Value As TipoFormatacao) _Formatacao = Value End Set End Property

Vamos novamente redefinir OnKeyPress:

Visual Studio

Page 11: EDITORIAL - The Club · gerar via QUICKREPORT, de preferência, no formato que aparece no PREVIEW. Resposta: ... usando os componentes da paleta indy ? Usando o componente da paleta

11

Protected Overrides Sub OnKeyPress(ByVal e As System.Windows.Forms.

KeyPressEventArgs)

Select Case _Formatacao Case OpcaoFormata.ForCep If Len(Me.Text) = 5 Then Me.Text = Me.Text & “-” Me.SelectionStart =

Len(Me.Text) + 1 Me.MaxLength = 9 End If

Case OpcaoFormata.ForData If Len(Me.Text) = 2 Or

Len(Me.Text) = 5 Then Me.Text = Me.Text & “/” Me.SelectionStart =

Len(Me.Text) + 1 Me.MaxLength = 10 End If

Case OpcaoFormata.forHora If Len(Me.Text) = 2 Then Me.Text = Me.Text & “:” Me.SelectionStart =

Len(Me.Text) + 1 Me.MaxLength = 5 End If

Case OpcaoFormata.forTelefone If Len(Me.Text) = 0 Then Me.Text = Me.Text & “(“ Me.SelectionStart =

Len(Me.Text) + 1 ElseIf Len(Me.Text) = 3 Then Me.Text = Me.Text & “)” Me.SelectionStart =

Len(Me.Text) + 1 ElseIf Len(Me.Text) = 8 Then Me.Text = Me.Text & “-” Me.SelectionStart =

Len(Me.Text) + 1 End If

Me.MaxLength = 13

End Select

End Sub

Selecione as opções diretamente no TextBox e execute oprojeto. Digite os valores e veja que a formatação selecionada éefetuada.

Além dessas implementações podemos criar várias, vai danecessidade que temos. Lembrando também que qualquercontrole pode ter as suas propriedades expandidas.

Se você tem interesse em aprender .net ou discutir .net entreno grupo de usuários Codificando.net - São Paulo.

Abraços.Alexandre TarifaLíder Codificando.net SP

Sobre o autorAlexandre Tarifa - [email protected] palestras e treinamentos, MVP (Most ValuableProfessional), MCAD (Microsoft Certified Application Developer)e MCT (Microsoft Certified Trainer). Bacharel pela UMESP epós-graduando pela Universidade Federal de São Carlos emCiência da Computação. Analista de Sistemas e Líder do grupode usuários Codificando.net São Paulo (sp.codificando.net).Escreve artigos para a revista MSDN Magazine e para os sitesLinha de Código, MSDN Brasil e Enterpriseguys. Visite o blog doautor: http://weblogs.pontonetpt.com/alexandretarifa/.

Agora nosso controle possui uma propriedade chamadaTipoFormatacao onde através de uma combo selecionaremos aopção:

Visual Studio

Page 12: EDITORIAL - The Club · gerar via QUICKREPORT, de preferência, no formato que aparece no PREVIEW. Resposta: ... usando os componentes da paleta indy ? Usando o componente da paleta

12

Validando controles comValidando controles comValidando controles comValidando controles comValidando controles comError ProviderError ProviderError ProviderError ProviderError Provider

A não validação dos dados inseridos por um usuário emqualquer aplicação pode trazer transtornos incalculáveis. Quantoantes estas informações forem validadas o sistema ficará maisrápido, seguro e com menos possibilidade de erros. Muitos errosque ocorrem nas aplicações ocorrem por inconsistência de dados evalidando a logo na entrada de dados faz com que o erro sejaprevisto e a ação que utilizaria a informação seja cancelada antesmesmo da utilização do dado.

Em aplicações que utilizam banco de dados, se nãovalidarmos algumas informações como, por exemplo, uma letratentando ser adicionada em um campo do tipo numérico nossaaplicação perderá performance, pois efetuará uma conexão com obanco de dados, executará o comando e somente quando o bancode dados retornar um erro que a informação será validada.

Na plataforma .net paradesenvolvimento de aplicaçõesWinForms foi criado um controle parafacilitar toda essa validação, chamado:Error Provider.

O Error Provider traz todos osrecursos necessários para a validaçãode uma forma segura e simplificada.Com a utilização deste controlequalquer evento disparado não seráexecutado enquanto todos os camposnão estiverem devidamente corretos.

Para entender melhor a utilizaçãodo controle, criar uma aplicação é aforma mais eficiente. Abra o VisualStudio 2003 (figura 1), selecione emProject Type a linguagem VisualBasic Projects, Templates selecioneWindows Application, name digiteError Provider, selecione um caminhoem Location e clique em OK.

por Alexandre Tarifa

Validando controles comValidando controles comValidando controles comValidando controles comValidando controles comError ProviderError ProviderError ProviderError ProviderError Provider

Figura 1. Criando um novo projeto.

O próximo passo será o design do formulário, utilize oformulário que já vem criado com a aplicação. Altere as seguintespropriedades do Formulário:

Tabela 1. Propriedadesdo formulário

Visual Studio

Page 13: EDITORIAL - The Club · gerar via QUICKREPORT, de preferência, no formato que aparece no PREVIEW. Resposta: ... usando os componentes da paleta indy ? Usando o componente da paleta

13

Adicione no formulário, adicione todos os controles conformea figura 2, e altere as propriedades dos controles conforme atabela 2.

Figura 2. Design do formulário

Com o formulário montado vamos criar toda a validação doformulário utilizando o controle Error Provider. Para adicionaro controle, selecione na ToolBox (figura 3) e de um duplo clique

sobre o controle.

Figura 3. Toolbox

Quando selecionamos o controle ele é adicionado naárea de controles sem interface logo abaixo doformulário, esta área é reservada a controles que nãoserão exibidos diretamente no formulário.

Com o controle adicionado, o Error Provideradiciona algumas novas propriedades nos controlespara efetuar a validação.

A primeira propriedade que vamos alterar será no próprioError Provider, selecione o controle, vá às propriedades (F4) ealtere a propriedade name para errValidacao.

O primeiro controle a ser tratado será o txtNome, serávalidado se existiu ou não a entrada de dados. Selecione no menuView , Code ou precione F7. Na janela de código selecione nascombos superiores txtNome e Validating.

Automaticamente é criado o código do evento, digite oseguinte código:

Private Sub txtNome_Validating(ByVal sender As Object, ByVal e AsSystem.ComponentModel.CancelEventArgs)

Handles txtNome.Validating If txtNome.Text = “” Then errValidacao.SetError(sender,

“Digite um nome”) e.Cancel = True Else errValidacao.SetError(sender, “”) End IfEnd Sub

Visual Studio

Page 14: EDITORIAL - The Club · gerar via QUICKREPORT, de preferência, no formato que aparece no PREVIEW. Resposta: ... usando os componentes da paleta indy ? Usando o componente da paleta

14

Para testar a aplicação, no botão btnOK, adicione o seguintecódigo:

Private Sub btnOK_Click(ByVal sender AsSystem.Object, ByVal e As System.EventArgs)Handles btnOK.Click

MessageBox.Show(“ Nome: “ & txtNome.Text& vbCrLf & _

“ Endereço:“ & txtEndereco.Text & vbCrLf & _“ Bairro: “ & txtBairro.Text & vbCrLf & _“ Cidade: “ & txtCidade.Text & vbCrLf & _“ Estado: “ & cmbEstado.Text & vbCrLf & _“ Email: “ & txtEmail.Text & vbCrLf & _“ Linguagem: “ & lstLinguagem.Text & vbCrLf)

End Sub

Execute a aplicação (F5), o formulário será exibido. Nãopreencha nenhum campo do formulário e clique sobre o botãobtnOK (figura 4).

Figura 4: Execução do exemplo

A vantagem da utilização do Error Provider, é que ele nãodeixa nenhuma funcionalidade ser efetuada enquando um valornão for digitado no TextBox. Todos os controles possuem umapropriedade chamada CausesValidation.

Esta propriedade define se o controle quando tiver algumaação deverá ou não participar da validação, caso esteja comoTrue, o ErrorProvider entra em ação, caso contrário, oErrorProvider é ignorado.

Adicione o código abaixo para complementar com a validaçãodos outros controles:

Private Sub txtEndereco_Validating(ByValsender As Object, ByVal e AsSystem.ComponentModel.CancelEventArgs)

Handles txtEndereco.Validating

If txtEndereco.Text = “” Then errValidacao.SetError(sender, “Digite

um endereço”) e.Cancel = TrueElse errValidacao.SetError(sender, “”)End IfEnd Sub

Private Sub txtBairro_Validating(ByVal sender As Object, ByVal e AsSystem.ComponentModel.CancelEventArgs)

Handles txtBairro.ValidatingIf txtBairro.Text = “” Then errValidacao.SetError(sender, “Digite

um bairro”) e.Cancel = TrueElse errValidacao.SetError(sender, “”)End IfEnd Sub

Private Sub txtCidade_Validating(ByVal sender As Object, ByVal e AsSystem.ComponentModel.CancelEventArgs)

Handles txtCidade.Validating

If txtCidade.Text = “” Then errValidacao.SetError(sender, “Digite

uma Cidade”) e.Cancel = TrueElse errValidacao.SetError(sender, “”)End If

End Sub

Private Sub cmbEstado_Validating(ByVal sender As Object,ByVal e AsSystem.ComponentModel.CancelEventArgs)

Handles cmbEstado.Validating

If cmbEstado.Text = “” Then errValidacao.SetError(sender,

“Selecione um Estado”) e.Cancel = TrueElse errValidacao.SetError(sender, “”)End If

Visual Studio

Page 15: EDITORIAL - The Club · gerar via QUICKREPORT, de preferência, no formato que aparece no PREVIEW. Resposta: ... usando os componentes da paleta indy ? Usando o componente da paleta

15

End SubPrivate Sub txtEmail_Validating(ByVal senderAs Object,ByVal e AsSystem.ComponentModel.CancelEventArgs)Handles txtEmail.ValidatingIf txtEmail.Text = “” Then errValidacao.SetError(sender,

“Digite um Email”) e.Cancel = TrueElse errValidacao.SetError(sender, “”)End IfEnd SubPrivate Sub lstLinguagem_Validating(ByValsender As Object,ByVal e AsSystem.ComponentModel.CancelEventArgs)Handles lstLinguagem.ValidatingIf lstLinguagem.Text = “” Then errValidacao.SetError(sender, “Selecioneuma Linguagem”) e.Cancel = True

Else errValidacao.SetError(sender, “”)End IfEnd Sub

Execute a aplicação e teste todos os controlesindividualmente.

ConclusãoSe desejar validar os campos de forma segura e de rápido

desenvolvimento, utilize o ErrorProvider.

Sobre o autorAlexandre Tarifa - [email protected] palestras e treinamentos, MVP (Most ValuableProfessional), MCAD (Microsoft Certified Application Developer)e MCT (Microsoft Certified Trainer). Bacharel pela UMESP epós-graduando pela Universidade Federal de São Carlos emCiência da Computação. Analista de Sistemas e Líder do grupode usuários Codificando.net São Paulo (sp.codificando.net).Escreve artigos para a revista MSDN Magazine e para os sitesLinha de Código, MSDN Brasil e Enterpriseguys. Visite o blog doautor: http://weblogs.pontonetpt.com/alexandretarifa/.

Visual Studio

Page 16: EDITORIAL - The Club · gerar via QUICKREPORT, de preferência, no formato que aparece no PREVIEW. Resposta: ... usando os componentes da paleta indy ? Usando o componente da paleta

16

Dicas rápidas para Delphi 7Dicas rápidas para Delphi 7Dicas rápidas para Delphi 7Dicas rápidas para Delphi 7Dicas rápidas para Delphi 7

Delphi

Como mostrar Menu Item HintsComo mostrar Menu Item HintsComo mostrar Menu Item HintsComo mostrar Menu Item HintsComo mostrar Menu Item HintsQuando o mouse está sobre um componente (um TButton,

por exemplo) se a propriedade ShowHint é True e se houver algumtexto na propriedade Hint, o hint/tooltip será mostrado para ocomponente.

Hints para itens de menu?Por projeto, mesmo se você colocar algo na propriedade Hint

de um Menu Item o popup hint não será exibido. No entanto, osItens do menu Iniciar do Windows mostram hints, e o menu dosFavoritos do Internet Explorer também.

É comum usar o evento OnHint nas variáveis globais daaplicação, nas aplicações Delphi, para mostrar os hints do menucomo uma barra de status.

O Windows não expõe as mensagens necessárias quesuportem o evento tradicional OnMouseEnter. No entanto, aimplementação do WM_MENUSELECT no TCustomForm(ancestral do TForm) tem o item hint de menu noApplication.Hint que pode ser usado no eventoApplication.OnHint.

Se você quer adicionar itens de menu com popup hints nosmenus de sua aplicação Delphi você precisa “somente” apontar amensagem WM_MenuSelect corretamente.

A classe TMenuItemHint – hints popup para itens de menu!Como não podemos depender do método

Application.ActivateHint para mostrar a janela para os itens demenu (o apontamento de menus é feito totalmente pelo Win-dows), para obter a janela de hint exibida você precisa criar suaprópria versão da janela hint – derivando uma nova classe apartir de THintWindow.

Segue como criar a classe TMenuItemHint – uma janela hintque realmente é exibida nos itens de menu.

Primeiro você precisa apontar a mensagemWM_MENUSELECT do Windows:

typetypetypetypetype TForm1 = classclassclassclassclass(TForm) ... privateprivateprivateprivateprivate procedureprocedureprocedureprocedureprocedure WMMenuSelect(varvarvarvarvar Msg:TWMMenuSelect) ; messagemessagemessagemessagemessage WM_MENUSELECT; endendendendend...implementationimplementationimplementationimplementationimplementation...procedureprocedureprocedureprocedureprocedure TForm1.WMMenuSelect

(varvarvarvarvar Msg: TWMMenuSelect) ;varvarvarvarvar menuItem : TMenuItem; hSubMenu : HMENU;beginbeginbeginbeginbegin inheritedinheritedinheritedinheritedinherited; // from TCustomForm //(so that Application.Hint is assigned)

menuItem := nilnilnilnilnil; ififififif (Msg.MenuFlag <> $FFFF) ororororor

(Msg.IDItem <> 0) thenthenthenthenthen beginbeginbeginbeginbegin ififififif Msg.MenuFlag andandandandand MF_POPUP = MF_POPUPthenthenthenthenthen beginbeginbeginbeginbegin hSubMenu := GetSubMenu

(Msg.Menu, Msg.IDItem) ; menuItem := Self.Menu.FindItem

(hSubMenu, fkHandle) ; endendendendend elseelseelseelseelse beginbeginbeginbeginbegin menuItem := Self.Menu.FindItem

(Msg.IDItem, fkCommand) ; endendendendend; endendendendend; miHint.DoActivateHint(menuItem) ;endendendendend; (*WMMenuSelect*)

Dicas rápidas para Delphi 7Dicas rápidas para Delphi 7Dicas rápidas para Delphi 7Dicas rápidas para Delphi 7Dicas rápidas para Delphi 7

Page 17: EDITORIAL - The Club · gerar via QUICKREPORT, de preferência, no formato que aparece no PREVIEW. Resposta: ... usando os componentes da paleta indy ? Usando o componente da paleta

17

A mensagem WM_MENUSELECT é enviada à janelaproprietária do menu (Form 1) quando o usuário seleciona (nãoquando clica) um item de menu. Usando o método FindItem daclasse TMenu, você consegue pegar o item de menu que estáselecionado no momento. Os parâmetros da função FindItemrelatam as propriedades que a mensagem recebeu. Uma vez quevocê saiba qual o item de menu sobre qual está o mouse,chamaremos o método DoActivateHint da classe TMenuItemHint.Observe que a variável miHint é definida como “var miHint :TMenuItemHint” e é criada no evento OnCreate do Form.

Agora vamos fazer a implementação da classeTMenuItemHint.

Aqui está a parte da interface:

TMenuItemHint = classclassclassclassclass(THintWindow)privateprivateprivateprivateprivate activeMenuItem : TMenuItem; showTimer : TTimer; hideTimer : TTimer; procedureprocedureprocedureprocedureprocedure HideTime(Sender : TObject) ; procedureprocedureprocedureprocedureprocedure ShowTime(Sender : TObject) ;publicpublicpublicpublicpublic constructorconstructorconstructorconstructorconstructor Create

(AOwner : TComponent) ; overrideoverrideoverrideoverrideoverride; procedureprocedureprocedureprocedureprocedure DoActivateHint

(menuItem : TMenuItem) ; destructordestructordestructordestructordestructor Destroy; overrideoverrideoverrideoverrideoverride;

endendendendend;

Você pode ver toda a implementação no projeto exemplo.Basicamente, a função DoActivateHint chama o método

ActivateHint do THintWindow usando a propriedade Hint doTMenuItem (se estiver atribuída).

O showTimer é usado para se ter certeza que o HintPause (doApplication) transcorre antes do hint ser mostrado.

O hideTimer usa o Application.HintHidePause para esconder ajanela do hint após um intervalo específico.

Quando usar os hints nos itens do menu?Enquanto alguns podem dizer que não é uma boa coisa

mostrar hints nos itens de menu, há situações que mostrar hintsno menu é muito melhor do que mostrar uma barra de status.

Segue o código fonte do Form, com a implementação da classeTMenuItemHint.

unitunitunitunitunit Unit1;

interfaceinterfaceinterfaceinterfaceinterface

usesusesusesusesusesWindows, Messages, SysUtils, Variants,Classes, Graphics, Controls, Forms,Dialogs, Menus, AppEvnts, StdCtrls,ExtCtrls, ComCtrls;

typetypetypetypetype TMenuItemHint = classclassclassclassclass(THintWindow) privateprivateprivateprivateprivate activeMenuItem : TMenuItem; showTimer : TTimer; hideTimer : TTimer; procedureprocedureprocedureprocedureprocedure HideTime(Sender : TObject) ; procedureprocedureprocedureprocedureprocedure ShowTime(Sender : TObject) ; publicpublicpublicpublicpublic constructorconstructorconstructorconstructorconstructor Create

(AOwner : TComponent) ; overrideoverrideoverrideoverrideoverride; procedureprocedureprocedureprocedureprocedure DoActivateHint

(menuItem : TMenuItem) ; destructordestructordestructordestructordestructor Destroy; overrideoverrideoverrideoverrideoverride; endendendendend;

TForm1 = classclassclassclassclass(TForm)... procedureprocedureprocedureprocedureprocedure FormCreate(Sender: TObject) ; procedureprocedureprocedureprocedureprocedure ApplicationEvents1Hint

(Sender: TObject) ; privateprivateprivateprivateprivate miHint : TMenuItemHint; procedureprocedureprocedureprocedureprocedure WMMenuSelect

(varvarvarvarvar Msg: TWMMenuSelect) ;messagemessagemessagemessagemessage WM_MENUSELECT;

endendendendend;

varvarvarvarvar Form1: TForm1;

implementationimplementationimplementationimplementationimplementation{$R *.dfm}

procedureprocedureprocedureprocedureprocedure TForm1.FormCreate(Sender: TObject) ;

beginbeginbeginbeginbegin miHint := TMenuItemHint.Create(self) ;endendendendend; (*FormCreate*)

Delphi

Page 18: EDITORIAL - The Club · gerar via QUICKREPORT, de preferência, no formato que aparece no PREVIEW. Resposta: ... usando os componentes da paleta indy ? Usando o componente da paleta

18

procedureprocedureprocedureprocedureprocedure TForm1.ApplicationEvents1Hint(Sender: TObject) ;

beginbeginbeginbeginbegin StatusBar1.SimpleText := ‘App.OnHint :

‘ + Application.Hint;endendendendend; (*Application.OnHint*)

procedureprocedureprocedureprocedureprocedure TForm1.WMMenuSelect(var Msg: TWMMenuSelect) ;

varvarvarvarvar menuItem : TMenuItem; hSubMenu : HMENU;beginbeginbeginbeginbegin inheritedinheritedinheritedinheritedinherited; // TCustomForm

// (se certifica que o Application.Hint// é atribuído)

menuItem := nilnilnilnilnil; ififififif (Msg.MenuFlag <> $FFFF) ororororor (Msg.IDItem<> 0) thenthenthenthenthen beginbeginbeginbeginbegin ififififif Msg.MenuFlag andandandandand MF_POPUP = MF_POPUPthenthenthenthenthen beginbeginbeginbeginbegin hSubMenu := GetSubMenu

(Msg.Menu, Msg.IDItem) ; menuItem := Self.Menu.FindItem

(hSubMenu, fkHandle) ; endendendendend elseelseelseelseelse beginbeginbeginbeginbegin menuItem := Self.Menu.FindItem

(Msg.IDItem, fkCommand) ; endendendendend; endendendendend;

miHint.DoActivateHint(menuItem) ;endendendendend; (*WMMenuSelect*)

{ TMenuItemHint }constructorconstructorconstructorconstructorconstructor TMenuItemHint.Create

(AOwner: TComponent) ;beginbeginbeginbeginbegin inheritedinheritedinheritedinheritedinherited;

showTimer := TTimer.Create(self) ; showTimer.Interval := Application.

HintPause;

hideTimer := TTimer.Create(self) ; hideTimer.Interval := Application.

HintHidePause;endendendendend; (*Create*)

destructordestructordestructordestructordestructor TMenuItemHint.Destroy;beginbeginbeginbeginbegin hideTimer.OnTimer := nilnilnilnilnil; showTimer.OnTimer := nilnilnilnilnil; self.ReleaseHandle; inheritedinheritedinheritedinheritedinherited;endendendendend; (*Destroy*)

procedureprocedureprocedureprocedureprocedure TMenuItemHint.DoActivateHint(menuItem: TMenuItem) ;

beginbeginbeginbeginbegin //força a remoção da velha janela //do hint hideTime(self) ;

ififififif (menuItem = nilnilnilnilnil) ororororor(menuItem.Hint = ‘’) thenthenthenthenthen

beginbeginbeginbeginbegin activeMenuItem := nilnilnilnilnil; Exit; endendendendend;

activeMenuItem := menuItem;

showTimer.OnTimer := ShowTime; hideTimer.OnTimer := HideTime;endendendendend; (*DoActivateHint*)

procedureprocedureprocedureprocedureprocedure TMenuItemHint.ShowTime(Sender: TObject) ;

varvarvarvarvar r : TRect; wdth : integer; hght : integer;beginbeginbeginbeginbegin ififififif activeMenuItem <> nilnilnilnilnil thenthenthenthenthen beginbeginbeginbeginbegin //position and resize wdth := Canvas.TextWidth

(activeMenuItem.Hint) ; hght := Canvas.TextHeight

(activeMenuItem.Hint) ;

r.Left := Mouse.CursorPos.X + 16;

Delphi

Page 19: EDITORIAL - The Club · gerar via QUICKREPORT, de preferência, no formato que aparece no PREVIEW. Resposta: ... usando os componentes da paleta indy ? Usando o componente da paleta

19

Delphi

r.Top := Mouse.CursorPos.Y + 16;

r.Right := r.Left + wdth + 6; r.Bottom := r.Top + hght + 4;

ActivateHint(r,activeMenuItem.Hint) ; endendendendend;

showTimer.OnTimer := nilnilnilnilnil;endendendendend; (*ShowTime*)

procedureprocedureprocedureprocedureprocedure TMenuItemHint.HideTime(Sender:TObject) ;beginbeginbeginbeginbegin //esconde (destroy) a janela hint self.ReleaseHandle; hideTimer.OnTimer := nilnilnilnilnil;endendendendend; (*HideTime*)

end

Overwrite no TMemo e TEditOverwrite no TMemo e TEditOverwrite no TMemo e TEditOverwrite no TMemo e TEditOverwrite no TMemo e TEditOs controles do Windows TMemo e TEdit não têm a

capacidade overwrite. No entanto, é possível simular estecomportamento, ajustanto a propriedade SelLength do controleedit ou memo durante o processamento do evento KeyPress. Issofaz com que o caractere que está na posição corrente sejasobrescrito.

O exemplo a seguir mostra como emular a capacidade deoverwrite de um componente TMemo. O estado do modo desobrescrever pode ser mudado pressionando a tecla Insert.

type TForm1 = class(TForm) Memo1: TMemo; procedure Memo1KeyDown (Sender: TObject; var Key: Word; Shift: TShiftState) ; procedure Memo1KeyPress (Sender: TObject; var Key: Char) ; private { Private declarations } InsertOn : bool; public { Public declarations } end;

var

Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Memo1KeyDown(Sender: TObject; var Key: Word; Shift:TShiftState) ;begin if (Key = VK_INSERT) and (Shift = []) then InsertOn := not InsertOn;end;

procedure TForm1.Memo1KeyPress (Sender: TObject; var Key: Char) ;begin if ((Memo1.SelLength = 0) and (not InsertOn)) then Memo1.SelLength := 1;end;

Algumas vezes precisamos limpar todos os componentes Editque estão no Form. Esta tarefa é feita facilmente com o seguinteprocedimento:

procedure ClearEdits; var j : Integer;beginfor j := 0 to ComponentCount-1 do if (Components[j] is TEdit) then (Components[j] as TEdit).Text := ‘’;end;

Como chamar o “Ver fonte (view source)”Como chamar o “Ver fonte (view source)”Como chamar o “Ver fonte (view source)”Como chamar o “Ver fonte (view source)”Como chamar o “Ver fonte (view source)”em um WebBrowserem um WebBrowserem um WebBrowserem um WebBrowserem um WebBrowser

Aqui está como chamar o Ver fonte do IE (para examinar oHTML) com o componente TWebBrowser.

Simplesmente arraste uma instância do componenteTWebBrowser em um formulário e um botão (Button) e façacomo segue:

uses ActiveX;procedure WBViewSourceDialog

(AWebBrowser: TWebbrowser) ;

Page 20: EDITORIAL - The Club · gerar via QUICKREPORT, de preferência, no formato que aparece no PREVIEW. Resposta: ... usando os componentes da paleta indy ? Usando o componente da paleta

20

Delphi

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 AWebBrowser.Document <> nil then try AWebBrowser.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;

procedure TForm1.FormCreate(Sender: TObject);

begin WebBrowser1.Navigate

(‘http://www.delphi.about.com’) ;end;

procedure TForm1.Button1Click(Sender: TObject) ;

begin WBViewSourceDialog(WebBrowser1) ;end;

MessageBox com timeoutMessageBox com timeoutMessageBox com timeoutMessageBox com timeoutMessageBox com timeoutAqui está como chamar um Message Box com timeout, ele irá

fechar a si mesmo após um período de tempo. O truque é chamaruma API não documentada localizada no user32.dll, a API é aMessageBoxTimeOut.

A função retorna um valor inteiro para MB_TIMEDOUT(indicando que o período de tempo para o timeout foi alcançado eo Message Box foi automaticamente fechado), ou um valorrepresentando o botão que o usuário clicou. Observe que o valorretornado é sempre 1, quando o Message Box tem somente umbotão de OK (MB_OKFlag).

//declaração de interfaceconst MB_TIMEDOUT = 32000;

function MessageBoxTimeOut(hWnd: HWND; lpText: PChar; lpCaption:PChar; uType: UINT; wLanguageId: WORD;dwMilliseconds: DWORD): Integer; stdcall;external user32 name‘MessageBoxTimeoutA’;

//implementação (Apontamento do evento//OnClick do Button1 no Form1)

procedure TForm1.Button1Click(Sender: TObject) ;

var iRet: Integer; iFlags: Integer;begin iFlags := MB_OK or MB_SETFOREGROUND or

MB_SYSTEMMODAL or MB_ICONINFORMATION; MessageBoxTimeout

(Application.Handle, ‘Test a timeoutof 2 seconds.’, ‘MessageBoxTimeoutTeste’, iFlags, 0, 2000) ;

iFlags := MB_YESNO or MB_SETFOREGROUND orMB_SYSTEMMODAL or MB_ICONINFORMATION;

iRet := MessageBoxTimeout(Application.Handle, ‘Teste de timeoutde 5 segundos.’, ‘MessageBoxTimeoutTeste’, iFlags, 0, 5000) ;

case iRet of IDYES: ShowMessage(‘Yes’) ; IDNO: ShowMessage(‘No’) ; MB_TIMEDOUT: ShowMessage(‘TimedOut’) ; end;end;

Page 21: EDITORIAL - The Club · gerar via QUICKREPORT, de preferência, no formato que aparece no PREVIEW. Resposta: ... usando os componentes da paleta indy ? Usando o componente da paleta

21

Delphi

Como colocar uma barra de progressoComo colocar uma barra de progressoComo colocar uma barra de progressoComo colocar uma barra de progressoComo colocar uma barra de progressodentro de um dialog box padrãodentro de um dialog box padrãodentro de um dialog box padrãodentro de um dialog box padrãodentro de um dialog box padrão

Vamos dizer que você tem um dialog box padrão do Windowsmostrando uma pergunta ao usuário com os botões de “Yes” e“No”. Não seria ótimo se existisse uma barra de progressocontando o tempo até que o dialog box se feche automaticamente?

Vamos lá então:Vamos criar um dialog usando CreateMessageDialog. Esta

função retornará um form object com o dialog. Neste objetopodemos adicionar a barra de progresso. Também podemosadicionar um objeto Timer para uma atualização dinâmica daposição da barra de progresso. Mostramos o dialog comShowModal. Apontamos o evento OnTimer do componenteTTimer para ver o número se passou a quantidade de segundosnecessária, se sim, fechamos o dialog ajustando a propriedadeModalResult, no código, para mrCancel. Se não, usamos StepItpara atualizar a barra de progresso.

Coloque um botão no formulário e tente este código:

procedure TForm1.Button1Click(Sender: TObject) ;

var AMsgDialog : TForm; AProgressBar : TProgressBar; ATimer : TTimer;begin AMsgDialog :=CreateMessageDialog(‘Quickly! Answer Yes or

No!’, mtWarning, [mbYes, mbNo]) ; AProgressBar := TProgressBar.

Create(AMsgDialog) ; ATimer := TTimer.Create(AMsgDialog) ; with AMsgDialog do try Tag := 10; //seconds!

Caption := ‘You have 10 seconds’; Height := 150;

with AProgressBar do begin Name := ‘Progress’; Parent := AMsgDialog; Max := AMsgDialog.Tag; //seconds Step := 1; Top := 100; Left := 8; Width := AMsgDialog.ClientWidth - 16; end;

with ATimer do begin Interval := 1000; OnTimer:=DialogTimer; end;

case ShowModal of ID_YES: ShowMessage(‘Answered “Yes”.’) ; ID_NO: ShowMessage(‘Answered “No”.’) ; ID_CANCEL: ShowMessage(‘Time up!’) end;//case finally ATimer.OnTimer := nil; Free; end;end;

//make sure you add this function’s//header in the private part of the TForm1//type declaration.procedure TForm1.DialogTimer(Sender:TObject);var aPB : TProgressBar;begin if NOT (Sender is TTimer) then Exit;

if ((Sender as TTimer).Owner) is TFormthen with ((Sender as TTimer).Owner) as TFormdo begin aPB := TProgressBar

(FindComponent(‘Progress’)) ;

if aPB.Position >= aPB.Max then ModalResult := mrCancel else aPB.StepIt; end;end;

Como imprimir uma página/documento comComo imprimir uma página/documento comComo imprimir uma página/documento comComo imprimir uma página/documento comComo imprimir uma página/documento como TWebBrowsero TWebBrowsero TWebBrowsero TWebBrowsero TWebBrowser

Você primeiro precisa carregar uma página noTWebBrowser, por exemplo (supondo que você tem umcomponente chamado WebBroser1):WebBrowser1.Navigate(‘http://www.theclub.com.br’);

Page 22: EDITORIAL - The Club · gerar via QUICKREPORT, de preferência, no formato que aparece no PREVIEW. Resposta: ... usando os componentes da paleta indy ? Usando o componente da paleta

22

Delphi

// impressão sem aparecer um dialogprocedure WBPrintNoDialog(WB: TWebBrowser) ;var vIn, vOut: OleVariant;begin WB.ControlInterface.ExecWB

(OLECMDID_PRINT,OLECMDEXECOPT_DONTPROMPTUSER,vIn, vOut) ;

end;

//com chamada do dialogprocedure WBPrintWithDialog(WB: TWebBrowser);var vIn, vOut: OleVariant;begin WB.ControlInterface.ExecWB(OLECMDID_PRINT,

OLECMDEXECOPT_PROMPTUSER, vIn, vOut) ;end;// Preview de impressãoprocedure WBPrintPreview(WB: TWebBrowser) ;var vIn, vOut: OleVariant;begin WB.ControlInterface.ExecWB(OLECMDID_PRINTPREVIEW, OLECMDEXECOPT_DONTPROMPTUSER, vIn, vOut);end;

//Chama o dialog de setup de páginaprocedure WBPrintPageSetup(WB: TWebBrowser) ;var vIn, vOut: OleVariant;begin WB.ControlInterface.ExecWB(OLECMDID_PAGESETUP,

OLECMDEXECOPT_PROMPTUSER, vIn, vOut) ;end;

Como fazer um search e replace numComo fazer um search e replace numComo fazer um search e replace numComo fazer um search e replace numComo fazer um search e replace numR i c h E d i tR i c h E d i tR i c h E d i tR i c h E d i tR i c h E d i t

O código abaixo procurará por uma string e a substituirá.Tenha certeza que você tem o RichEdit1 em seu Form1.

procedure TForm1.RearchAndReplace (InSearch, InReplace: string) ;var X, ToEnd : integer;

oldCursor : TCursor;begin oldCursor := Screen.Cursor; Screen.Cursor := crHourglass; with RichEdit1 do begin X := 0; ToEnd := length(Text) ; X := FindText(inSearch, X, ToEnd, []) ; while X <> -1 do begin SetFocus; SelStart := X; SelLength := length(inSearch) ; SelText := InReplace; X := FindText(inSearch, X + length(InReplace), ToEnd, []) ; end; end; Screen.Cursor := oldCursor;end;

procedure TForm1.Button1Click(Sender: TObject) ;

var SearchText, ReplaceText: string;begin SearchText := ‘Pascal’; ReplaceText := ‘Delphi’; RearchAndReplace(SearchText, ReplaceText);end;

Como esconder o text cursor dentro de umComo esconder o text cursor dentro de umComo esconder o text cursor dentro de umComo esconder o text cursor dentro de umComo esconder o text cursor dentro de umT M e m oT M e m oT M e m oT M e m oT M e m o

Aqui está um código exemplo de como esconder o text cursorno Memo1 dentro do Form1.

Substitua todo o código pelo que segue abaixo:

unit Unit1;

interface

usesWindows, Messages, SysUtils, Classes,Graphics, Controls, Forms, Dialogs,StdCtrls, ComCtrls, ExtCtrls;

Page 23: EDITORIAL - The Club · gerar via QUICKREPORT, de preferência, no formato que aparece no PREVIEW. Resposta: ... usando os componentes da paleta indy ? Usando o componente da paleta

23

Delphi

const WM_MYMEMO_ENTER = WM_USER + 500;

type TForm1 = class(TForm) Memo1: TMemo; procedure Memo1Enter(Sender: TObject) ; procedure Memo1Exit(Sender: TObject) ; procedure Memo1Change(Sender: TObject); private public procedure WMMYMEMOENTER

(var Message: TMessage) ; message WM_MYMEMO_ENTER; end;

var Form1: TForm1;

implementation{$R *.DFM}

procedure TForm1.WMMYMEMOENTER(var Message: TMessage) ;

begin CreateCaret(Memo1.Handle,0,0,0) ;end;

procedure TForm1.Memo1Enter(Sender: TObject);begin PostMessage

(Handle, WM_MYMEMO_ENTER, 0, 0);end;

procedure TForm1.Memo1Exit(Sender: TObject);begin CreateCaret(Memo1.handle,1,1,1) ;end;

procedure TForm1.MemoChange(Sender: TObject);begin CreateCaret(Memo1.handle,0,0,0) ;end;end.

Como determinar a posição do cursorComo determinar a posição do cursorComo determinar a posição do cursorComo determinar a posição do cursorComo determinar a posição do cursordentro de um TRichEditdentro de um TRichEditdentro de um TRichEditdentro de um TRichEditdentro de um TRichEdit

Veja o exemplo:

{Usage:

var sRC:string;

src := GetPosition(RichEdit1) ;//src reults in a string//formated like: Row:Col}

function GetPosition(ARichEdit: TRichEdit): string

var iX,iY : Integer;begin iX := 0; iY := 0; iY := SendMessage(ARichEdit.Handle, EM_LINEFROMCHAR,ARichEdit.SelStart,0) ; iX := ARichEdit.SelStart - SendMessage(ARichEdit.Handle, EM_LINEINDEX, iY, 0) ;

Result := IntToStr(iY + 1) + ‘:’ +IntToStr(iX + 1) ;end;

Como completer strings parciais digitadasComo completer strings parciais digitadasComo completer strings parciais digitadasComo completer strings parciais digitadasComo completer strings parciais digitadasdentro de um Combo Boxdentro de um Combo Boxdentro de um Combo Boxdentro de um Combo Boxdentro de um Combo Box

O exemplo abaixo mostra como completar strings parciaisdigitadas dentro de um combo box. O código representa oapontamento do evento OnKeyPress do combo box, que faz aexecução padrão das teclas antes de encontrar o item na listacorrespondente e atualizar o texto.

Observação: O evento OnKeyPress não faz nada quando ousuário pressiona Delete. Neste caso deve-se capturar a teclautilizando-se o evento OnKeyDown.

procedure TForm1.ComboBox1KeyPress(Sender:TObject; var Key: Char) ;var Found: boolean; j,SelSt: Integer; TmpStr: string;begin { primeiro, processe a tecla para obter

a string corrente }

Page 24: EDITORIAL - The Club · gerar via QUICKREPORT, de preferência, no formato que aparece no PREVIEW. Resposta: ... usando os componentes da paleta indy ? Usando o componente da paleta

24

{ Este código requer que todos os itensestejam listados em uppercase}

if Key in [‘a’..’z’] then Dec(Key,32) ;{Somente Uppercase!}

with (Sender as TComboBox) do begin SelSt := SelStart; if (Key = Chr(vk_Back)) and

(SelLength <> 0) then TmpStr := Copy(Text,1,SelStart)+Copy

(Text,SelLength+SelStart+1,255)

else if Key = Chr(vk_Back) then{SelLength = 0}

TmpStr := Copy(Text,1,SelStart-1)+Copy(Text,SelStart+1,255)

else {Key in [‘A’..’Z’, etc]} TmpStr :=

Copy(Text,1,SelStart)+Key+Copy(Text,SelLength+SelStart+1,255) ;

if TmpStr = ‘’ then Exit; { atualize SelSt para a posição

corrente de inserção }

if (Key = Chr(vk_Back)) and (SelSt > 0)then Dec(SelSt)

else if Key <> Chr(vk_Back) thenInc(SelSt) ;

Key := #0; { indica qual tecla foiapontada }

if SelSt = 0 then begin Text:= ‘’; Exit; end;

{Agora que TmpStr é a string sendodigitada no momento, veremos se conseguimosencontrar uma correspondência }

Found := False; for j := 1 to Items.Count do if Copy(Items[j-1],1,Length(TmpStr)) =

TmpStr then begin Text := Items[j-1]; { atualize para a

correspondente que foi encontrada} ItemIndex := j-1;

Found := True; Break; end; if Found then { selecione o final não

digitado da string } begin SelStart := SelSt; SelLength := Length(Text)-SelSt; end else Beep; end;end;

Como ordenar os itens de um objeto TListComo ordenar os itens de um objeto TListComo ordenar os itens de um objeto TListComo ordenar os itens de um objeto TListComo ordenar os itens de um objeto TListQuando você está trabalhando com um objeto TList e quer

ordenar os itens baseados um critério seu, pode usar o códigoabaixo.

O exemplo a seguir mostra como ordenar os itens em ordemalfabética baseado nos nomes. Ele assume que a lista contémapenas referências para as variáveis do tipo TMyListItem, ondeTMyListItem é definida como:

type TMyListItem = record Points : Integer; Name: string[255] ; end;

A função CompareNames faz as comparações entre os objetosda lista. A lista é ordenada quando o usuário clicar no botão.

function CompareNames(Item1, Item2: Pointer): Integer;

begin Result := CompareText((Item1 asTMyListItem).Name, (Item2 asTMyListItem).Name) ;end;

procedure TForm1.Button1Click(Sender: TObject) ;

begin List1.Sort(@CompareNames) ;end;

Delphi

Page 25: EDITORIAL - The Club · gerar via QUICKREPORT, de preferência, no formato que aparece no PREVIEW. Resposta: ... usando os componentes da paleta indy ? Usando o componente da paleta

25

{Note: the Sort method needs a pointer to

a custom function (with the signature below)that indicates how the items are to beordered.

type TListSortCompare = function (Item1, Item2: Pointer): Integer;

Your sorting / comparison function shouldreturna positive value if Item1 is less than Item2,0 if they are equal, and a negative valueif Item1 is greater than Item2.}

Como mostrar os números de semana emComo mostrar os números de semana emComo mostrar os números de semana emComo mostrar os números de semana emComo mostrar os números de semana emum TDateTimePickerum TDateTimePickerum TDateTimePickerum TDateTimePickerum TDateTimePicker

Se você quer que seu TDateTimeCalendar mostre o númerode semanas quando o calendário é acionado, coloque este códigono evento OnDropDown:

uses CommCtrl;

//interface

type THackCommonCalendar =

class(TCommonCalendar) ;

//implementação

procedure TForm1.DateTimePicker1DropDown(Sender: TObject) ;

var Style: Integer; ReqRect: TRect; MaxTodayWidth: Integer;begin with THackCommonCalendar

(Sender as TDateTimePicker) do begin Style := GetWindowLong

(CalendarHandle, GWL_STYLE) ;

SetWindowLong(CalendarHandle, GWL_STYLE,

Style or MCS_WEEKNUMBERS); FillChar(ReqRect, SizeOf(TRect), 0) ; Win32Check(MonthCal_GetMinReqRect

(CalendarHandle, ReqRect)) ; MaxTodayWidth :=

MonthCal_GetMaxTodayWidth( CalendarHandle) ;

if MaxTodayWidth > ReqRect.Right thenReqRect.Right := MaxTodayWidth;

SetWindowPos(CalendarHandle, 0, 0, 0, ReqRect.Right, ReqRect.Bottom,SWP_NOACTIVATE or SWP_NOMOVE orSWP_NOZORDER) ;

end;end;

Como arredondar os cantos dos controlesComo arredondar os cantos dos controlesComo arredondar os cantos dos controlesComo arredondar os cantos dos controlesComo arredondar os cantos dos controlesAqui está como desenhar controles com os cantos

arredondados.Para testar, arraste um TEdit, TPanel e TMemo em um

formulário.

procedure DrawRounded(Control: TWinControl) ;var R: TRect; Rgn: HRGN;begin with Control do begin R := ClientRect; rgn := CreateRoundRectRgn(R.Left,

R.Top, R.Right, R.Bottom, 20, 20); Perform(EM_GETRECT, 0, lParam(@r)) ; InflateRect(r, - 4, - 4) ; Perform(EM_SETRECTNP, 0, lParam(@r)) ; SetWindowRgn(Handle, rgn, True) ; Invalidate; end;end;

procedure TForm1.FormCreate(Sender: TObject);begin // arredondando o Panel1 DrawRounded(Panel1) ;

// arredondando o Memo1

Delphi

Page 26: EDITORIAL - The Club · gerar via QUICKREPORT, de preferência, no formato que aparece no PREVIEW. Resposta: ... usando os componentes da paleta indy ? Usando o componente da paleta

26

Delphi

Memo1.BorderStyle := bsNone; DrawRounded(Memo1) ;

// arredondando o Edit1 Edit1.BorderStyle := bsNone; DrawRounded(Edit1) ;

end;

Usando as setas do teclado para se moverUsando as setas do teclado para se moverUsando as setas do teclado para se moverUsando as setas do teclado para se moverUsando as setas do teclado para se moverentre os controlesentre os controlesentre os controlesentre os controlesentre os controles

As teclas Up e Down são virtualmente inúteis em controlesEdit. Então, porque não usá-las para navegar entre os controles?Se você ajustar a propriedade KeyPreview de um form para Truevocê pode usar o seguinte código no seu evento OnKeyDown doformulário para controlar a navegação:

procedure TForm1.FormKeyDown( Sender : TObject; var Key: Word; Shift : TShiftState ) ;

var Direction : Integer;

begin Direction := -1; case Key of VK_DOWN, VK_RETURN : Direction := 0;

{Next} VK_UP : Direction := 1; {Previous} end; if Direction <> -1 then begin Perform(WM_NEXTDLGCTL, Direction, 0) ; Key := 0; end;

end;

Qual é a palavra sob o cursor do mouse emQual é a palavra sob o cursor do mouse emQual é a palavra sob o cursor do mouse emQual é a palavra sob o cursor do mouse emQual é a palavra sob o cursor do mouse emum TRichEdit?um TRichEdit?um TRichEdit?um TRichEdit?um TRichEdit?

Aqui está o código para você saber qual a palavra que estásob o cursor do mouse.

A variável string WordInRE conterá a palavra.Observação:Você precisará de um TRichEdit (RichEdit1), um form

(Form1), e o código abaixo no evento OnMouseMove doRichEdit1.

uses RichEdit;

var WordInRE : string;

procedure TForm1.RichEdit1MouseMove (Sender: TObject; Shift: TShiftState;

X, Y: Integer) ;

var ci, lix, co, k, j: Integer; Pt: TPoint; s: string;

begin with TRichEdit(Sender) do begin Pt := Point(X, Y) ; ci := Perform(Messages.

EM_CHARFROMPOS, 0, Integer(@Pt)) ; if ci < 0 then Exit; lix := Perform

(EM_EXLINEFROMCHAR, 0, ci); co := ci - Perform

(EM_LINEINDEX, lix, 0) ; if -1 + Lines.Count < lix then Exit; s := Lines[lix]; Inc(co) ;

k := co; while (k > 0) and (s[k] <> ‘ ‘) do

k:=k-1; Inc(co) ;

j := co; while (j <= Length(s)) and

(s[j] <> ‘ ‘) do Inc(j) ; WordInRE := Copy(s, k, j - i) ;

end;

end;

Page 27: EDITORIAL - The Club · gerar via QUICKREPORT, de preferência, no formato que aparece no PREVIEW. Resposta: ... usando os componentes da paleta indy ? Usando o componente da paleta

27

Novas característicasNovas característicasNovas característicasNovas característicasNovas característicasdo Delphi 2006do Delphi 2006do Delphi 2006do Delphi 2006do Delphi 2006

- Maior espaço para memorizarA memória controla novos suportes de inserção no espaço

aumentado para 2GB(até 4GB).

- Alinhamento Melhorado do BlocoOs blocos retornam pelo gerenciador de memória sempre no

limite de 8 bytes, o alinhamento de 16 bytes pode ser forçadoexecutando o seguinte código:SetMinimumBlockAlignment(mba16Byte);

- Realocação InteligenteA realocação é controlada inteligentemente. O novo gerente

de memória tenta evitar os blocos moveis a menos que taloperação seja compensada.

- Melhorando o Travamento ParticionadoO travamento particionado é menor comparado ao previews

do gerenciador de memória, então ele criará uma aplicação emmulti - camada intensiva e observar uma melhora significativano desempenho.

- O Comportamento Melhorado da FragmentaçãoDevido à melhora do gerenciamento da estrutura interna, a

fragmentação do endereço causa um problema menor do que opreviews do gerenciador de memória.

- Gerenciamento de Memória com um SimplesMecanismo de Compartilhamento

No novo gerente da memória foi introduzido um mecanismode compartilhamento para evitar a necessidade de uma bibliotecaborlndmm.dll, embora o método antigo ainda seja suportado. (EmSimpleShareMem.pas há uma unit com os detalhes).

- Reportando as Perda de MemóriaPermite que as aplicações registrem (e excluam registros)

prevendo as perdas da memória e pode opcionalmente retratar asperdas inesperadas na espera do programa.

- Reportando o Estado ProlongadoO novo gerente de memória tem como relatar as funções do

estado prolongado permitindo os intervalos de inserção nosespaços usados das categorias do bloco, satisfatoriamente eeficiência do gerente de memória (Eficiência é medida pelaporcentagem de alocação dos endereços nos espaços desperdiçadosdevido à gerência dos blocos, estruturas e fragmentação).

- Especificando o Alinhamento Mínimo do BlocoO alinhamento mínimo do bloco que retorna para o gerente

de memória é 8bytes. No curso da implementação, todas ospedidos alinhados dos blocos menores que 8bytes serão menorque 16bytes. Para executar 16bytes em todos os alinhamentosdas novas alocações, executeSetMinimumBlockAlignment(mba16byte). Para restaurar os8bytes omitidos, executarSetMinimumBlockAlignment(mba8Byte).

- Habilitando um Endereço de Espaço Maior que

2GBEstes são três pré-requisitos para utilizar um endereço com

espaço maior do que 2gb - Operando Sistema SustentadoUm versão do windows que sustenta um usuário com

endereço em modo maior do que 2GB é requerido. Estandocorretamente qualquer uma das edições windows x64 ou 32-bitwindows XP/2003 com os 3GB acertando a opção no arquivoboot.ini.

- Diretório Apropriado para o LinkO IMAGE_FILE_LARGE_ADRESS_AWARE, um flag obriga

mostrar no cabeçalho do arquivo EXE para informar o windows

Novas característicasNovas característicasNovas característicasNovas característicasNovas característicasdo Delphi 2006do Delphi 2006do Delphi 2006do Delphi 2006do Delphi 2006

Delphi

Page 28: EDITORIAL - The Club · gerar via QUICKREPORT, de preferência, no formato que aparece no PREVIEW. Resposta: ... usando os componentes da paleta indy ? Usando o componente da paleta

28

do suporte da aplicação num endereço com espaço maior que2GB. Este flag pode especificar acertando o {$SetPEFlagsIMAGE_FILE_LARGE_ADDRESS_AWARE} direto do arquivoproject’s .dpr.

- Componentes e BibliotecaTodas as bibliotecas e componentes dão suporte nos endereços

de grande capacidade. Com os endereços de 2GB os elevados bitsão sempre apontados como ‘0’. Então um endereço de grandeespaço poderá ariscar apontar bugs aritméticos que não mostrapreviamente algum sintoma.

Tanto bugs são tipicamente causadas por typecastingapontados para integers no lugar de cardinals quando apontandoalgum bug aritmético e/ou similaridade.

- Relatando Perda de MemóriaUm novo gerente de memória tem a habilidade para relatar

todos os blocos da memória que não tem alimentado antes daespera do programa.

Pode haver exemplos nos blocos de memória e está perdido,sendo a finalidade particular de se relatar será suprida. Paraessa finalidade há uma função chamadaRegisterExpectedMemoryLeak, que busca por parâmetros deponteiros dos blocos perdidos.

Perdas registradas com RegisterExpectedMemoryLeak serãoexcluídos do relatório da perda de memória.

A perda de memória é desabilitada retornando o defeito, maspode habilitar ajustando a variável globalReportMemoryLeaksOnShutdown para “true”.

Se não houver nenhuma perda de memória então a caixa dedialogo não mostrará, mesmo seReportMemoryLeaksOnShutDown receber “True”. Um códigosnippit usado pode permitir a perda da memória que serárelatada somente quando a aplicação rodar o debugger“ReportMemoryLeaksOnShutdown := DebugHook <> 0”.

O limite de registro das perdas no banco de dados é de 16K,então há a possibilidade de que RegisterExpectedMemory possafalhar e retorna “False” chamandoUnRegisterExpectecMemoryLeak removendo as entradas nobanco de dados.

A seguir um exemplo que relata a perda de memória.

O código a seguir que causou a caixa de diálogo.

- Relatando Gerente de Memória EstáticaO novo gerenciador de memória é inteiramente compatível e

auxilia chamando GetHeapStatus. Existem duas funções querelatam o estado fornencendo mais detalhes.

- GetMemoryManagerStateRetorna a lista de todos os blocos internos, tamanho e

número de blocos alocados em cada um. Também retornara aquantidade de endereços reservando cada um em blocos internos,assim que os blocos terminarem a fragmentação é que serápossível medí-los.

- GetMemoryMapRetorna um lista de todos os endereços dos pedaços com

espaços de 64K que estão em uso ou não, alocando ou reservandopelo sistema ou gerenciador da memória do Delphi.

- Compartilhando Gerenciador de Memória entre

Aplicação e BibliotecaNo passado o método preferencial de compartilhar o

gerenciador de memória entre aplicação e biblioteca seria atravésda unit ShareMem.pas e a biblioteca Borlndmm.DLL.

Este método ainda é suportado, junto com as antigasbibliotecas Borlndmm.DLL e podem usar novas Borldmm.DLL dealto desempenho.

O novo gerenciador de memória adiciona as alternativas decompartilhamento optando em não requisitar o uso da bibliotecaexterna. Este método é gerenciado através de duas funções,chamadas:

- AttemptToUseSharedMemoryManagerProcura os processos correntes no gerenciador de memória

Delphi

Page 29: EDITORIAL - The Club · gerar via QUICKREPORT, de preferência, no formato que aparece no PREVIEW. Resposta: ... usando os componentes da paleta indy ? Usando o componente da paleta

29

compartilhado. Se na memória alocada não tiver defeito o modulecomutará à usar o gerente de memória preferivelmente.Retornando “True” se um outro gerente for encontrado e se omodule se comutar com sucesso

- ShareMemoryManagerFaz como que o gerente de memória disponível do module

compartilhe os outros modules no processo atual. Somente umgerente de memória pode ser compartilhado no processo, sendoque esta função pode falhar, (e retorna “False”).

A nova unit SimpleShareMem.pas programa este novomecanismo de compartilhamento, e é recolocado naShareMem.pas.

- Gerenciador de Memória Usando RecolocaçãoUm das versões anteriores, o gerenciador de memória pode

ser recolocado como a terceira parte do gerenciador.

Para habilitar esta parte precisará programar uma novafuncionalidade para suportar a liberação, o procedimentoSetMemoryManager foi sobrecarregado para aceitar também onovo registro TMemoryManagerEx.

O registro TMemoryManagerEx se extende do antigoTMemoryManager adicionado dos seguintes campos:

- AllocMemIsto deve apontar uma função que retorna um bloco ‘0’ ou

preenchido do tamanho requerido. -RegisterExpectedMemoryLeakEste aponta para a função usada no registro da perda de

memória prevista. Se a perda da memória que verifica e querelata não for executada no gerente de memória, pode esteapontar para uma função que simplesmente retorna “False”.

-UnregisterExpectedMemoryLeakEste aponta para uma função usada para cancelar o registro

previamente registrado na memória. Se a perda de memória queregistra e que relata não for executada no gerente de memória narecolocação, podendo esta apontar simplesmente uma função queretorna “False”.

Para os gerentes de memórias antigos que instalaram nelesmesmos usando o antigo TMemoryManager, um defeitoAllocMem, os RegisterExpectedMemoryLeak eUnregisterExpectedMemoryLeak serão instalados.

O defeito AllocMem chama simplesmente GetMem e cancelaos blocos da memória, quando o defeitoRegisterExpectedMemoryLeak eUnregisterExpectedMemoryLeak não funcionar e retornar“False”.

- Implementação DetalhadaO novo gerente de memória é atualmente três em um:- Small (Pequeno: menor que 25K);- Médium (Médio: menor que 260K);- Large (Grande: maior que 260K);Os blocos são gerenciados separadamente.

Os requisitos para blocos grandes são passadoscompletamente ao sistema operando (VirtualAlloc) para alocar osendereços no início do espaço (Blocos médios e pequenos têm seusendereços alocados no final do espaço – mantê-los separadosmelhora o comportamento da fragmentação).

O gerente dos blocos médios obtém memória do OS no pedaço1.25MB.

Estes pedaços são chamados de “média combinação de blocos”e são subdivididas em blocos médios enquanto a aplicação osrequisita. Os blocos médios são mantidos em listas doublé-linked.

...

Sempre que um bloco médio é liberado, o MM verifica osblocos neighbouring para determinar se não são utilizadas epodem ser combinadas como o bloco que estão sendo liberados(nunca pode haver dois blocos neighbouring médios que são osambos utilizados).

O MM não tem nenhuma linha”clean-up” de fundo, assimtudo deve ser feita como parte da chamada de “FreeMem/GetMem/ReallocMem”.

Em uma linguagem de programação orientada a objetos, namaioria das alocações de memórias são livres e usualmente deobjetos pequenos. Em testes práticos de aplicações via Delphi sãoencontradas em média 99% das operações de memória envolvemblocos menores que 2K.

Fazendo assim o sentido de “Optimize” especificamente parablocos pequenos, cuja alocação é “combinação de blocospequenos”.

Delphi

Page 30: EDITORIAL - The Club · gerar via QUICKREPORT, de preferência, no formato que aparece no PREVIEW. Resposta: ... usando os componentes da paleta indy ? Usando o componente da paleta

30

Essas combinações são atualmente os médios blocos que sãosubdivididos em blocos pequenos de tamanhos iguais. Desde acombinação particular de blocos pequenos contenham somenteblocos de mesmo tamanho, e os demais pequenos blocos livresnunca se combinem, para que a alocação dos blocos sejaextremamente simplificada e mais rápida.

O MM mantêm uma lista doublé-linked de combinações comblocos pequenos disponíveis, procurando assim pedir blocos comtamanhos disponíveis quando precisar servir o GetMem serámais rápido.

.Movendo os dados dentro da memória é tipicamente umaoperação muito cara, consequentemente, o MM têm umalgorítimo inteligente de alocação para evitar tão como possívelmover na memória.

Quando um bloco é aumentado, ele ajusta o tamanho do blocona antecipação das características do aumento, melhorandoassim a probabilidade das realocações seguintes podem ser feitasno mesmo lugar.

Quando apontar um tamanho mínimo, o MM pedirá um novotamanho significativamente menor que o antigo sendo o blocomovido de outra maneira. Os blocos são encolhidos nunca abaixode um determinado nível mínimo, atualmente aproximado de64bytes.

Isto se apresenta tipicamente após as operações que envolvemos pequenos blocos (comum quando se manipula longas strings).

A velocidade é melhorada através de um mecanismo detravamento melhorado, cada bloco de tamanho pequeno, médios egrandes é travado individualmente. Se, ao prestar serviços a umpedido de manutenção de GetMem, o tipo “optimal” for travadopor uma outra linha, então o MM tentará até três tamanhosmaiores.

Este recurso diminui drasticamente o número de disputas delinhas e melhora o desempenho para aplicações emmulticamadas.

- Mudança de ComportamentoO novo gerente de memória pode expor o bugs que

previamente não mostravam nenhum sintoma (ou sintomasatrasados). Bugs que podem ter diferentes sintomas com o novogerente de memória são:

- Double-freeEstes são erros onde o mesmo ponteiro é livrado mais de uma

vez. O novo gerenciador da memória possui um flag no cabeçalhode cada bloco que é usado para indicar se o bloco esta em uso ounão.

O gerenciador consequentemente mostrará uma exceção(“Operação do Ponteiro Inválida”) se uma tentativa de tentarlivrar o bloco que já esteja livre for feita. O gerenciador damemória não levantou consistentemente este erro previamente.

- Usando Blocos da Memória depois de LiberadosEste tipo de bug ocorre tipicamente quando um objeto é

referenciado depois que está liberado.

O gerenciador da memória usa os blocos liberados obstruimais agressivamente que o gerenciador antigo, desde que esteutilize melhor o cachê do CPU.

Assim os blocos liberados são utilizados mais frequentementeque no gerenciador antigo, possivelmente causando bugs dessetipo venham a frente de onde estavam anteriormente.

- Memory OverwriteTanto o novo quanto antigo gerenciador emprega um

cabeçalho de 32bit em cada bloco que é usado para controlar o“Heap”, se este cabeçalho for corrompido nas aplicações, resultageralmente em crash.

Desde que os blocos em reúso mais frequentemente com ogerenciador atual, um crash pode ocorrer mais rapidamente doque com o antigo gerenciador de memória.

Deve-se relatar que o novo gerenciador é menos tolerante aosbugs de corrupções do “Heap” causado pela aplicação. O upsidepara este bug deve ser mais fácil de travar os bugs durante ociclo de desenvolvimento. O downside poderá frustrar a vida dequem faz aplicações que contem tais bugs.

O antigo gerenciado que é usado pelo Delphi 2005 (e versõesatualizadas do Delphi) é avaliado por um código cintral em umformulário de um modulo do gerenciador de realocação.

Este módulo pode ser útil para comparar o desempenho dosantigo com os novos gerentes de memória, e também pode serusados nos casos onde o comportamento do gerente antigo édesejado após o comportamento do novo.

Delphi

Page 31: EDITORIAL - The Club · gerar via QUICKREPORT, de preferência, no formato que aparece no PREVIEW. Resposta: ... usando os componentes da paleta indy ? Usando o componente da paleta
Page 32: EDITORIAL - The Club · gerar via QUICKREPORT, de preferência, no formato que aparece no PREVIEW. Resposta: ... usando os componentes da paleta indy ? Usando o componente da paleta