Criação de Componentes

Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Para efetuar o download você precisa estar logado. Clique aqui para efetuar o login
Confirmar voto
0
 (2)  (0)

Veja neste artigo de Fabio Francelino, como criar um componente para rastrear erros.

Rastreando Erros com TExErrorDialog

Como sabemos é muito importante o modo como tratamos os erros ocorridos nos sistemas, tanto os esperados quanto os inesperados, isso pode fazer a diferença na hora da manutenção de um sistema complexo e também transmite confiabilidade ao usuário final. Um programa é considerado robusto quando tem a capacidade de rastrear todos os seus erros e apresentar uma informação plausível para o usuário tomar alguma decisão ou entrar em contato com o setor de desenvolvimento do sistema.

Criando o pacote

Vamos começar criando um pacote para o componente TExErrorDialog. Vá no menu File|New>Other e escolha a opção Package. Salve o pacote com o nome sugerido em um diretório e clique na opção Options, na descrição do pacote digite o nome que irá aparecer na lista de pacotes instalados (Component|Install Packges). Certifique-se que as opções Designtime and runtime e Explicit rebuild estejam marcadas, caso queira, acesse a aba Version Info e configure as descrições do arquivo.

Criando a unit do componente

Vá ao menu Component>New Component, na caixa de diálogo crie um descendente (Ancestor Type) de TComponent com o nome (Class Name) de “TExErrorDialog” na paleta ExControls e o nome da unit como “untExErrorDialog”, não se esqueça de mudar o diretório da unit, clique em OK. Vamos codificar as propriedades, eventos e tipos  do componente conforme a Listagem 1.

 

Listagem 1. Código fonte completo

unit untExErrorDialog;

 

interface

 

uses Windows, Messages, SysUtils, Classes, Forms;

 

type

{ Tipos de Erro }

TErrorType = (etNone = 0, etRunTime = 1, etSQL = 2,

  etValidation = 3, etLogic = 4);

{ Status do Erro }

TErrorStatus = (esNone = 0, esFatal = 1,

  esNormal = 2);

{Tipo de Erro}

TErrorInfo = record

  ErrorStatus: TErrorStatus;

  ErrorType: TErrorType;

  ErrorSource: string;

  ErrorMsgUser: string;

  ErrorMsgSys: string;

  ErrorClass: string;

  ErrorMethod: string;

  ErrorCode: string;

end;

 

{ Componente de Erro }

TExErrorDialog = class(TComponent)

  private

    FErrorInfo: TErrorInfo;

    FErrorStatus: TErrorStatus;

    FErrorType: TErrorType;

    FErrorSource: string;

    FErrorMsgUser: string;

    FErrorMsgSys: string;

    FErrorClass: string;

    FErrorMethod: string;

    FErrorCode: string;

    FShowDetail: Boolean;

    FClearAfterShow: Boolean;

    FOnBeforeShow: TNotifyEvent;

    FOnAfterShow: TNotifyEvent;

    procedure SetErrorInfoValues();

    procedure SetErrorPropValues();

  protected

  public

    procedure Clear();

    procedure ShowErrorMsg(); overload;

    procedure ShowErrorMsg(

      const pErrorInfo: TErrorInfo); overload;

  published

    property ErrorStatus: TErrorStatus

      read FErrorStatus write FErrorStatus;

    property ErrorType: TErrorType

      read FErrorType write FErrorType;

    property ErrorSource: string

      read FErrorSource write FErrorSource;

    property ErrorMsgUser: string

      read FErrorMsgUser write FErrorMsgUser;

    property ErrorMsgSys: string

      read FErrorMsgSys write FErrorMsgSys;

    property ErrorClass: string

      read FErrorClass write FErrorClass;

    property ErrorMethod: string

      read FErrorMethod write FErrorMethod;

    property ErrorCode: string

      read FErrorCode write FErrorCode;

    property ShowDetail: Boolean

      read FShowDetail write FShowDetail;

    property ClearAfterShow: Boolean

      read FClearAfterShow write FClearAfterShow;

    property OnBeforeShow: TNotifyEvent

      read FOnBeforeShow write FOnBeforeShow;

    property OnAfterShow: TNotifyEvent

      read FOnAfterShow write FOnAfterShow;

end;

 

procedure Register;

 

implementation

 

uses untExGuiErrorDialog;

 

procedure Register;

