Bem amigos, há muito tempo que venho querendo ministrar um curso para ensinar a desenvolver componentes em Delphi. É uma forma de aprender mais e passar o conhecimento que obtive com meus colegas do fórum e com alguns livros que li. Então mãos à obra, pois temos muito trabalho a fazer.

Conhecendo a estrutura

No início o desenvolvimento de componentes, confesso, é um pouco confuso, mas logo você irá se apaixonar por seus próprios componentes, prometo.

A primeira coisa que se deve ter em mente é que componentes são desenvolvidos sem auxílio pleno no que diz respeito a visual, ou seja, é basicamente a digitação de classes, procedures e functions. Por isso é necessário se ter uma boa noção de como criar procedimentos, funções, classes e etc.

Você deve estar se perguntando: Na Internet existem milhares de componentes gratuitos e até com código fonte aberto, porque desenvolvê-los? Para responder esta questão faço uso de duas palavras que resumem tudo: controle e personalização. Nem sempre encontramos componentes que se encaixem com nossa realidade, daí surge a necessidade de criá-los.

Para este nosso primeiro artigo, vamos criar um componente bem interessante e útil. O TexTabToEnter. O componente fará o trabalho de trocar o tab pelo enter em toda a aplicação. Calma, calma. A ideia inicial é que possamos ver o básico da criação de um componente, pois o TexTabToEnter existe aos montes na grande teia, vamos apenas treinar.

Nota: Usarei o prefixo “ex” para todos os componentes que criaremos em nossos exemplos.

Por onde começar?

O início de um projeto de componente é bem mais simples do que muitos imaginam.

Abra o Delphi e logo em seguida feche o projeto default que se abre usando a opção Close All no menu File. Depois disso basta acionar a opção New Component presente no meu Component. Uma caixa de diálogo aparecerá (veja Figura 1) e nela vamos preencher alguns parâmetros.

Diálogo de criação do componente
Figura 1. Diálogo de criação do componente

Nesta caixa de diálogo definimos informações referentes ao nosso novo componente conforme explicação:

  • Ancestor type: Classe "pai" do nosso componente, ou seja, de qual classe nosso componente será "parente". No caso TComponent.
  • Class Name: Nome da nova classe que estamos criando. Vamos usar em nossos exemplos o prefixo "ex" de exemplo para todas as classes.
  • Pallete Page: Em qual paleta do Delphi nosso componente será instalado.
  • Unit file name: Informe ao Delphi em qual diretório será salvo nosso componente.

Após a configuração dessas informações basta clicar em Ok para que o Delphi crie pra nós o escopo inicial de nosso componente e olhando com atenção para nossa nova Unit vemos que existem algumas seções que não encontramos em nossos programas (veja a Listagem 1).


unit exTabToEnter;
 
interface;
 
uses 
  SysUtils, Classes;
 
type 
  TexTabToEnter = class(TComponent);
  private 
    {Private Declarations}
  protected 
    {Protected Declarations}
  public 
    {Public Declarations}
  published 
    {Published Declarations}
  end; 
 
procedure Register;
 
implementation 
 
procedure Register;
begin
  RegisterComponents('ClubeDelphi', [TabToEnter]);
end;
 
end.
Listagem 1. Unit do nosso componente ainda sem nenhuma implementação

Implementando funcionalidades

Para este primeiro projetos, vamos fazer algo bem simples.

Nosso componente será responsável por fazer com que o Enter funcione como TAB em nossos sistemas.

A mágica consiste em “desviar” o evento onMessage do objeto TApplication para uma função Execute do componente que por sua vez fará a “troca” de Tab para Enter.

Nota: Na verdade não faremos a troca, afinal de contas o tab continuará tendo sua funcionalidade.

Vamos precisar de apenas uma propriedade: Ativo do tipo Boolean. Esta propriedade quando ativa será checada pela procedure Execute realizando a tarefa desejada. Para criar uma propriedade basta usar a palavra reservada property na seção Published. Esta seção é responsável por publicar nossas propriedades no Object Inspector, ou seja, será visível para o desenvolvedor em tempo de projeto. (veja a Listagem 2).

unit exTabToEnter;
 
interface;
 
uses 
  Windows, Messages, SysUtils, Classes;
 
