segunda-feira, 17 de setembro de 2007

Construção de Componentes IV

Na seqüência de artigos sobre criação de componentes você pode observar que podemos criar um componente funcional, pronto para ser instalado na paleta de Componente. Vimos que é possível testar o novo componente, tanto em tempo de design, quanto em runtime Vimos também que, mesmo depois de instalado, você pode acrescentar novas funcionalidades, e características, recompilar e re-instalar o componente e continuar a testa-lo.

Em seguida listaremos alguns passos básicos que você deve executar sempre que for criar um componente novo:

1 Criar uma unidade (unit) para o componente novo:
No menu File ► New ►Unit

2 Derivar seu componente de um tipo de componente pré-existente, descendente direta ou indiretamente da VCL.

3 Adicionar novas properties (propriedades), methods (métodos), e events (eventos).

4 registrar seu componente na IDE.

5 Criam um bitmap para o componente. De maneira que na palheta de componentes da IDE ele seja exibido com uma imagem exclusiva, podendo assim ser identificado facilmente.

6 Criam um pacote (uma biblioteca de dinâmico-ligação especial – Uma Package) de forma que possa organizar logicamente seus componentes ao registrá-los e instala-los na IDE.

7 Criam um arquivo de Ajuda para seu componente, explicando e suas propriedades, métodos, e eventos, facilitando para outros desenvolvedores a consumo do seu componente.


Criando um bitmap para o componente criado.

Conforme mencionado acima, vamos criar uma imagem, bitmap para representar um componente qualquer criado, na palheta de componentes, aonde foi instalado. Na própria IDE do Delphi existe uma ferramenta para editar imagens. Essa ferramenta, é usada para criarmos os bitmaps, os quais podemos associa-los aos componentes que construímos.

Passo 1: No menu Tools ► Image Editor, você executa o editor de imagem ao qual me refiro.




Passo 2: No menu, do “Image Editor” (do Delphi), File ►New ► Component Resource File (.dcr)

Passo 3: Na janela de diálogo, cujo o título é “untitled1.dcr”, na palavra “Contents” clike com o botão direito do mouse, escolha “New | Bitmap”.



Passo 4: No próximo diálo, será solicitado as dimensões do bitmap. Altere o valor para 24 pixels tanto, para altura (Height), quanto para largura (Width). Em colors, selecione VGA (16 colors).



Passo 5: Em resposta, na tela é criado sub-itens abaixo de “Contents”: Bitmap, abaixo dele, Bitmap1. Com o botão direito do mouse sobre “Bitmap1”, selecione “Rename” para nomearmos nosso arquivo.



Nomeie o bitmap1 com o mesmo nome da classe que define o componente criado por você, totalmente em caixa alta. Por exemplo, usaremos o nosso “TZNDisplayTimerUltimate”. Portanto, re-nomeie o bitmap1 com o nome dessa classe, em caixa alta, veja a seguir: “TZNDISPLAYTIMERULTIMATE”.



Passo 6: Com um duplo click sobre “TZNDISPLAYTIMERULTIMATE” você poderá iniciar a edição do bitmap. Desenhe seu bitmap na tela conforme imagem abaixo.



Passo 7: Para salvar, feche a imagem (menu file | Close), em seguida salve no mesmo diretório onde se encontra a sua package.



Passo 8: Agora, basta codificar a diretiva de compilação que inclui o arquivo bitmap que criamos na package que contém o componente para o qual a imagem foi criada. No exemplo em questão, estamos trabalhando com a mesma package dos artigos anteriores: “ZnConstruindoComponenetes”. Portanto, no Delphi, abra a package e na unit ““ZnConstruindoComponenete.dpk” e codifique conforme o trecho abaixo:



