Share |

Class Interceptor

Num outro documento falei dos Class Helpers, uma maneira de adicionar novas propriedade e métodos a uma classe já existente. Estes permitem que todos os componentes de uma classe passem a ter essas novas propriedade e métodos sem ser necessário registar um novo componente.

No entanto, os Class Helpers não permitem que se adicionem novas variáveis à classe, visto que as variáveis têm de ser sempre definidas antes das propriedade e métodos, e quando criamos um Helper, o nosso código é adicionado ao fim das declarações da classe mãe.

Para isto, temos de criar uma sub-classe da primeira.
Mas isto trás-nos de novo ao problema de, ou se regista esta sub-classe como um novo componente para o podermos usar em DesignTime, ou criamos o componente em RunTime, perdendo a vantagem do RAD.

E aqui entram os Class Interceptors: Sub-Classes de uma classe já existente mas que usa o mesmo nome da classe mãe, para “enganar” o compilador.

A primeira regra de um Interceptor é então que tenha o mesmo nome da classe que queremos derivar.
A segunda regra é que a definição do Interceptor venha depois da definição da classe principal. Nomeadamente, se colocarmos o Interceptor na sua própria unit, devemos chamar essa unit depois de chamar a unit que contém o componente original.


Para exemplificar, vamos criar um componente derivado de um TButton, mas que tenha dois estados: Ligado e Desligado.
Ao clicar uma vez, o botão fica no estado Ligado. Ao clicar uma segunda vez, o botão volta ao estado normal.
Precisamos ainda de de uma propriedade que nos permita ligar ou desligar esta opção, por forma a podermos usar o TButton da forma tradicional sempre que quisermos.

unit ToogleButton;
 
interface
 
uses
    StdCtrls, Controls;
 
type
    TButton = Class (StdCtrls.TButton)
      Private
        State: Boolean;   // Memoriza o estado do botão (ligado ou desligado). O Default é desligado
        Toogle: Boolean;  // Memoriza o tipo de botão: True = ToogleButton  False = TButton tradicional
        procedure SwitchState (CheckedState:Boolean);  // Alterna entre os estados Ligado e Desligado
      Public
        property Checked: Boolean read State write SwitchState;   // Define em RunTime o estado do botão
        property ToogleButton: Boolean read Toogle write Toogle;  // Define o tipo de botão, atribuindo um valor à variável Toogle
        procedure Click; Override;  // Captura o evento OnClick do botão, e adiciona a alternancia entre estados ao código já exitente
    End;
 
implementation
 
procedure TButton.SwitchState(CheckedState:Boolean);
begin
     State:=Not State;   // Alterna o estado do botão
 
     // Define o aspecto visual do botão para o estado seleccionado
     if State then begin
                        BevelKind:=bkFlat;
                        BevelInner:=bvLowered;
                   end
              else begin
                        BevelKind:=bkNone;
                        BevelInner:=bvRaised;
                   end;
end;
 
procedure TButton.Click;
begin
     if Toogle then SwitchState(Not State);  // Se for um ToogleButton, alterna o estado actual
     inherited;  // Resume o código existente no evento OnClick
end;
 
end.


Para utilizar, basta definir um TButton na nossa form, adicionar a unit ToogleButton à cláusula Uses e definir a propriedade ToogleButton do novo botão para True no OnCreate da form.

unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ToogleButton;
  //  A unit ToogleButton é declarada depois da unit StdCtrls, que é a unit onde
  // está definida a classe TButton
  //  Se fosse colocado ao contrário, o compilador iria dar erro, pois a classe
  // TButton assumida seria a original não o Interceptor
 
type
  TForm1 = class(TForm)
    Button1: TButton;  // Vai assumir a última instância encontrada da TButton, neste caso, o Interceptor
    Edit1: TEdit;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
procedure TForm1.Button1Click(Sender: TObject);
// Ao executar o evento OnClick, o estado irá mudar automáticamente
begin
     if Button1.Checked   // Mostra o estado actual do botão, com um texto inserido no TEdit (apenas para teste)
        then Edit1.Text:='Ligado'
        else Edit1.Text:='Desligado';
end;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
     Button1.ToogleButton:=True;  // Activa a função ToogleButton do Interceptor
end;
 
end.




You could leave a comment if you were logged in.
dev_geral/pascal/delphi/class_interceptor.txt · Esta página foi modificada pela última vez em: 2012/01/29 14:04 por thoga31

Share |
Voltar ao topo
chimeric.de = chi`s home Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0