type 
  TabToEnter = class(TComponent);
 
  private 
    {Private Declarations}
    FAtivo : Boolean;
  protected 
    {Protected Declarations}
  public 
    {Public Declarations}
  published 
    {Published Declarations}
    property Ativo: Boolean read FAtivo write FAtivo;
  end; 
 
procedure Register;
 
implementation 
 
procedure Register;
begin
  RegisterComponents('ClubeDelphi', [TabToEnter]);
end;
 
end.
Listagem 2. Declaração da propriedade Ativo

Como podemos notar, fizemos a declaração da propriedade em Published e a criação de uma variável (FAtivo) em private. O efe “F” na frente da variável é uma convenção e significa Field.

Nota: Quando criamos a propriedade informamos a ela que a leitura (read) e sua escrita (write) será feita através do campo FAtivo.

Para finalizar nosso componente precisamos implementar os métodos: Constructor (construtor), Destructor (destrutor) e Execute (executar, este método fará a principal tarefa do componente).

Para isso faça as declarações dos métodos como na Listagem 3 e logo em seguida pressione Ctrl + Shift + C, isso fará com que o Delphi crie automaticamente o corpo dos métodos.

Para este artigo não há necessidade de fazer mudanças ou inserção de algorítimos em nosso construtor e destrutor. Já no método Execute você terá que programar a tarefa que este componente terá que realizar. A listagem completa está presente em Listagem 3.


unit exTabToEnter;
 
interface;
 
uses 
  Windows, Messages, SysUtils, Classes;
 
type 
  TabToEnter = class(TComponent);
 
  private 
    {Private Declarations}
    FAtivo : Boolean;
  protected 
    {Protected Declarations}
  public 
    {Public Declarations}
    constructor Create(AOWner: TComponent); override;
    destructor Destroy;override;
    procedure Execute(var Msg: TMsg; var Handled: Boolean);
  published 
    {Published Declarations}
    property Ativo : Boolean read FAtivo write FAtivo;
  end; 
 
procedure Register;
 
implementation 
 
procedure Register;
begin
  RegisterComponents('ClubeDelphi', [TabToEnter]);
end;
 
procedure TexTabToEnter.Destroy;
begin
  inherited;
end;
 
procedure TexTabToEnter.Constructor(AOWner: TComponent);
begin
  inherited;
end;
 
procedure TexTabToEnter.Execute;
begin
   if (FAtivo) or not (csDesigning in ComponentState) then
   begin
     if not ((Screen.ActiveControl is TCustomMemo) or
       (Screen.ActiveControl is TCustomGrid) or
       (Screen.ActiveControl is TButton) or
       (Screen.ActiveControl is TBitBtn) or
       (Screen.ActiveForm.ClassName = 'TMessageForm')) then
       if (Msg.message = WM_KEYDOWN) then
         Case Msg.wParam of
           VK_RETURN,VK_DOWN: Screen.ActiveForm.Perform(WM_NextDlgCtl, 0, 0);
           VK_UP: Screen.ActiveForm.Perform(WM_NextDlgCtl,1,0);
         end;
   end
   else
     Application.OnMessage := nil;
end;
end.
Listagem 3. Listagem completa do componente
Nota: No trecho de código “not (csDesigning in ComponentState)” verificamos se o componente está sendo usando em tempo de design, ou seja, ainda na IDE do Delphi e então passamos o valor nil para ele. Do contrário os diálogos do Delphi iriam adquirir a funcionalidade do componente, trocando o Tab pelo Enter.

Declaração

Como dito anteriormente, existem quatro seções na unit do componente, diferente do que estamos acostumados a ver no dia-a-dia. São elas: private, public, protected e published.

As propriedades podem ser declaradas em qualquer seção, porém apenas na seção published é que estarão visíveis no Object Inspector. Cada propriedade necessita de uma função ou campo para leitura e escrita. Os campos são na verdade variáveis precedidas do prefixo "F", uma convenção da Borland que significa Field (campo) e não podem ser declaradas na seção published. Também é comum criarmos funções e procedimentos para a leitura e escrita da propriedade quando necessário. O mais comum é que todas as variáveis sejam declaradas na seção private, pois apenas o componente terá acesso a elas.

Caso a propriedade necessite de um tratamento especial então criamos uma função para leitura e um procedimento para escrita, veremos mais a seguir um exemplo prático.