{$LONGSTRINGS ON}
{$OPENSTRINGS ON}
{$OPTIMIZATION ON}
{$OVERFLOWCHECKS OFF}
{$RANGECHECKS OFF}
{$REFERENCEINFO ON}
{$SAFEDIVIDE OFF}
{$STACKFRAMES OFF}
{$TYPEDADDRESS OFF}
{$VARSTRINGCHECKS ON}
{$WRITEABLECONST OFF}
{$MINENUMSIZE 1}
{$IMAGEBASE $400000}
{$IMPLICITBUILD OFF}

requires
rtl,
vcl,
designide;

contains
ZnCombo in 'ZnCombo.pas',
ZNDisplayTimerUltimate in 'ZNDisplayTimerUltimate.pas',
ZNDisplayTimerProgress in 'ZNDisplayTimerProgress.pas',
ZnGraphicSeta in 'ZnGraphicSeta.pas',
ZNNode in 'ZNNode.pas',
ZnAresta in 'ZnAresta.pas';

end.



Compile e SALVE a package, conforme demonstrado em artigos anteriores.



Artigo completo (View Full Post)

Novos Tempos - Mart'nália

O coração de quem é Zn bate em dois por quatro. Onde o Surdo e o Tan-tan fazem mais sentido, ecoam deep in my heart.

Gostei bastante desse último trabalho da Mart'nália ...

"NOVOS TEMPOS" uma composição do violonista|Guitarrista, Cláudio Jorge, composta numa viagem em turnê com Martinho da Vila. Segundo reza a lenda, assim que ouviu, Mart'nália, reservou pra ela, exigindo exclusividade: "_ Essa é minha, não dá pra ninguém que um dia eu gravo". Pois é, aconteceu ... Obrigado Claudio Jorge, obrigado Mart'nália. Então por isso mesmo ... lá vai ...

“Se você gosta de samba, encosta e vê se dá ...”




NOVOS TEMPOS
A chuva chega e ela vem lavar
Vem me livrar do mal
É água fresca para aliviar
Meu coração que secou
De tanto pranto derramado
Pela mágoa
Que se instalou no meu peito
De um jeito tão perverso
Hoje se desfaz nesses versos
Um arco-íris se formou no céu
É um sinal
Que a paz está de volta na minha alma
Sinto calma
São novos tempos enfim graças à chuva
Que levou o rancor
Me permitindo viver
Outro grande amor
Graças à chuva
Que levou o rancor
Me permitindo viver
Outro grande amor

Artigo completo (View Full Post)

domingo, 16 de setembro de 2007

Delphi - Alternativas Free

A maioria dos artigos que temos publicado é sobre Delphi, muitas pessoas não tem acesso a essa ferramenta por causa da necessidade de licença. Portanto, listamos alguns links com alternativas free, para você conhecer.

A Borland disponibiliza uma versão free do Delphi. Ela é antiga, não atende a todas as necessidades de um projeto de software atual. Contudo, ainda é muito eficaz, podendo ser usada em alguns projetos onde exista restrição de custos. Ou um projeto que prescinda de alta tecnologia.

Delphi 3 douwnload

Alternativas free ao Delphi:

Free Pascal

http://pt.wikipedia.org/wiki/Free_Pascal

Lazarus:

é um ambiente de desenvolvimento integrado (IDE) para o compilador Free Pascal. O software objetiva ser compatível com o Delphi e, ao mesmo tempo, suportar diversas arquiteturas e sistemas operacionais. O que em muitos aspectos representa uma grande vantagem dessa ferramenta como diferencia de mercado.

Ainda hoje, apesar de toda a popularidade do Delphi, muitos projetos, durante o processo de codificação e implementação, são feitos desprezando as principais características de ponta da ferramenta. Essas características, justamente, justificam a compra da sua licença e diferencia o Delphi diante das demais ferramentas presentes no mercado. Portanto, considerando isso, tanto faz se o projeto está usando a versão atual, uma mais antiga, ou até mesmo um genérico, free, como o Free Pascal ou Lazarus. Se o projeto não faz uso dos componentes Dataware (Conscientes de dados), ou da tecnologia MIDAS/Data Snap (essa por sua vez, na minha opnião é o que justifica o custo de uma licença enterprise).




