segunda-feira, 20 de agosto de 2007

Construção de componentes - I

Vamos trabalhar num exemplo de construção de componentes. Aplicar na prática os conceitos orientação a objetos, buscar alcançar um alto índice de coesão, e conseqüentemente de re-usabilidade. Sempre vc deve ter foco em alcançar esses objetivos nos módulos que está implementando. A construção de componentes é uma abordagem que se propõe a isso. Constantemente, nos temas que temos discutido aqui no Estação ZN, o paradigma OO tem ocupado um lugar de destaque em nossos artigos. Isso não é por acaso, tão pouco por partidarismo passional, nem mesmo por modismo. O principal e único motivo é porque temos experimentado soluções satisfatórias ao optarmos por essa abordagem no nosso trabalho.
Nos últimos meses temos estado ausentes do blog por conta de um projeto novo onde fomos alocados. Um projeto novo que surgiu da demanda suscitada mediante ao fracasso de um outro. Um projeto do tipo: “Salve minha empresa, pelo amor de Deus, porque esse fracassou!!!”. Pra você ter uma idéia, durante o processo de seleção, a pessoa do RH que me entrevistava, num dado momento, fez uma pergunta inusitada: “Você esta acostumado a salvar causas perdidas?” .... Caracas!! (eu pensei), virei santo (das causas perdidas do TI brasileiro ... creeeeeeeeddddoooooo ....). Bem, dessa história, o que realmente importa é a certeza que tenho adquirido na pratica do dia a dia de trabalho que o sucesso ou o fracasso de um projeto de software passa em grade parte pela abordagem de desenvolvimento que é adotada para seu empreendimento. Pois bem, a relação do projeto fracassado, ao qual me refiro, com o tema deste artigo é justamente a ausência das boas praticas de programação, a ausência do zelo por uma modularização eficiente, a ausência de um processo formal de engenharia de software (adequado a realidade atual do mercado de TI internacional), que caracteriza a forma pela qual o dito cujo fio implementado.
Não obstantemente, também tenho observado que:
Quem com marreta marretar, com marreta será marretado.

Os que pelo martelo de Thor lutam, pelo próprio martelo perecerão
.
Pra bom entendedor, um pingo é letra ....

Portanto, vamos prosseguindo .... neste artigo, o primeiro exemplo ....

VCL

A VCL (Visual Components Library – Biblioteca de componentes visuais) é um conjunto de classes, a qual é usada para definir todos os componentes no Delphi (Botões, Caixas de Texto, Janelas, etc..). Você pode criar novas classes extendidas da VCL e conseqüentemente, definir novos componentes. Estes por sua vez podem ser vinculados a um pacote (package) e instalados na IDE do Delphi.
O que é extender, ou derivar uma classe de outra? Isso é o conceito de herança da orientação a objetos. Uma classe herda (extende) de uma outra seus atributos e métodos, e se especializa acrescentando outras funcionalidades ou características exclusivas. Por exemplo, imagine uma classe automóvel, da qual eu extendo uma nova, a fim de especializa-la para automóvel esportivo. Que é acrescida de uma série de características e funcionalidades exclusivas que a definem como tal, embora inda conserve muito em comum com seu ancestral direto, a classe automóvel.
Note que não vemos nas ruas, tão pouco nas lojas, nenhum veículo que possa ser usado como exemplo da classe automóvel. Dentro da nossa linha de raciocínio, todos os veículos existentes já são extremante especializados, exemplo: Ou temos, automóvel de passeio, Ou automóvel de luxo, automóvel utilitário, automóvel esportivo e etc...
A classe “Automóvel” dentro do nosso contexto é o que conceituamos por classe abstrata. Um tipo de classe que não pode gerar nenhuma instância. Esse tipo de classe possui um propósito servir de modelo, de extensor para outras classes. Na VCL existem inúmeras classes, chamadas de intermediárias (Invariavelmente indicadas com o prefixo “TCustom” em seus nomes) que servem de ponto de partida para você construir seu novo componente a partir de um comportamento padrão pré-existente.
Permita-me fazer um paralelo com Husserl, que afirma que toda consciência é consciência de alguma coisa. Logo, o que você imaginaria construir se não lhe fosse dado conhecer nenhum objeto? Ou, você pode ter certeza que nunca irá precisar construir nada que já não tenha sido conceituado. Portanto, não tem lógica criar uma classe que não descenda de nenhuma outra.
A discussão sobre a importância do desenvolvimento de componentes para uma organização de fábrica de software é algo presente nos principais institutos voltados para área. Academicamente esse assunto é abordado em matérias como Engenharia de Software e Arquitetura de Software. Sou um dos engajados nesse tema, também levanto veementemente esta bandeira. Embora, particularmente, eu tenha algumas reservas em ralação de como a IDE do Delphi trabalha com componentes, acredito que o programador pode aprender muito sobre Delphi e como tirar máximo proveito dessa ferramenta, se empenhado na construção de componentes, buscando aperfeiçoar-se nessa técnica.