begin

  RegisterComponents('ExControls', [TExErrorDialog]);

end;

 

{ Mostra a mensagem passando os parametros internos }

procedure TExErrorDialog.ShowErrorMsg();

begin

  { Sincroniza as propriedades com o record }

  SetErrorInfoValues;

  { Chama a rotina }

  ShowErrorMsg(FErrorInfo);

end;

 

{ Mostra a mensagem passando os parametros

  de pErrorInfo }

procedure TExErrorDialog.ShowErrorMsg(

  const pErrorInfo: TErrorInfo);

begin

  { Cria o formulario }

  frmExGuiErrorDialog :=

    TfrmExGuiErrorDialog.Create(Self);

  FErrorInfo := pErrorInfo;

  frmExGuiErrorDialog.SetFieldValue(pErrorInfo);

  { Sincroniza o record com as propriedades }

  SetErrorPropValues;

  { Verifica e dispara o evento }

  if Assigned(FOnBeforeShow) then

    FOnBeforeShow(Self);

  { Seta o valor da propriedade ShowDetail }

  frmExGuiErrorDialog.cmdDetalhes.Visible :=

    FShowDetail;

  { Mostra o form Modal }

  frmExGuiErrorDialog.ShowModal;

  if Assigned(FOnAfterShow) then

    FOnAfterShow(Self);

  { Verifica e limpa os parametros }

  if FClearAfterShow then

    Clear();

  { Libera a memória }

  frmExGuiErrorDialog.Free;

  frmExGuiErrorDialog := nil;

end;

 

{ Seta as propriedades internas do record }

procedure TExErrorDialog.SetErrorInfoValues();

begin

  { Seta as propriedades do record }

  FErrorInfo.ErrorType := FErrorType;

  FErrorInfo.ErrorStatus := FErrorStatus;

  FErrorInfo.ErrorSource := FErrorSource;

  FErrorInfo.ErrorMsgUser := FErrorMsgUser;

  FErrorInfo.ErrorMsgSys := FErrorMsgSys;

  FErrorInfo.ErrorClass := FErrorClass;

  FErrorInfo.ErrorMethod := FErrorMethod;

  FErrorInfo.ErrorCode := FErrorCode;

end;

 

{ Seta as propriedades internas do componente }

procedure TExErrorDialog.SetErrorPropValues();

begin

  { Seta as propriedades do record }

  FErrorType := FErrorInfo.ErrorType;

  FErrorStatus := FErrorInfo.ErrorStatus;

  FErrorSource := FErrorInfo.ErrorSource;

  FErrorMsgUser := FErrorInfo.ErrorMsgUser;

  FErrorMsgSys := FErrorInfo.ErrorMsgSys;

  FErrorClass := FErrorInfo.ErrorClass;

  FErrorMethod := FErrorInfo.ErrorMethod;

  FErrorCode := FErrorInfo.ErrorCode;

end;

 

{ Limpa todas as propriedades internas }

procedure TExErrorDialog.Clear();

begin

  { Limpa as propriedades do record }

  with FErrorInfo do

  begin

    ErrorType := etNone;

    ErrorStatus := esNone;

    ErrorSource := EmptyStr;

    ErrorMsgUser := EmptyStr;

    ErrorMsgSys := EmptyStr;

    ErrorClass := EmptyStr;

    ErrorMethod := EmptyStr;

    ErrorCode := EmptyStr;

  end;

  { Limpa as propriedades publicas }

  ErrorType := etNone;

  ErrorStatus := esNone;

  ErrorSource := EmptyStr;

  ErrorMsgUser := EmptyStr;

  ErrorMsgSys := EmptyStr;

  ErrorClass := EmptyStr;

  ErrorMethod := EmptyStr;

  ErrorCode := EmptyStr;

end;

end.

Propriedades do componente

Nessa seção destaco as propriedades ErrorStatus e ErrorType que são de tipos, delarados no inicio da unit e que nos mostram os tipos de erros que vamos apresentar e qual o status desses erros, como vemos  no código a seguir:

 

{ Tipos de Erro }

TErrorType = (etNone = 0, etRunTime = 1, etSQL = 2,

  etValidation = 3, etLogic = 4);

{ Status do Erro }

TErrorStatus = (esNone = 0, esFatal = 1,

  esNormal = 2);

Eventos do componente