Artigo completo (View Full Post)

sábado, 1 de setembro de 2007

Construção de Componentes III

Dando continuidade ao assunto, neste artigo pretendo exemplificar o conceito de herança em OO. Neste momento, faremos uma abordagem simples onde nos ateremos somente ao trivial de como fazer isso em Delphi. A minha idéia é tentar chagar ao mais próximo de uma situação real. Acho que dessa forma posso tornar mais acessível o conteúdo desse artigo.
Vou extender a classe que criamos no artigo Construção de Componentes II, para uma que saiba trabalhar também com uma barra de progressão. Para que seja opcional ao programador optar por usar a barra ou não, implementaremos a associação dela com o TZNDisplayTimerUltimate externamente. Na literatura sobre criação de componentes em Delphi você vai encontrar esses termos, componentes compostos internos e externos:

Componentes Internos: Criados e Gerenciados pelo componente pricipal. Esta opção deixa
o componente encapsulado, obtendo a vantagem de se poder decidir o
que vamos publicar ou esconder do componente. Assim como fizemos na
relação do ZnDisplayTimer com o campo FTimer. A desvantagem é o
acoplamento extremo entre os dois componentes. Em determinadas situações
isso pode ser indesejável.

Componentes Externos: São associados através de uma propriedade do componente principal. Temos
um acoplamento bem mais fraco, isso pode ser bastante vantajoso.


Associações

Craig Larman, em Applying UML and Patterns (Traduzido como: Utilizando UML e Padrões), descreve associações entre classes como um relacionamento entre tipos (ou, mais especificamente, instâncias desses tipos). Não esquecendo que devemos entender “tipos” como classes, e que estes relacionamentos indicam uma conexão com significado e interesse. Na UML, as associações são descritas como: “Um relacionamento semântico entre dois ou mais classificadores envolvendo conexão entre suas instâncias


Por que um ProgressBar?

Minha escolha foi justamente por conta da principal funcionalidade do componente que criamos. De forma visual, transmitir ao usuário, uma idéia de quanto tempo falta até que seja disparado um evento. E este evento pode ser usado para se codificar qualquer coisa: A execução de uma consulta, a exibição de um filme, a transmissão de um e-mail, etc...
Toda vez que em seu programa, alguma módulo executar uma ação que demande tempo, você pode usar uma barra de progressão (TProgressBar, da palheta Win32, o TGauge, palheta Samples. Existem ainda vários outros, mais incrementados, como os da JVCL - Jedi) que mostrará quanto da ação ainda resta para ela ser completada. A propriedade “Prosition” do TProgressBar indica o quanto da barra já foi preenchida. As propriedades “Max” e “Mim”, marcam o valor relativo de início e final do preenchimento da barra. Para efetuar o preenchimento gradual da barra faça chamada ao método “StepBy” ou “StepIt”. A Propriedade “Step” determina o valor de incremento que será usado por “StepIt”. Veja um micro-exemplo:

procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
begin
ProgressBar1.Max := 100000000;
ProgressBar1.Min := 0;

for i := 0 to 100000000 do
begin
ProgressBar1.StepBy(i);
end;

end;

Criando o Componente

No Delphi, No menu File ► Open Project ... , abra a unit “ZnConstruindoComponenetes” da package que criamos e temos trabalhado nela nos artigos anteriores sobre componentes. Em seguida, no menu Component ►New Component, vamos criar mais um componente que herdará do temporizador que construímos anteriormente.



Salve a unit ZNDisplayTimerProgress.pas, pois ela já está adicionada a package.



Antes de qualquer coisa adicione na seção uses da interface a unit “ZNDisplayTimerUltimate”. Onde está definido a classe ancestral.


interface

uses
SysUtils, Classes, ZNDisplayTimerUltimate;


Vamos criar a associação entre a classe TZNDisplayTimerProgress e a classe TProgressBar, a qual implementaremos em forma de uma propriedade. Visto que, nosso objetivo é criarmos um componente composto por um componente externo.


