22 agosto 2011

Cuidados ao usar o OnExit

É comum fazermos uso do evento OnExit quando queremos validar o conteúdo de um Edit. E essa pode ser uma boa prática quando necessitamos verificar o que foi digitado apenas quando o usuário terminar de fazer a entrada de dados, como, por exemplo, um Edit que vai receber o CPF ou CNPJ.

Ao colocarmos um código qualquer no evento OnExit ele sempre será executado quando o usuário sair do Edit, o que acontece quando ele pressiona a tecla TAB, clica com o mouse em um outro Edit ou pressiona um botão OK, por exemplo:


No entanto, existem algumas situações especiais em que o evento OnExit não é gerado. Quer um exemplo? Você está no Edit e, ao invés de clicar no botão OK, você pressiona as teclas ALT + O (considerando que o botão OK tem a tecla O como atalho). É como se você tivesse pressionado o botão OK, porém, sem perder o foco que está no Edit. Só mais um exemplo: Os botões do tipo SpeedButton não recebem foco, então, mesmo que clique com o mouse sobre um SpeedButton, o foco continuará no Edit e, conseqüentemente, o evento OnExit não será gerado.

E a solução?

A solução para esse pequeno inconveniente é simples. Basta você colocar o seguinte código no evento OnClick do botão.


procedure TForm1.Button1Click(Sender: TObject);
begin
   ActiveControl := nil;
   ...
end;



Com isso você força a saída de qualquer Edit ou outro componente que esteja com o foco, gerando assim o evento OnExit.


Suponhamos que você possua 2 Edits em um formulário. Supondo também que você queira dar alguma informação ao usuário da aplicação logo depois que ele sair do Edit1 você faz:


procedure TForm1.Edit1Exit(Sender: TObject);
begin
    MessageDlg('Mensagem...', mtInformation, [mbOk], 0);
end;


A princípio está tudo ok, ou melhor, parece estar tudo ok.
Se você altera o foco para o outro Edit através do pressionamento da tecla TAB, tudo bem. Mas experimente alterar o foco clicando com o mouse sobre o Edit2. Neste segundo caso a mensagem será exibida normalmente. Mas ao fechar o dialogo onde aparece a mensagem, o foco simplesmente se perde. Para setar o foco no Edit2 é necessário clicar novamente sobre ele.


Isso poderia não problema nenhum até que seu usuário experimente esta situação. Nada que ele digitar será acatado.

Mas existe uma maneira fácil de resolver o problema. Basta você cancelar o foco e forçar uma reentrada no componente Edit2. Como fazer isso? Veja o código:


procedure TForm1.Edit1Exit(Sender: TObject);
begin
   MessageDlg('Mensagem...', mtInformation, [mbOk], 0);
    // cancela o foco e força novamente a entrada
   ActiveControl := nil;
   PostMessage(Edit2.Handle, WM_SETFOCUS, 0, 0);
   Edit2.SetFocus;
end;



Porém, você nunca terá certeza se o usuário clicou foi no Edit2. Então temos que criar uma rotina genérica que leva o foco para qualquer outro controle:


procedure TForm1.Edit1Exit(Sender: TObject);
var
   Ctrl: TWinControl;
begin
   MessageDlg('Mensagem...', mtInformation, [mbOk], 0);
    // cancela o foco e força novamente a entrada
   Ctrl := ActiveControl;
   ActiveControl := nil;
   PostMessage(TWinControl(Ctrl).Handle, WM_SETFOCUS, 0, 0);
   TWinControl(Ctrl).SetFocus;
end;

 bserve que antes de cancelar o foco com ActiveControl := nil, salvamos qual é o controle que detém o foco fazendo Ctrl := ActiveControl.

 Depois enviamos uma mensagem ao controle que detinha o foco, forçando-o a receber o foco novamente.

Nenhum comentário:

Postar um comentário