Declaramos dois eventos para ajudar a controlar erros fatais e dar um tratamento genérico de erro que são OnBeforeShow e OnAfterShow. As propriedades ClearAfterShow e ErrorStatus trabalham baseadas no seguintes eventos:

 

property OnBeforeShow: TNotifyEvent read FonBeforeShow

  write FOnBeforeShow;

property OnAfterShow: TNotifyEvent read FonAfterShow

  write FOnAfterShow;

Codificando o componente

Temos duas rotinas que merecem destaque, pois ambas tem o mesmo nome com parâmetros diferentes. ShowErrorMsg (com a diretiva overload, que permite declarar rotinas com nomes iguais e parâmetros de tipos diferentes), em uma das suas declarações possui um parâmetro que é um record, ou seja, uma estrutura de dados (definida no escopo da unit), para facilitar o intercâmbio de um conjunto de informações entre rotinas e funções. Por causa desse record  devemos sincronizar as propriedades do componente com o record recebido como parâmetro e vice-versa, para isso temos as rotinas SetErrorInfoValues e SetErrorPropValues veja na Listagem 2.

 

Listagem 2. Rotinas do componente

private

  procedure SetErrorInfoValues();

  procedure SetErrorPropValues();

protected

public

  procedure Clear();

  procedure ShowErrorMsg(); overload;

  procedure ShowErrorMsg(

    const pErrorInfo: TErrorInfo); overload;

Formulário do componente

Sei que vocês estão tentados a compilar o componente, mas ainda falta a parte mais importante: o formulário de apresentação, ou seja, onde todas as informações serão exibidas para o usuário final.

Adicione um novo formulário (File|New>Form) no pacote e salve sua unit como “untGuiExErrorDialog.pas” e o nome do formulário como “frmExGuiErrorDialog”. Por que Gui?, Gui é a abreviação de Graphic User Interface nada mais conveniente.

Adicione no formulário os seguintes componentes: um StaticText, dois Buttons, um Memo e quatro Image. Disponha os componentes para que fiquem parecido com a Figura 1.

Error1.gif 

Figura 1. Formulário de apresentação dos erros

Altere as propriedades dos componentes conforme a Tabela 1.

 

Componente

Nome

Valor

StaticText

Name

lblErrMsg

 

BevelKind

BkTile

Button

Name

cmdDetalhes

 

Caption

<<&Detalhes

 

Default

True

Button

Name

cmdOk

 

Caption

&Ok

 

Cancel

True

Memo

Name

txtErrorDescription

 

ScrollBars

ssVertical

Image

Name

imgValidation

Image

Name

imgLogic

Image

Name

imgInformation

Image

Name

imgRunTime

 

 

 

 

 

 

 

 

 

 

 

Tabela 1. Propriedade dos componentes no formulário

Escolha uma imagem de 32x32 para cada um dos Images (altere para False a propriedade Visible dos Images), cada imagem representa um tipo de erro, e deixe todos exatamente sobrepostos, ao terminar lembre-se de voltar o tamanho do seu formulário para que fique sem aparecer o Memo (altere para bsSingle a propriedade BorderStyle do formulário). Insira na seção public do formulário o seguite código:

 

procedure SetFieldValue(const pErrorInfo: TErrorInfo);

 

E implemente-o conforme a Listagem 3.

 

Listagem 3. Código do método SetFieldValue do formulário

procedure TfrmExGuiErrorDialog.SetFieldValue(

  const pErrorInfo: TErrorInfo);

begin

  with pErrorInfo do

  begin

    { Verifica qual o tipo de erro }

    case ErrorType of

      etNone:

        begin

          Caption := 'Tipo de Erro Desconhecido.';

          imgRunTime.Visible := True;

        end;

      etValidation:

        begin

          Caption := 'Erro de Validação.';

          imgValidation.Visible := True;

        end;

      etSQL:

        begin

          Caption := 'Erro de Comando SQL.';

          imgRunTime.Visible := True;

        end;

      etRunTime:

        begin

          Caption := 'Erro de Run-Time.';

          imgRunTime.Visible := True;

        end;

      etLogic:

        begin

          Caption := 'Erro de Lógica de Programação.';

          imgLogic.Visible := True;

        end;

    end;

    lblErrMsg.Caption := ErrorMsgUser;

    txtErrorDescription.Text :=

      'Code: ' + ErrorCode + #13#10 +

      'Source: ' + ErrorSource + #13#10 +

      'Class: ' + ErrorClass + #13#10 +

      'Method: ' + ErrorMethod + #13#10 +

      'Description: ' + ErrorMsgSys;

  end;