type
TZNDisplayTimerProgress = class(TZNDisplayTimerUltimate)
private
{ Private declarations }
protected
{ Protected declarations }
public
{ Public declarations }
published
property ProgressBar: TProgressBar;
end;

Ctrl + Shift + C” para implementarmos o método SetProgressBar. Antes de digitar o código abaixo apague o que você ancontar lá.


{ TZNDisplayTimerProgress }

procedure TZNDisplayTimerProgress.SetProgressBar(
const Value: TProgressBar);
begin
if FProgressBar <> Value then
begin
FProgressBar := Value;
if FProgressBar <> nil then
FProgressBar.FreeNotification(Self);
end;
end;

Pretendo associar um componente ProgressBar ao temporizador, adicionando um, a propriedade que acabamos de codificar. Ora adicionaremos, ora, se necessário, removeremos. um TComponente pode notificar que um outro componente está sendo inserido ou está sendo removido de alguma associação. Por exemplo, se um componente possuir campos ou propriedades cujos tipos sejam referências a outros componentes (outras classes, como no nosso caso), ele pode verificar através das notificações uma remoção de componente, por exemplo, permitindo assim invalidar essas referências evitando “access violate”.
O método FreeNotification, insere um componente, através do parâmetro “AComponent”, numa lista que registra os componentes cujo algumas operações sobre eles deverão ser notificadas ao Owner (componente proprietário). Em outras palavras, isso permite que um componente Owner A, seja notificado que um outro B, numa de suas associações, será destruído. Permitindo que seja implementado tratamento para essa situação. Veja um screenshot da definição deste método na classe TComponent.



Agora vamos sobrescrever o método “Notification” na nossa classe.

procedure Notification(AComponent: TComponent; Operation: TOperation);


Observe na imagem a cima o funcionamento do método “Notification”. O tipo de operação é testado. Caso remoção, indicando que um componente foi removido da lista de componentes associados (FComponents), chama “RemoveFreeNotification”, que remove o componente passado pelo parâmetro (“AComponent”) da lista de componentes notificáveis (FFreeNotifies.Remove(AComponent);)


type TOperation = (opInsert, opRemove);

O parâmetro “Operation”, cujo o tipo é TOpration representa os tipos de operações sobre os componentes registrados na lista de notificações (FFreeNotifies) cujo a ocorrência é propagada pelo método Notification. Os valores definidos por esse tipo são:

opInsert: Indica que um objeto (indicado pelo parânetro AComponent) recentemente foi criado.
opRemove: Indica que um objeto foi destruído.


type
TZNDisplayTimerProgress = class(TZNDisplayTimerUltimate)
private
FProgressBar: TProgressBar;
procedure SetProgressBar(const Value: TProgressBar);
{ Private declarations }
Protected

(*Estamos fazendo herança do método “Notification” e sobrescrevendo ele. *)
procedure Notification(AComponent: TComponent;
Operation: TOperation); override;
public
{ Public declarations }
published
property ProgressBar: TProgressBar read FProgressBar write SetProgressBar;
end;



Testamos através do parâmetro “AComponent” se a notificação ocorrida se refere ao campos FProgressBar, testamos também a operação, caso seja de remoção do componente, limpamos a referência (ao endereço de memória) do componente atribuindo “nill”.

procedure TZNDisplayTimerProgress.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited;
//Remove a referência quando o componente externo é destuido
if (AComponent = FProgressBar) and (Operation = opRemove) then
FProgressBar := nil;
end;


Agora vou ter que fazer uma pequena alteração na superclasse (TZNDisplayTimerUltimate), o método privado “SetResetTimeValue (const Value: Integer);” deve ficar na seção “protected”e ser marcado como “virtual”. Dei um mole nesse ponto, mais nada que não possa ser reajustado sem grandes traumas Logo, voltando a unit “TZNDisplayTimerUltimate”, faça a alteração conforme exemplo abaixo:


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;
(* Este método estava na private, nesnte momento o movi para
a seção "privaate"*).
procedure SetResetTimeValue(const Value: Integer); virtual;
public
constructor Create(AOwner: TComponent); override;


