Construção de Componentes II
Certa ocasião, o cliente solicitou que numa tela de consulta, fosse construído um temporizador. O objetivo era que, segundo um valor pré-configurado pelo usuário, o sistema, regularmente, desse um refresh na consulta. Essa funcionalidade deveria, através de algum componente visual, exibir o tempo restante até que disparasse a próxima atualização. Para isso, poderíamos usar uma barra de progressão ou simplesmente um Label.
Neste artigo vamos trabalhar num componente que possa atender esse tipo de requisito.
Neste artigo vamos trabalhar num componente que possa atender esse tipo de requisito.
Dicas
Observar os conceitos discutidos no artigo sobre escopo de visibilidade. Isso é extremamente importante neste momento.
Dominar o conceito de polimorfismo do paradigma OO, também discutido em artigos anteriores (meus e do Felipe).
Relembrando, o que colocamos no artigo Construção de Componentes I, devemos construir um componente sempre a partir de um outro pré-existente, seja ele extendido direto da VCL ou extendido de outro construído por você (recursivamente). Uma consideração é extremamente importante: Qual a classe hierarquicamente mais alta (mais abstrata), possuidora das características essenciais do objeto que pretendo construir? Essa será a classe base, da qual herdará o seu componente. Quando você souber responder essa pergunta com precisão, estará um passo na frente para ser um bom construtor de componentes. Um pré-requisito fundamental para isso, é conhecer bem a VCL e ter sempre por perto uma boa referência para consultar. O Help do Delphi não pode faltar neste contexto (O Diagrama da VCL também é bem legal).
O que posso adiantar que invariavelmente, num universo de coisas mais simples, corriqueiras, o feijão com arroz do dia-a-dia, o componente que você pretende construir estará dentro de três grupos bases de classes:
Dominar o conceito de polimorfismo do paradigma OO, também discutido em artigos anteriores (meus e do Felipe).
Relembrando, o que colocamos no artigo Construção de Componentes I, devemos construir um componente sempre a partir de um outro pré-existente, seja ele extendido direto da VCL ou extendido de outro construído por você (recursivamente). Uma consideração é extremamente importante: Qual a classe hierarquicamente mais alta (mais abstrata), possuidora das características essenciais do objeto que pretendo construir? Essa será a classe base, da qual herdará o seu componente. Quando você souber responder essa pergunta com precisão, estará um passo na frente para ser um bom construtor de componentes. Um pré-requisito fundamental para isso, é conhecer bem a VCL e ter sempre por perto uma boa referência para consultar. O Help do Delphi não pode faltar neste contexto (O Diagrama da VCL também é bem legal).
O que posso adiantar que invariavelmente, num universo de coisas mais simples, corriqueiras, o feijão com arroz do dia-a-dia, o componente que você pretende construir estará dentro de três grupos bases de classes:
1- TWinControl:
Classe base para todo componente baseado em janela. Ou seja, a idéia de janelas que o
SO Windows transmite. As características mais marcantes dessa classe são:
1.1 Pode receber foco.
1.2 Obter mensagens do Windows.
1.3 Pode trabalhar com Handles de janelas. Em suma, você pode ficar moito próximo as
APIS do Windows. Finalizando, para trabalhar com essa categoria de classes você
deverá herdar seu componente de TCustomControl.
2- TGraphicControl:
Classe base para os componentes visuais que não possuem handle do Windows. Característica que
pode ser bastante preferível quando você deseja economizar recursos do SO. Em contraste com a
classe TWinControl , TGraphicControl não recebe foco, tão pouco pode trabalhar com mensagens do
Windows. Para você criar um componente gráfico desta categoria de classes deverá extender seu
componente de TCustomControl.
3 – TComponent:
Esta é a superclasse de todos os componentes. Inclusive os “controles” (“TGenecosControls”, digamos) .
Entretanto, quando o componente que você desejar criar não possuir características visuais essa classe
poderá ser ideal para atender sua necessidade. TComponent é a classe mais alta da VCL a possuir propriedades
(Properties). Nela surge a propriedade “Name”, por exemplo. Outro ponto importante é que nela surge o conceito
de Owner, cujo a importância falaremos um pouco adiante. A classe TComponent extende de TPersistent e apresentam
importantes características:
3.1 Integração com IDE:
A habilidade para serem adicionados em uma paleta de componentes da IDE.
Capaz de serem manipulados em tempo de projeto (design time).
3.2 Proprietariedade (Ownership):
A habilidade para administrar outros componentes. Se um componente A possui
o componente B, então A é responsável por destruir B, quando A é destruído.
Isso é muito importe e nos remete ao que foi discutido no artigo sobre o uso
do método “Free” ou “Destroy”. Lembre-se que quando estamos trabalhando com
uma variável cujo tipo é uma classe, obrigatoriamente estaremos alocando memória
dinamicamente. Portanto, somos responsáveis por gerenciar a liberação da mesma.
3.3 Streaming e Filing:
características de persistência herdadas de TPersistent.
3.4 Suporte a COM:
Podem ser convertidos em controles de ActiveX, objetos COM do Windows.
Os TComponents podem ser encapsulados por objetos COM.
Um Diagrama rezumido da VCL
Como no mundo real, os componentes existentes, em muitos casos, são objetos compostos por um conjunto de outros objetos. Da mesma forma, posso aproveitar essa idéia para montar o meu temporizador com display. O qual chamarei de ZNDisplayTimer. Sendo fiel a minha linha de raciocínio, vou compor o ZNDisplayTimer por dois componentes, inicialmente: Um Timer (TTimer), e um Label (TLabel).
Vou aproveitar este artigo para experimentarmos esse efeito na prática, o nosso componente será capaz de, em tempo de projeto exibir o tempo restante para ele executar uma ação.
Vamos ao que interessa .... Codificando
Inicie a construção do nosso novo componente, no menu do Delphi: Component ►New Component (Ou alternada mente digite “Alt ► C ► N”).Vou preferir herdar o componente de TCustomLabel, porque a partir dessa classe eu posso decidir o que eu vou esconder (encapsular), e o que eu vou permitir acesso na que pretendo criar, a qual chamarei de TZNDisplayTimerUltimate. Neste caso específico, pretendo esconder a propriedade “Caption”. Minha finalidade com isso é não permitir que o programador que vier fazer uso deste componente não se confunda e atribua valor para essa propriedade. O que tornaria o comportamento do ZNDisplayTimer deficiente.
type
TZNDisplayTimerUltimate = class(TCustomLabel)
private
{ Private declarations }
protected
{ Protected declarations }
public
{ Public declarations }
published
property Align;
property Alignment;
property Color;
property Font;
property ParentColor;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ShowHint;
property Transparent;
property Visible;
end;
Das propriedades originais, as que pretendo expor são as digitadas no trecho de código acima: Align, Alignment, Color, Font, ParentColor, ParentFont, ParentShowHint, PopupMenu, ShowHint, Transparent, Visible. Digite conforme o exemplo acima, em seguida salve sua unit. Tudo que é declarado na seção “published” ficará listado no Object Inspector.
Além dessas propriedades, preciso de uma que armazene o valor que definirá o período entre a execução da ação desejada (essa ação inicialmente desejamos atualizar uma consulta). Denominarei essa propriedade de “ResetTimeValue”. Outra somente de leitura que indicará o valor corrente do tempo, cujo o nome será: “CurrentTimeValue”. Veja a seguir:
type
TZNDisplayTimerUltimate = class(TCustomLabel)
private
{ Private declarations }
protected
{ Protected declarations }
public
{ Public declarations }
published
property Align;
property Alignment;
property Color;
property Font;
property ParentColor;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ShowHint;
property Transparent;
property Visible;
(* Acrescente as linhas abaixo e pressione “Ctrl + Shift + C *)
property ResetTimeValue: Integer;
property CurrentTimeValue: Integer FCurrentTimeValue default 0;
end
O Delphi vai auto-completar a codificação das propriedades novas.
.
.
.
property ShowHint;
property Transparent;
property Visible;
property ResetTimeValue: Integer read FResetTimeValue write SetResetTimeValue;
property CurrentTimeValue: Integer read FCurrentTimeValue default 0;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('EstacaoZn', [TZNDisplayTimerUltimate]);
end;
{ TZNDisplayTimerUltimate }
procedure TZNDisplayTimerUltimate.SetResetTimeValue(const Value: Integer);
begin
FResetTimeValue := Value;
end;
Agora vou definir o componente interno possuidor da capacidade de ser um temporizador, um TTimer. Vou cuidar para que ele fique encapsulado porque, partindo do mesmo princípio que usei para esconder o caption do Label, não quero que meu componente Dilpay seja usado equivocadamente. Portanto, a fim de esconder, principalmente, o evento OnTimer (O qual terá um papel fundamental para o comportamento do ZNDisplayTimer), bem como as demais propriedades da classe TTimer, vou defini-lo na seção “protected”. Entretanto, isso demandará a codificação de uma interface para comunicação com as propriedades do Timer.
Esse encapsulamento é muito importante, pois somente mediante a manipulação do componente da forma que planejei, conseguirei garantir, em qualquer circunstancia, não importando o programador, o comportamento adequado para o nosso componente. Entenda que embora este componente tenha características de um temporizador, ou melhor, conforme especifiquei no inicio do artigo, seja de fato um, não quero deixar sombra de dúvida que ele não é, em essência, igual ao TTimer da VCL. Ele especializa um TTimer, e possui uma finalidade específica, bem diferente do seu progenitor. Veja o trecho abaixo:
Esse encapsulamento é muito importante, pois somente mediante a manipulação do componente da forma que planejei, conseguirei garantir, em qualquer circunstancia, não importando o programador, o comportamento adequado para o nosso componente. Entenda que embora este componente tenha características de um temporizador, ou melhor, conforme especifiquei no inicio do artigo, seja de fato um, não quero deixar sombra de dúvida que ele não é, em essência, igual ao TTimer da VCL. Ele especializa um TTimer, e possui uma finalidade específica, bem diferente do seu progenitor. Veja o trecho abaixo:
type
TZNDisplayTimerUltimate = class(TCustomLabel)
private
{ Private declarations }
FResetTimeValue: Integer;
FCurrentTimeValue: Integer;
procedure SetResetTimeValue(const Value: Integer);
protected
FTimer: TTimer;
public
{ Public declarations }
published
property Align;
property Alignment;
property Color;
property Font;
property ParentColor;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ShowHint;
property Transparent;
property Visible;
property ResetTimeValue: Integer read FResetTimeValue write SetResetTimeValue;
property CurrentTimeValue: Integer read FCurrentTimeValue default 0;
(*As linhas abaixo implementam a interface com o componente FTimer. Após digitar pressione “Ctrl + Shift + C” *)
property EnabledTimer: Boolean read GetEnabledTimer write SetEnabledTimer default False;
property Interval: Integer read GetInterval write SetInterval;
end;
Neste momento, quero chamar a atenção para o fato de que, quem está construindo um componente deve arquitetar sua construção considerando a possibilidade desse componente ser extendido mais tarde. Ou seja, imaginar que seu componente poderá ser superclasse para um outro que o especializará. Não julgo que este exemplo, especificamente, constitua o cenário mais adequado para situação que descrevi. Todavia, mais uma vez sobre a premissa de uma ênfase didática, vou aproveitar e exemplificar aqui, como preparar sua classe para que ela seja herdada. Por isso, defini o campo FTimer, na “protected” e não na “private”. Visto que, isso o tornaria inacessível para o caso de um extensor. Logo, seguindo esta mesma linha de raciocínio, os métodos, “GetEnabledTimer” e “SetEnabledTimer” que fazem a interface para a propriedade “EnabledTimer”. Bem como, “GetInterval” e “SetInterval”, que fazem o mesmo para a propriedade “Interval”, serão definidos na seção “protected” e serão marcados como “virtual”, viabilizando assim a possibilidade de polimorfismo, no herdeiro. Se você pressionou “Ctrl + Shift + C” como recomendado acima, verá que o Delphi auto-completou a codificação do corpo dos métodos que citei na “implemantation”, sendo que suas assinaturas foram parar na “private”. Retire a assinatura dos métodos que citei (GetEnabledTimer e SetEnabledTimer, GetInterval e SetInterval) da seção “private” e transporte para a seção “propected” imediatamente abaixo da definição o campo “FTimer”. Em seguida marque-os com a diretiva “virtual”, conforme o trecho abaixo:
type
TZNDisplayTimerUltimate = class(TCustomLabel)
private FResetTimeValue: Integer;
FCurrentTimeValue: Integer;
procedure SetResetTimeValue(const Value: Integer);
{ Private declarations }
protected
FTimer: TTimer;
function GetEnabledTimer: Boolean; virtual;
function GetInterval: Integer; virtual;
procedure SetEnabledTimer(const Value: Boolean); virtual;
procedure SetInterval(const Value: Integer); virtual;
public
{ Public declarations }
published
property Align;
property Alignment;
property Color;
property Font;
property ParentColor;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ShowHint;
property Transparent;
property Visible;
property ResetTimeValue: Integer read FResetTimeValue write SetResetTimeValue;
property CurrentTimeValue: Integer read FCurrentTimeValue default 0;
property EnabledTimer: Boolean read GetEnabledTimer write SetEnabledTimer default False;
property Interval: Integer read GetInterval write SetInterval;
end;
Em seguida vamos codificar os corpo dos métodos que acabamos de criar.
1 - GetEnabledTimer
function TZNDisplayTimerUltimate.GetEnabledTimer: Boolean;
begin
Result := FTimer.Enabled;
end;
2 - GetInterval
function TZNDisplayTimerUltimate.GetInterval: Integer;
begin
Result := FTimer.Interval;
end;
3 - SetEnabledTimer
procedure TZNDisplayTimerUltimate.SetEnabledTimer(const Value: Boolean);
begin
FTimer.Enabled := Value;
end;
4 - SetInterval
procedure TZNDisplayTimerUltimate.SetInterval(const Value: Integer);
begin
FTimer.Interval := Value;
end;
Sobrescrevendo um Método – Override:
Por falar em polimorfismo, agora vamos especializar o método “constructor” da classe TCustomLabel, a fim de configuramos de maneira adequada a “TZNDisplayTimerUltimate”. Na seção “public” digite conforme ilustrado no trecho abaixo:
protected
procedure UpdateClock(Sender: TObject);
procedure UpdateCurrentTime(const Multiplicador: Integer);
public
(* Digite o construtor e pressione “Ctrl + Shift + C” *)
constructor Create(AOwner: TComponent); override;
Sobrescrevendo o construtor da classe ..... Após marcar o método “Create”, construtor, com a palavra chave “override”, vou codificar para instanciar o componente interno (temporizador) e setar os valores default.
constructor TZNDisplayTimerUltimate.Create(AOwner: TComponent);
begin
(* evocando o método do ancestral *)
inherited Create(AOwner);
(* Instanciando o componente interno*)
FTimer := TTimer.Create(Self);
(* Configurando a Classe com valores default *)
FTimer.Name := 'ZnDisplayTimer';
FTimer.Enabled := False;
FCurrentTimeValue := 0;
FResetTimeValue := 5;
end;
Codificando a funcionalidade do TZNDisplayTimerUltimate
O componente deverá possuir duas funcionalidades. Elas deverão ser sincronizadas e dependentes:
1° Ação- De tempos em tempos disparar uma ação, sendo que, o intervalo entre as ações deve ser constante podendo ser, dinamicamente, definido pelo usuário do sistema. Implementaremos ela em forma de evento e a propriedade que definirá esse intervalo é a “ResetTimeValue”.
2° Ação – Exibir o tempo restante para a próxima ação disparada. A propriedade “Caption” que vamos absorver da classe TCustomLabel.
Na seção “Type” vamos definir o evento que implementará a primeira ação do nosso componente.
Vejamos o código abaixo:
type
(* Primeiro codifique o evento *)
TExecuteEvent = procedure(Sender: TObject) of object;
TZNDisplayTimerUltimate = class(TCustomLabel)
private
FTimer: TTimer;
FResetTimeValue: Integer;
FCurrentTimeValue: Integer;
FResetMod: TResetMod;
.
.
.
constructor Create(AOwner: TComponent); override;
published
.
.
.
property Align;
property Alignment;
(*Em seguida, digite a propriedade aqui, assim ela seja listada no
Object Inspector *)
property OnExecute: TExecuteEvent read FOnExecute write FOnExecute;
Ao pressionar “Ctrl + Shift + C” será criado o campo privado “FOnExecute”, veja abaixo:
type
TExecuteEvent = procedure(Sender: TObject) of object;
TZNDisplayTimerUltimate = class(TCustomLabel)
private
FResetTimeValue: Integer;
FCurrentTimeValue: Integer;
FOnExecute: TExecuteEvent;
procedure SetResetTimeValue(const Value: Integer);
{ Private declarations }
protected
FTimer: TTimer;
.
.
O Evento “OnExecute” esta pronto, a primeira funcionalidade está implementada. Agora, vamos tratar da exibição e do sincronismo ente a contagem do tempo e a execução do evento.
type
TExecuteEvent = procedure(Sender: TObject) of object;
TZNDisplayTimerUltimate = class(TCustomLabel)
private
FResetTimeValue: Integer;
FCurrentTimeValue: Integer;
FOnExecute: TExecuteEvent;
procedure SetResetTimeValue(const Value: Integer);
protected
FTimer: TTimer;
function GetEnabledTimer: Boolean; virtual;
function GetInterval: Integer; virtual;
procedure SetEnabledTimer(const Value: Boolean); virtual;
procedure SetInterval(const Value: Integer); virtual;
procedure UpdateClock(Sender: TObject); virtual;
procedure UpdateCurrentTime(const Multiplicador: Integer); virtual;
public
constructor Create(AOwner: TComponent); override;
published
.
.
.
Na seção “protected” declarei dois procedimentos e os marquei com a diretiva virtual, preparando a classe para ser extendida. Mais uma vez o bom e velho “Ctrl + Shift + C” e vamos codificar cada um deles. Adicione na seção “uses” da “implementation” a unit “DateUtils”.
implementation
uses
DateUtils;
Por falar em uses, veja como deve estar a seção “uses” da “interface” .
interface
uses
SysUtils, Classes, Controls, StdCtrls, ExtCtrls;
.
.
.
Codificando o método UpdateCurrentTime.
procedure TZNDisplayTimerUltimate.UpdateCurrentTime(
const Multiplicador: Integer);
var
AuxSecond: Integer;
begin
AuxSecond := SecondOf(Time);
if ((AuxSecond * Multiplicador) mod FResetTimeValue = 0) then
FCurrentTimeValue := 1
else
FCurrentTimeValue := FCurrentTimeValue + 1;
end;
FCurrentTimeValue indica o valor do tempo corrente. O método acima incrementa o campo ou reseta seu valor caso ele atinja o limite determinado para isso. Ou seja, a cada intervalo determinado no campo FResetTimeValue o campo FCurrentTimeValue é resetado, recebendo valor 1. Enquanto isso não acontece ele é incrementado. O Parâmetro “Multiplicador” serve para flexibilizar nosso componente, de maneira que ele seja capaz de trabalhar com a ordem de grandeza segundo, minuto, ou hora. Basta para isso variar o valor do multiplicador entre: 1 para segundo, 60 para minuto, 360 para hora.
No método seguinte faremos a chamada ao “UpdateCurrentTime”, atualizaremos o “Caption” para assim exibir o valor de “FCurrentTimeValue” em seguida. A cada vez que ele for resetado dispararemos o evento “OnExecute”.
No método seguinte faremos a chamada ao “UpdateCurrentTime”, atualizaremos o “Caption” para assim exibir o valor de “FCurrentTimeValue” em seguida. A cada vez que ele for resetado dispararemos o evento “OnExecute”.
procedure TZNDisplayTimerUltimate.UpdateClock(Sender: TObject);
begin
(*Atualizando o tempo corrente*)
UpdateCurrentTime(1);
(*Atribuindo o valor atualizado na propriedade de output do componente*)
Self.Caption := IntToStr(FCurrentTimeValue);
(*Caso o campo tenha seido resetado dispara o evento OnExecute*)
if (FCurrentTimeValue = 1) then
if Assigned(FOnExecute) then FOnExecute(Self);
end;
Agora voltaremos ao construtor para a última configuração.
constructor TZNDisplayTimerUltimate.Create(AOwner: TComponent);
begin
(* evocando o método do ancestral *)
inherited Create(AOwner);
(* Instanciando o componente interno*)
FTimer := TTimer.Create(Self);
(* Configurando a Classe com valores default *)
FTimer.Name := 'ZnDisplayTimer';
FTimer.Enabled := False;
FCurrentTimeValue := 0;
FResetTimeValue := 5;
(*Ao evento onTimer atribuimos o método que possui
a principal funcionalidade do nosso componente*)
FTimer.OnTimer := UpdateClock;
end;
Agora que nosso componente está pronto o adicione a package que criamos no artigo anterior sobre construção de componentes. Compile a package e re-instale.
Clik em "Browse..." para selecionar a unit do seu component (ZNDisplayTimerUltimate.pas), em seguida click "OK"
É chegado o momento ... vamos fazer um pequeno programa para testarmos nossa criação.
Testando o componente que criamos
Inicie uma nova aplicação, antes de qualquer coisa feche o projeto da package. No menu do Delphi: File ►Close All. Em seguida, File ► New ►Application.
Adicione o componente ZNDisplayTimerUltimate
Configure a propriedade fonte do ZNDisplayTimerUltimate para um tamanho maior e set sua propriedade “Enabled”, no Object Inspector para True.
e um BitBtn (palheta additional).
No Evento OnExecute do ZNDisplayTimerUltimate
digite .....
procedure TForm1.ZNDisplayTimerUltimate1Execute(Sender: TObject);
begin
ShowMessage('Bla!!!! ... Estação ZN ... Boladão')
end;
Adicione um SpinEdit (palheta Samples), no evento OnCreate do Form1 atribua valor para ele.
procedure TForm1.FormCreate(Sender: TObject);
begin
(*Vamos iniciar a aplicação com o Display desativado*)
ZNDisplayTimerUltimate1.EnabledTimer := False;
(*setando um valor inicial para o SpinEdit1*)
SpinEdit1.Value := 7;
end;
No evento OnClick do BitBtn1 vamos ativar o componente em tempo de execução.
procedure TForm1.BitBtn1Click(Sender: TObject);
begin
( * definindo um novo valor para o intervalo *)
ZNDisplayTimerUltimate1.ResetTimeValue := SpinEdit1.Value;
(*Controlando o ZNDisplay ...*)
ZNDisplayTimerUltimate1.EnabledTimer :=
not (ZNDisplayTimerUltimate1.EnabledTimer);
end;
Execute a aplicação e teste .....
Segue o código completo da aplicação exemplo.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons, ZNDisplayTimerUltimate, Spin;
type
TForm1 = class(TForm)
ZNDisplayTimerUltimate1: TZNDisplayTimerUltimate;
BitBtn1: TBitBtn;
SpinEdit1: TSpinEdit;
procedure ZNDisplayTimerUltimate1Execute(Sender: TObject);
procedure BitBtn1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.ZNDisplayTimerUltimate1Execute(Sender: TObject);
begin
ShowMessage('Bla!!!! ... Estação ZN ... Boladão')
end;
procedure TForm1.BitBtn1Click(Sender: TObject);
begin
ZNDisplayTimerUltimate1.ResetTimeValue := SpinEdit1.Value;
ZNDisplayTimerUltimate1.EnabledTimer :=
not (ZNDisplayTimerUltimate1.EnabledTimer);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
(*Vamos iniciar a aplicação com o Display desativado*)
ZNDisplayTimerUltimate1.EnabledTimer := False;
(*setando um valor inicial para o SpinEdit1*)
SpinEdit1.Value := 7;
end;
end.
O Código completo do componente ...
unit ZNDisplayTimerUltimate;
interface
uses
SysUtils, Classes, Controls, StdCtrls, ExtCtrls;
type
TExecuteEvent = procedure(Sender: TObject) of object;
TZNDisplayTimerUltimate = class(TCustomLabel)
private
FResetTimeValue: Integer;
FCurrentTimeValue: Integer;
FOnExecute: TExecuteEvent;
procedure SetResetTimeValue(const Value: Integer);
{ Private declarations }
protected
FTimer: TTimer;
function GetEnabledTimer: Boolean; virtual;
function GetInterval: Integer; virtual;
procedure SetEnabledTimer(const Value: Boolean); virtual;
procedure SetInterval(const Value: Integer); virtual;
procedure UpdateClock(Sender: TObject); virtual;
procedure UpdateCurrentTime(const Multiplicador: Integer); virtual;
public
constructor Create(AOwner: TComponent); override;
published
property Align;
property Alignment;
property Color;
property Font;
property ParentColor;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ShowHint;
property Transparent;
property Visible;
property ResetTimeValue: Integer read FResetTimeValue write SetResetTimeValue;
property CurrentTimeValue: Integer read FCurrentTimeValue default 0;
property EnabledTimer: Boolean read GetEnabledTimer write SetEnabledTimer default False;
property Interval: Integer read GetInterval write SetInterval;
property OnExecute: TExecuteEvent read FOnExecute write FOnExecute;
end;
procedure Register;
implementation
uses
DateUtils;
procedure Register;
begin
RegisterComponents('EstacaoZn', [TZNDisplayTimerUltimate]);
end;
{ TZNDisplayTimerUltimate }
constructor TZNDisplayTimerUltimate.Create(AOwner: TComponent);
begin
(* evocando o método do ancestral *)
inherited Create(AOwner);
(* Instanciando o componente interno*)
FTimer := TTimer.Create(Self);
(* Configurando a Classe com valores default *)
FTimer.Name := 'ZnDisplayTimer';
FTimer.Enabled := False;
FCurrentTimeValue := 0;
FResetTimeValue := 5;
(*Ao evento onTimer atribuimos o método que possui
a principal funcionalidade do nosso componente*)
FTimer.OnTimer := UpdateClock;
end;
function TZNDisplayTimerUltimate.GetEnabledTimer: Boolean;
begin
Result := FTimer.Enabled;
end;
function TZNDisplayTimerUltimate.GetInterval: Integer;
begin
Result := FTimer.Interval;
end;
procedure TZNDisplayTimerUltimate.SetEnabledTimer(const Value: Boolean);
begin
FTimer.Enabled := Value;
end;
procedure TZNDisplayTimerUltimate.SetInterval(const Value: Integer);
begin
FTimer.Interval := Value;
end;
procedure TZNDisplayTimerUltimate.SetResetTimeValue(const Value: Integer);
begin
FResetTimeValue := Value;
end;
procedure TZNDisplayTimerUltimate.UpdateClock(Sender: TObject);
begin
UpdateCurrentTime(1);
Self.Caption := IntToStr(FCurrentTimeValue);
if FCurrentTimeValue = 1 then
if Assigned(FOnExecute) then FOnExecute(Self);
end;
procedure TZNDisplayTimerUltimate.UpdateCurrentTime(
const Multiplicador: Integer);
var
AuxSecond: Integer;
begin
AuxSecond := SecondOf(Time);
if ((AuxSecond * Multiplicador) mod FResetTimeValue = 0) then
FCurrentTimeValue := 1
else
FCurrentTimeValue := FCurrentTimeValue + 1;
end;
end.
Você pode pesquisar mais sobre o assunto em:
Downloads nos artigos do Bruno (Cod Gear):Artigo completo (View Full Post)
Mini Book About Components' Creation: http://cc.borland.com/Item/24302
Apostila sobre Criação de Componentes Passo a Passo by Bruno Lichot:
Apostila sobre Criação de Componentes Passo a Passo com exemplos e código fonte inclusos.
Mostra como Criar Compoenentes Simples e Componantes DBWare para Banco de Dados.
e-mail: bruno.lichot@gmail.com
lista: nddv@yahoogrupos.com.br
Atenciosamente,
Bruno Lichot
CodeGear Team Brazil
Amigos, com o tempo curto ... foi o que deu pra fazer dessa vez ...
[]’s ...