end;

 

No botão OK apenas indicamos a propriedade ModalResult como mrOK e fechamos o formulário (Close).

Devemos declarar na cláusula uses do formulário a unit do componente (untExErrorDialog), o que já nos permite tirar vantagem do record, facilitando o intercâmbio de informações entre o componente e o formulário.

Outro detalhe, é o tipo de erro etSQL não possuir uma imagem em particular, ele utiliza a mesma imagem do erro de run-time. Já podemos compilar e instalar o componente.

Alterando a imagem que representa o componente

Escolha uma imagem que representa bem o componente no formato .BMP com o tamanho 24x24, vá no menu Tools e abra o Image Editor, crie um novo Resource files (.dcr), adicione um novo bitmap, mude seu nome para o nome do componente (TEXERRORDIALOG) e cole a imagem desenhada na área em branco, salve o arquivo com o nome “untExErrorDialog.dcr”.

Para que a figura apareça na IDE do Delphi, vá no menu Project|View Source e adicione a seguinte linha de código:

 

{$R *.res}

{$R untExErrorDialog.dcr} <- adicione aqui

...

 

Veja na Figura 2, como ficará o componente registrado na IDE do Delphi.

Error2.gif 

Figura 2. Componente ExErrorDialog instalado na IDE do Delphi

Utilizando o ExErrorDialog

Vamos finalmente testar todas as funcionalidades do componente. Crie uma nova aplicação no Delphi e configure o formulário como mostra a Figura 3.

Error3.gif 

Figura 3. Utilizando o componente

O código completo do componente e do exemplo está para download no endereço do artigo. Para testar, temos na Listagem 4, o código do botão Run-Time, onde utilizamos constantes (declaradas no formulário) para mostrar as mensagens de erros ao usuário (propriedade ErrorMsgUser).

 

Listagem 4. Utilizando o componente de Erro

procedure TForm1.Button1Click(Sender: TObject);

begin

  try

   { Forçando o Erro }

    Button1.Tag := StrToInt('X');

  except

   { Seta as informaçõe do erro }

    with ExErrorDialog1 do

    begin

      ErrorType := etRunTime;

      ErrorStatus := esNormal;

      ErrorClass := 'TButton';

      ErrorMethod := 'Tag';

      ErrorSource := 'cmdRunTimeClick';

      ErrorMsgUser := ErrConvert; <- constante

      ErrorMsgSys := 'X is not a valid integer value.';

      ShowErrorMsg;

    end;

  end;

end;

 

No exemplo, um erro do tipo fatal pode causar o fechamento do seu programa com uma mensagem elegante (Figura 4), podemos ainda mostrar o último erro ocorrido sem nenhum esforço e ainda tratar mensagens de erro no evento OnBeforeShow. Podemos chamar rotinas passando nosso TErrorInfo como parâmetro e verificar o código retornado na propriedade ErrorCode, o que torna fácil o intercâmbio de informações de erro.

Error4.gif 

Figura 4. Componente em execução

Aconselho a colocar apenas um componente em seu DataModule e utilizá-lo em todo o seu programa, tornando fácil e prático a exibição de uma mensagem de erro. Podemos chamar funções que já preenchem as propriedades de erro e depois avaliar se mostramos o erro ou não. Os erros de lógica, como por exemplo, pode alertar programadores sobre valores inválidos em suas chamadas de funções e rotinas.

Outro aspecto que devemos destacar é a necessidade que alguns sistemas tem de fazer um log de erro, com o evento AfterShow você poderá chamar sua rotina de log e passar um TErrorInfo para ser gravado em um arquivo.

Se o leitor gostar dessa brincadeira poderá estender o componente e adicionar as funcionalidades de log embutidas no componente e até uma opção de envio de e-mail.

Conclusões

Utilizando corretamente esse componente você será capaz de identificar as seguintes informações sobre o erro: em qual função ocorreu o erro, por que, qual componente foi o responsável pelo erro, qual medida a ser tomada, qual o código, quem disparou a função. Isso reduz seu tempo de manutenção praticamente em 50% pois agora você já sabe tudo sobre o erro e basta somente corrigi-lo e não procurá-lo.

 
Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Ficou com alguma dúvida?