Recompile a package, e salve. Voltemos a unit do “ZNDisplayTimerProgress” para digitarmos a assinatura.


ype
TZNDisplayTimerProgress = class(TZNDisplayTimerUltimate)
private
FProgressBar: TProgressBar;
procedure SetProgressBar(const Value: TProgressBar);
{ Private declarations }
protected
(* Este método estava na private, nesnte momento o movi para
a seção "privaate"*)
procedure SetResetTimeValue(const Value: Integer); override;
procedure Notification(AComponent: TComponent;
Operation: TOperation); override;
public
{ Public declarations }
published
property ProgressBar: TProgressBar read FProgressBar write SetProgressBar;
end;


Agora fazendo o polimorfismo, implementaremos o corpo do método ...


procedure TZNDisplayTimerProgress.SetResetTimeValue(const Value: Integer);
begin
inherited SetResetTimeValue(Value);

if not Assigned(FProgressBar) then Exit;
FProgressBar.Min := 1;
FProgressBar.Max := Value;
end;


Mais um polimorfismo: “UpdateCurrentTime”, neste método vamos incrementar a ProgressBar juntamente com o Label.




type
TZNDisplayTimerProgress = class(TZNDisplayTimerUltimate)
private
FProgressBar: TProgressBar;
procedure SetProgressBar(const Value: TProgressBar);
{ Private declarations }
protected
(* Este método estava na private, nesnte momento o movi para
a seção "privaate"*)
procedure SetResetTimeValue(const Value: Integer); override;
procedure Notification(AComponent: TComponent;
Operation: TOperation); override;

procedure UpdateCurrentTime(const Multiplicador: Integer); override;
public
{ Public declarations }
published
property ProgressBar: TProgressBar read FProgressBar write SetProgressBar;
end;


Codificando o corpo do método ....


procedure TZNDisplayTimerProgress.UpdateCurrentTime(
const Multiplicador: Integer);
begin
inherited UpdateCurrentTime(Multiplicador);

if not Assigned(FProgressBar) then Exit;
FProgressBar.Position := CurrentTimeValue;
end;


Agora re-compile apackage “ZnConstruindoComponenetes” .....



Re-instale, clickando em Instal ...



Para testar o que acabamos de construir, feche o projeto da package, no menu File ►Close All. Em seguida inicie uma nova aplicação no menu File ► New ►Application.


Adicione os seguintes componentes no Form1:

1- Um ProgressBar (Palheta Win32)



Configure as seguintes propriedades:
Left = 8
Top = 80
Width = 350
Font.Color = clNavy
Font.Height = 24
Font.Name = 'MS Sans Serif'
Font.Style = [fsBold]

2- Um componente ZNDisplayTimerProgress (Palheta EstacaoZn).





Configure as seguintes propriedades:
Left = 232
Top = 24
Width = 3
Height = 13
ResetTimeValue = 5
Interval = 1000
ProgressBar = ProgressBar1

As propriedades dos componentes são configuradas no Object Inspector.



3- Um BitBtn (palheta additional).







Configure as seguintes propriedades:
Name = btnAtivar
Left = 16
Top = 16
Width = 75
Height = 25
Caption = '&Ativar'


4- Um SpinEdit (Palheta Samples)



Configure as seguintes propriedades:
Left = 112
Top = 16
Width = 77
Height = 22


5 – Um ListBox (Palheta Standard):

Configure as seguintes propriedades:
Left = 8
Top = 108
Width = 353
Height = 229



Codificando o programa

Primeiro o evento OnCreate do Form1

procedure TForm1.FormCreate(Sender: TObject);
begin
SpinEdit1.Value := 10;
end;


Segundo o evento OnChange do SpinEdit1

