Esse artigo faz parte da revistaClube Delphi edição 10. Clique aqui para ler todos os artigos desta edição




Atenção: por essa edição ser muito antiga não há arquivo PDF para download. Os artigos dessa edição estão disponíveis somente através do formato HTML.


Tratando Erros de Execução

Utilizando o evento OnException paratratar todos os erros de execução

Uma boa prática a se aplicar aos projetos de sistemas informatizados, é a adoção de um mecanismo para tratamento de erros. Desta forma, seu aplicativo não exibiria mensagens indecifráveis para o usuário, tornando claro todo o ocorrido ao longo do processo e uso.

Geralmente, uma linguagem de desenvolvimento não fornece uma boa interface para interceptar ocorrências de erros, identificá-las e posteriormente tratá-las, considerando as diversas possibilidades.Mas em se tratando das ferramentas Inprise-Borland, todo esta tarefa fica minimizada ao contexto do desenvolvimento na linguagem adotada, pela simples utilização da estrutura de objetos da Classe Exception.

Nas operações com Banco de Dados, onde os erros originados de tentativas de quebra de integridade, violação de chave primária e outros, podem ocorrer com grande probabilidade, seria muito interessante se pudéssemos criar uma procedure única para o tratamento de todos os erros - ao invés de usar um try..except para cada situação.

Felizmente, este é um recurso de fácil implementação no Delphi - o objeto Tapplication possui o evento OnException - que é disparado quando qualquer erro é gerado pela aplicação, em qualquer formulário.

Uma das novidades do Delphi 5, é o objeto TapplicationEvents - que herda a funcionalidade do objeto Tapplication e permite a manipulação de seus eventos de forma visual (o objeto Tapplication é não visual).

Vamos agora criar um aplicativo exemplo, que irá utilizar o evento OnException para centralizar o tratamento de erros:

Interface principal do sistema e código fonte:


unit Principal;
interface
uses
  Windows, Messages,SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Menus, AppEvnts, ComCtrls;
type
  TFrmPrincipal = class(TForm)
    MainMenu1: TMainMenu;
    Mdulos1: TMenuItem;
    Geral1: TMenuItem;
    ApplicationEvents1: TApplicationEvents;
    StatusBar1: TStatusBar;
    procedure ApplicationEvents1Exception(Sender: TObject; E: Exception);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
var
  FrmPrincipal:    TFrmPrincipal;
implementation
{$R *.DFM}
procedure TFrmPrincipal.Geral1Click(Sender: TObject);
begin
   Try
     Application.CreateForm(TFrmTesta Erros, FrmTestaErros);
     FrmTestaErros.ShowModal;
     Finally
       FrmTestaErros.Free;
   End;
end;
procedure TFrmPrincipal.ApplicationEvents1 Exception(Sender: TObject;
  E: Exception);
var mensagem: string;
    Pos1, Pos2: integer;
