May 05 2007
Delphi: como interceptar o evento OnExit de um TMaskEdit?
Com certeza o componente TMaskEdit foi modelado às pressas pela equipe responsável, pois forçar uma validação com uma mensagem fixa sempre que o usuário sai do campo é um crime. E tem mais: eu diria que a pena é de prisão perpétua, pois além disso, quando você limpa o conteúdo do campo e sai dele, a validação também é executada. Neste caso, adivinha o que acontece? Uma mensagem de erro aparece mesmo sem ter valor algum no campo.
Há quem diga que é impossível desabilitar esta validação. Realmente é, se pensarmos de forma racional. No entanto, não custa nada partir pra baixaria uma vez ou outra.
Todos os componentes trabalham com mensagens enviadas pelo Windows para ativar os eventos. Portanto, o que acontece com o TMaskEdit?
Ele recebe uma mensagem informando que o usuário saiu do campo, executa o OnExit e, neste momento, faz a validação do conteúdo.
Já que o problema descrito acima acontece mesmo quando o usuário limpa o valor do campo, a solução é interceptar o evento OnExit e só executar o código padrão caso algum valor tenha sido informado.
Como fazer? Simples. Veja:
Declare uma procedure type of object (em outra palavras, um método) e um field do tipo TWndMethod:
FOldWindowProc: TWndMethod; procedure WMWindowProc(var Msg: TMessage);
A implementação do método é a seguinte:
procedure TfrmForm.WMWindowProc(var Msg: TMessage); begin if (Msg.Msg = CM_EXIT) then begin if (maskEdit.Text <> '') then FOldWindowProc(Msg); end else FOldWindowProc(Msg); end;
No evento FormShow do formulário faça as seguintes atribuições:
FOldWindowProc := maskEdit.WindowProc; maskEdit.WindowProc := WMWindowProc;
Pronto! Agora sempre que o evento OnExit do TMaskEdit for executado ele só fará a validação se o Text for diferente de vazio.
T+
Ps1: falei especificamente do TMaskEdit, porém este conceito de captura de eventos vale para todos os componentes.
Ps2: há alguns meses eu escrevi sobre algo parecido com o componente TScrollBox. Veja aqui.








Eu modifiquei o arquivo c:\arquivo de programas\Borland\Delphi7\source\vcl\mask.pas
na rotina
// Original
procedure TCustomMaskEdit.ValidateEdit;
var
Str: string;
Pos: Integer;
begin
Str := EditText;
if IsMasked and Modified then
begin
if not Validate(Str, Pos) then
begin
if not (csDesigning in ComponentState) then
begin
Include(FMaskState, msReEnter);
SetFocus;
end;
SetCursor(Pos);
ValidateError;
end;
end;
end;
// Modificado
procedure TCustomMaskEdit.ValidateEdit;
var
Str: string;
Pos: Integer;
begin
Str := EditText;
if (Str = ”) then Exit;
if IsMasked and Modified then
begin
if not Validate(Str, Pos) then
begin
if not (csDesigning in ComponentState) then
begin
Include(FMaskState, msReEnter);
SetFocus;
end;
SetCursor(Pos);
ValidateError;
end;
end;
end;
E também funcionou.
Fica Melhor Ainda assim:
procedure TCustomMaskEdit.ValidateEdit;
var
Str: string;
Pos: Integer;
begin
Str := EditText;
if (Trim(Text) = ”) then
Exit;
if IsMasked and Modified then
begin
if not Validate(Str, Pos) then
begin
if not (csDesigning in ComponentState) then
begin
Include(FMaskState, msReEnter);
SetFocus;
end;
SetCursor(Pos);
ValidateError;
end;
end;
end;