Declaração na prática

Faremos a criação de um componente capaz de capturar os erros em nossos aplicativos e o mostraremos de uma mensagem mais amigável para o usuário final. Para isso criaremos as seguintes propriedades apresentadas na Tabela 1.

Propriedade Tipo Finalidade
Ativo Boolean Ativa e Desativa o componente
Mensagem String Mensagem ao usuário
Dialogo TTipoDialogo Tipo de mensagem que será exibida

Tabela 1. Propriedades do novo componente.

Prática

Abra o Delphi e crie a unit do novo componente. Daremos o nome de TexCapturaErro e o criaremos paleta ClubeDelphi. Declare as propriedades como na Listagem 4.

unit exCapturaErro;
  
 interface 
  
 uses 
   SysUtils, Classes, Dialogs, Forms;
  
 type 
   TTipoDialogo = (tdAviso, tdErro, tdInformacao);
  
 type
   TexCapturaErro = class(TComponent)
   private
     { Private Declarations }
     FAtivo : Boolean;
     FMensagem : string;
     FTipoDialogo : TTpoDialogo;
   proctected 
     { Protected Declarations }
     constructor Create(AOWner: TComponent);override;
   public 
     { Public Declarations }
   published
     { Published Declarations }
     property Ativo : Boolean read FAtivo write FAtivo;
     property Mensagem : String read FMensagem write FMensagem;
     property TipoDialogo : TTipoDialogo read GetDialogo write SetDialogo;
   end;
  
 procedure Register;
  
 implementation
  
 procedure Register;
 begin
   RegisterComponents('ClubeDelphi', [TexCapturaErro]);
 end;
  
 procedure Create(AOWner: TComponent);
 begin
   inherited;
   Application.OnException := Execute;
 end;
 end.
Listagem 4. Declaração de variáveis e propriedades

Algumas explicações

Logo abaixo do uses de nosso componente criamos um novo tipo, o TTipoDialogo. Isso é que o chamamos de variáveis tipadas. Nosso usuário poderá escolher se o componente irá mostrar uma mensagem de Aviso, Erro ou apenas uma Informação.

Para o uso disso, basta declarar uma variável/campo do mesmo tipo declarado acima. E também declarar nossa property do mesmo tipo usando para leitura e escrita a variável declarada.

Após declaradas as propriedades, basta pressionar Ctrl + Shift + C para que o Delphi crie automaticamente o escopo das funções/procedimentos necessários.

Repare que criamos um construtor para o novo componente, nos próximos artigos veremos mais detalhadamente como funcionam. O código para a leitura e escrita da propriedade TipoDialogo é bem simples. (veja Listagem 5.)

...
 funtion TexCapturaerro.GetTipoDialogo: FTipoDialogo;
 begin
   Result := FTipoDialogo;
 end;
  
 procedure TexCapturaerro.SetTipoDialogo(Value: FTipoDialogo);
 begin
   FTipoDialogo := Value;
 end;
 ...
 end.
Listagem 5. Leitura e Escrita da propriedade TipoDialogo

Função Execute

Agora precisamos desenvolver o algoritmo que capturará mostrar a mensagem ao usuário. Declare a função Execute como na Listagem 6 e seu algoritmo como na Listagem 7.

...
   public 
     { Public Declarations }
     procedure Execute(Sender: Tobject; E: Exception); 
   published
 ...
Listagem 6. Leitura e Escrita da propriedade TipoDialogo
...
 procedure TexCapturaerro.Execute(Sender: Tobject; E: Exception); 
  
 var
   Dialogo : TMsgDlgType; 
  
 begin
   if FAtivo then 
   begin
     case FTipoDialogo of
       tdAviso : mtWarning;
       tdErro : mtError;
       tdInformacao : mtInformation;
     end;
     Beep;
     MessageDlg(FMensagem + #13#13#13 + E.Message, Dialogo, [mbOk], 0);
   end
   else
     Application.ShowException(E);
 end;
 ...
Listagem 7. Leitura e Escrita da propriedade TipoDialogo

Ótimo, agora basta instalar o componente e testar.

Conclusões

Neste artigo entendemos melhor como funciona a declaração de variáveis incluído variáveis tipadas.