Dentre um leque de maneiras possíveis de iniciar um projeto de construção de componentes, no menu do Delphi: File ► New ► Other ► (na Aba New – Conforme figura abaixo) selecione “Component” e click “OK”.



Em seguida uma tela de dialogo do component wizard irá solicitar as informações a seguir:



Ancestror Type: Você define aqui a classe da qual herdará o componente que deseja criar.

Class Name: Onde você define o nome da classe que deseja criar. Ou seja, o nome da classe do novo componente que você está criando.

Pallete Page: A palheta de componente na qual você deseja que seu novo componentes esteja organizado na IDE do Delphi (Standard, Additional, etc). Podendo escolher dentre qualquer uma das existentes ou simplesmente criar uma exclusiva para sua própria biblioteca de componentes novos personalizados. Caso queira criar uma nova basta digitar o nome desejado nesta opção.

Unit File Name: o path, e o nome da unit que será o arquivo “.pas” onde seu componente estará codificado.

Search Path: É aconselhável que essa opção seja configurada automaticamente pelo Delphi, a não ser que você seja um programador avançado. Aqui fica configurado os diretórios onde o Delphi irá procurar as units referenciadas na uses da seu arquivo “.pas” para fazer a link edição.



OBS: A “procedure Register” é o único caso em que um identificador no Delphi tenha que obedecer a diferenciação de caixa. Ou seja, case sensitive. Obrigatoriamente deve iniciar com letra maiúscula. Caso contrário, embora o compilador não reclame, o registro do componente não será efetivado e nenhuma mensagem de erro será emitida.

Em artigos anteriores já expliquei a respeito das palavras reservadas private, protected, public e published. Também mencionei sobre a padronização de iniciar um classe com o prefixo “T” que indica “Type”.

O Componente que decidi construir, visando somente o aspecto didático, trata-se de uma caixa de seleção (que chamamos de combo box) possuidora de uma funcionalidade capaz de alterar o tipo de fonte dos componentes visuais exibidos num formulário. A idéia é permitir que o usuário possa selecionar um tipo de fonte desejado a partir de uma escolha na caixa de seleção. Componente este que vamos construir neste artigo. Estou usando um exemplo conhecido, o qual tomei como base usando como modelo um exemplo do capitulo 9 do livro, a Bíblia do Delphi, do Marco Cantú.

Seção Published
Vamos codificar as propriedades “Style”, “Items”, “ChangeFormFont”. Na seção “published”, dentro de “type” digite conforme trecho a baixo. Em seguida pressione “Ctrl + Shift + C”, simultaneamente.


type
TZnCombo = class(TCustomComboBox)
private
FChangeFormFont: Boolean;
procedure SetChangeFormFont(const Value: Boolean);
{ Private declarations }
protected
{ Protected declarations }
public
{ Public declarations }
published
property Style default csDropDownList;
property Items stored False;
property ChangeFormFont: Boolean read FChangeFormFont write
SetChangeFormFont default True;
end;


Sua unit deverá ficar conforme imagem abaixo após pressionar “Ctrl + Shift + C”.



Seção Public
Agora vamos definir alguns dos comportamentos do nosso componente codificando os seguintes métodos de visibilidade pública. Digite os métodos, “procedure CreateWnd”, “constructor Create” e “procedure Change” . Em seguida pressione “Ctrl + Shift + C”, simultaneamente. Veja, trecho de código a segui:


type
TZnCombo = class(TCustomComboBox)
private
FChangeFormFont: Boolean;
procedure SetChangeFormFont(const Value: Boolean);
{ Private declarations }
protected
{ Protected declarations }
public
constructor Create (AOwner: TComponent); override;
procedure CreateWnd; override;
procedure Change; override;
published
property Style default csDropDownList;
property Items stored False;
property ChangeFormFont: Boolean
read FChangeFormFont write SetChangeFormFont default True;
end;


Codificando o corpo dos métodos públicos:

A) procedure CreateWnd;

procedure TZnCombo.CreateWnd;
begin
inherited CreateWnd;
Items.Assign (Screen.Fonts);

// setando a fonte do Form Owner como default
if FChangeFormFont and Assigned (Owner) and (Owner is TForm) then
ItemIndex := Items.IndexOf ((Owner as TForm).Font.Name);
end;


B) constructor

constructor TZnCombo.Create(AOwner: TComponent);
begin
inherited Create (AOwner);
Style := csDropDownList;
FChangeFormFont := True;
ParentFont := False;
end;