begin
   If Pos(UpperCase('is not a valid date'), UpperCase(E.Message)) > 0 then
           showmessage('Data inválida, proceda a correção.')
   else
      if Pos(UpperCase('must have a value'), UpperCase(E.Message)) > 0 then
           begin
              Pos1:=Pos('''', E.Message);
              mensagem:=E.Message;
              Delete(mensagem, Pos1, 1);
              Pos2:=Pos('''', mensagem);
              mensagem:=copy(E.Message, Pos1 + 1, Pos2 - Pos1);
              showmessage('É obrigatório o preenchimento do campo '+ mensagem + '.');
           end
   else
      If Pos(UpperCase('key violation'), UpperCase(E.Message)) <> 0 then
           showmessage('Houve violação de Chave.  Registro já incluido.')
   else
      If Pos(UpperCase('Input value'), UpperCase(E.Message)) <> 0 then
           showmessage('Campo preenchido com valor não válido. Procedaa correção.')
   else
      If Pos(UpperCase('is not a valid time'), UpperCase(E.Message)) <> 0 then
           showmessage('Hora inválida, proceda a correção.')
   else
      showmessage('Ocorreu o seguinte erro: '+UpperCase(E.Message));
end;
end.

Detalhando passo-a-passo o evento OnException:

O que o procedimento faz nada mais é do que comparar qual a string de erro que foi gerada. Esta string é passada como parâmetro através do objeto E (Exception), dentro de sua propriedade message.

If Pos(UpperCase('is not a valid date'), UpperCase(E.Message)) > 0 then

A primeira comparaçào se refere a um erro de data. A função Pos, indica se a substring passada como parâmetro existe dentro da mensagemde erro. Se existir, a função irá retornar um valor maio que 0 (zero).

Outros erros, testados pelos seus trechos significativos ('key violation', 'Input value', 'is not a valid time') podem ser tratados da mesma forma, diminuindo o trabalho e a manutenção do aplicativo.

Isto é só uma demonstração do que você pode fazer para prever todos os erros possíveis em seu projeto. Basta conhecer qual a mensagem de erro retornada pelo objeto Exception - e tratá-la neste evento.

Algumas situaçòes irão pedir uma maior habilidade do desenvolvedor com a linguagem. Por exemplo, se tentarmos capturar o erro gerado por um campo unique. Veja na figura ao lado um exemplo:



Poderíamos indicar ao usuário qual a coluna que gerou o erro. Observe abaixo como este problema pode ser resolvido:


if Pos(UpperCase('must have a value'), UpperCase(E.Message)) > 0 then- Testa a ocorrência do erro 'must have a value'.Caso positivo, investe na captura de qual coluna.


Pos1:=Pos('''', E.Message);

Atribui a variável Pos1, a posição do primeiro delimitador(') que envolve o nome do campo ( exemplo'Moeda').

mensagem:=E.Message;

Atribui o conteúdo da propriedade message(a própria mensagem de erro natural) a variável mensagem.

Delete(mensagem, Pos1, 1);

Usa-se a função Delete para excluir da string(variável mensagem) a ocorrência do primeiro delimitador(') que envolve o campo('Moeda').

Pos2:=Pos('''', mensagem);

Atribui a variável Pos2, o valor numérico da posição do segundo delimitador que envolve o nome do campo causador da exceção.

mensagem:=copy(E.Message, Pos1 + 1, Pos2 - Pos1);

Atribui um novo valor a variável mensagem, utilizando-se a função copy para extrair da propriedade message a sub-string que representa o nome do campo.

showmessage ('É obrigatório o preenchimento do campo '+ mensagem + '.');

Por último, é exibido a constante 'É obrigatório o peenchimento do campo', mais a concatenação da string que representa o nome da coluna.

Dica: Conforme apresentado no projeto que se segue, a tabela utilizada é Country do banco de dados de exemplo do Interbase.Porém o nome da coluna desta tabela não é MOEDA e sim CURRENCY. Aí vai umadica: O que a classe exception expõe, não é exatamente o nome da coluna, mas sim o conteúdo da propriedade DisplayLabel (quando tornada objeto). Fica assim explicado porque MOEDA e não CURRENCY conforme o original.

Caso a mensagem de erro não tenha sido prevista, exibimos uma janela padrão: showmessage('Ocorreu o seguinteerro: '+UpperCase(E.Message));

Interface de teste da captura de erro

Configuração dos Objetos:


TDATABASE

AliasNameIBLocal

ConnectedTRue

DatabasenameBDIB

NameDatabase1


TABLE1

Active True

DatabasenameBDIB

NameTableCountry

TableNameCountry


DATASOURCE1

DatasetTableCountry

NameDSTableCountry


DBGRID1

DataSourceDsTableCountry


CÓDIGO DA UNIT:


unit TestaErros;
interface
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Db, Grids, DBGrids, DBTables;
type
  TFrmTestaErros = class(TForm)
    Database: TDatabase;
    TableCountry: TTable;
    DSTableCountry: TDataSource;
    DBGrid1: TDBGrid;
    TableCountryCOUNTRY: TStringField;
    TableCountryCURRENCY: TStringField;
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  FrmTestaErros: TFrmTestaErros;
 
implementation
 
{$R *.DFM}
 

A tela em execução provoca a entrada de um novo registro.Na sequência, o usuário tenta avançar para a próxima linha, que provoca de imediato o método Post.

Desta forma, o Servidor reage com uma exceção indicando o não preenchimento do campo Moeda. Como temos um tratamento específico, não é exibido a caixa de diálogo(figura 2) e sim a mensagem da nossa última tela.




Laercio Guerço Rodrigues é membro da DigiData Informática, resposável pela implementação de cursos voltados as áreas de desenvolvimento de Sistemas Client Server, atualmente empenhado em divulgar e implemtar cursos e aplicativos no modelo Objeto Distribuido(CORBA e D-COM), Internet(Web DataBase) e literatura específica em Delphi.