procedure TForm1.SpinEdit1Change(Sender: TObject);
begin
ZNDisplayTimerProgress1.ResetTimeValue := SpinEdit1.Value;
end;


Terceiro o evento OnClick do btnAtivar

procedure TForm1.btnAtivarClick(Sender: TObject);
begin
ZNDisplayTimerProgress1.EnabledTimer := not ZNDisplayTimerProgress1.EnabledTimer;
end;



Quarto o evento OnExecute do ZNDisplayTimerProgress1

procedure TForm1.ZNDisplayTimerProgress1Execute(Sender: TObject);
begin
ListBox1.Items.Add('Disparada Ação ' + TimeToStr(Now));
end;






Segue todo o código da Unit referente ao programa teste:



unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Spin, Buttons, ComCtrls, ZNDisplayTimerUltimate,
ZNDisplayTimerProgress;

type
TForm1 = class(TForm)
ZNDisplayTimerProgress1: TZNDisplayTimerProgress;
ProgressBar1: TProgressBar;
btnAtivar: TBitBtn;
SpinEdit1: TSpinEdit;
ListBox1: TListBox;
procedure btnAtivarClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure SpinEdit1Change(Sender: TObject);
procedure ZNDisplayTimerProgress1Execute(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.btnAtivarClick(Sender: TObject);
begin
ZNDisplayTimerProgress1.EnabledTimer := not ZNDisplayTimerProgress1.EnabledTimer;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
SpinEdit1.Value := 10;
end;

procedure TForm1.SpinEdit1Change(Sender: TObject);
begin
ZNDisplayTimerProgress1.ResetTimeValue := SpinEdit1.Value;
end;

procedure TForm1.ZNDisplayTimerProgress1Execute(Sender: TObject);
begin
ListBox1.Items.Add('Disparada Ação '+ TimeToStr(Now));
end;

end.


Para conferir também, segue a unit onde criamos o componente deste artigo:


unit ZNDisplayTimerProgress;

interface

uses
SysUtils, Classes, ZNDisplayTimerUltimate, ComCtrls;

type
TZNDisplayTimerProgress = class(TZNDisplayTimerUltimate)
private
FProgressBar: TProgressBar;
procedure SetProgressBar(const Value: TProgressBar);
{ Private declarations }
protected
(* Este método estava na private, nesnte momento o movi para
a seção "privaate"*)
procedure SetResetTimeValue(const Value: Integer); override;
procedure Notification(AComponent: TComponent;
Operation: TOperation); override;

procedure UpdateCurrentTime(const Multiplicador: Integer); override;
public
{ Public declarations }
published
property ProgressBar: TProgressBar read FProgressBar write SetProgressBar;
end;

procedure Register;

implementation

procedure Register;
begin
RegisterComponents('EstacaoZn', [TZNDisplayTimerProgress]);
end;

{ TZNDisplayTimerProgress }

procedure TZNDisplayTimerProgress.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited;
//Remove a referência quando o componente externo é destuido
if (AComponent = FProgressBar) and (Operation = opRemove) then
FProgressBar := nil;
end;

procedure TZNDisplayTimerProgress.SetProgressBar(
const Value: TProgressBar);
begin
if FProgressBar <> Value then
begin
FProgressBar := Value;
if FProgressBar <> nil then
FProgressBar.FreeNotification(Self);
end;
end;

procedure TZNDisplayTimerProgress.SetResetTimeValue(const Value: Integer);
begin
inherited SetResetTimeValue(Value);

if not Assigned(FProgressBar) then Exit;
FProgressBar.Min := 1;
FProgressBar.Max := Value;
end;

procedure TZNDisplayTimerProgress.UpdateCurrentTime(
const Multiplicador: Integer);
begin
inherited UpdateCurrentTime(Multiplicador);

if not Assigned(FProgressBar) then Exit;

FProgressBar.Position := CurrentTimeValue;
end;

end.

Artigo completo (View Full Post)

 
BlogBlogs.Com.Br