C) procedure Change;

procedure TZnCombo.Change;
begin
// Atribuindo a fonte ao Form Owner
if FChangeFormFont and Assigned (Owner) and (Owner is TForm) then
TForm (Owner).Font.Name := Text;
inherited;

end;


Criando uma Package

Agora, para instalar o TZnCombo na IDE e podermos fazer uso dele em um projeto, devemos criar o que traduzimos por pacote (package). No menu: Component ►Install Component ...



Você pode escolher adicionar seu componente a uma package preexistente, ou criar uma package nova. Neste Exemplo, preferi criar uma nova, a qual chamei de “ZnConstruindoComponenetes.dpk”. Em “Unit File Name”, aponto para o arquivo “.pas” no qual estou trabalhando. Onde estamos codificando nosso componente. Veja detalhamento sobre essa funcionalidade (instalar componentes) no artigo sobre Flash e Delphi ....



Click em “Compile”, em seguida em “Install” (Não esqueça de adicionar a unit "Forms" na seção uses).




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.

1 – Adicione um TZnCombo, um TMemo e um TLabel (No menu Vew ► Component List, digite .. TZn ...)


Com o Component List évc pode acessar mais rápido o componente que deseja ..... adicionando o Label.



Set a propriedade “ParentFont” do Label1 para “False”, conforme figura abaixo. Assim evitaremos que a font dele seja alterada quando selecionarmos um tipo no combo que contruimos.



Adicione o Memo ...



Pronto!!! Pouco código? Isso é um bom sinal. Salve a aplicação. Execute seu programa (pressione F9), ou clike sobre o executável gerado (Alt + P + B – para construir o Executável).



Digite alguma coisa na área de texto ....



Altere o tipo da fonte selecionando uma dentre as listadas na combo.


Note que o Label1 não altera sua fonte, visto que setamos sua propriedade “ParentFont” para False. Caso contrário, ele alteraria a font simultaneamente com os demais componentes.



A idéia é que esse artigo seja uma introdução ao assunto. Seguiremos, aprofundando, no próximo artigo ....

segue o código completo da Unit "ZnCombo.pas":

unit ZnCombo;

interface

uses
SysUtils, Classes, Controls, StdCtrls;

type
TZnCombo = class(TCustomComboBox)
private
FChangeFormFont: Boolean;
procedure SetChangeFormFont(const Value: Boolean);
{ Private declarations }
protected
{ Protected declarations }
public
constructor Create (AOwner: TComponent); override;
procedure CreateWnd; override;
procedure Change; override;
published
property Style default csDropDownList;
property Items stored False;
property ChangeFormFont: Boolean
read FChangeFormFont write SetChangeFormFont
default True;
end;

procedure Register;

implementation

uses
Forms;

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

{ TZnCombo }

procedure TZnCombo.Change;
begin
// Atribuindo a fonte ao Form Owner
if FChangeFormFont and Assigned (Owner) and (Owner is TForm) then
TForm (Owner).Font.Name := Text;
inherited;

end;

constructor TZnCombo.Create(AOwner: TComponent);
begin
inherited Create (AOwner);
Style := csDropDownList;
FChangeFormFont := True;
ParentFont := False;
end;

procedure TZnCombo.CreateWnd;
begin
inherited CreateWnd;
Items.Assign (Screen.Fonts);

// setando a fonte do Form Owner como default
if FChangeFormFont and Assigned (Owner) and (Owner is TForm) then
ItemIndex := Items.IndexOf (
(Owner as TForm).Font.Name);
end;

procedure TZnCombo.SetChangeFormFont(const Value: Boolean);
begin
FChangeFormFont := Value;
// refresh - atualizando a nova fonte
if FChangeFormFont then
Change;
end;

end.


2 comentários:

  1. Muito bom o seu artigo, porém creio que devamos acrescentar Forms na uses para evitar erro ao compilar.

    Abraço.

    ResponderExcluir
  2. Opa Rodrigo!!!
    Obrigado por participar do Estação Zn.
    É muito importante, na maioria das vezes construtiva, a participação dos visitantes e leitores do blog. Realmente não mencionei a necessidade de declarar a unit “Forms” na seção “uses” da “ZnCombo.pas”. Eu pretendia colocar o fonte completo da unit como geralmente faço nos artigos. Infelizmente, nem sempre conseguimos uma boa equação entre os elementos “Tempo”, “Perfeição” e “Escopo”.
    Já atualizei o artigo, agora quem quiser construir o exemplo, suponho, poderá fazê-lo sem grandes traumas .... heheh
    Obrigado!
    Att,
    Gerson.

    ResponderExcluir

 
BlogBlogs.Com.Br