sábado, 25 de agosto de 2007

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.


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:
  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:


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”.

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):

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 ...


Artigo completo (View Full Post)

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.


Artigo completo (View Full Post)

quarta-feira, 4 de julho de 2007

Ué? É ADODataSet ou ClientDataSet?

Olá a todos novamente.

Primeiramente quero pedir dois milhões de desculpas por não ter postado nestas últimas semanas... Mudei de emprego, estou em novo projeto e agora as coisas estão voltando para os eixos.

Indo diretamente ao assunto (o bom de escrever na net é que a reclamação só vem em forma de comentário mais tarde hehe), vou mostrar duas coisas muito legais no componente TADODataSet.


Quem conhece o TClientDataSet sabe de suas inúmeras vantagens ao desenvolver aplicativos com acesso a bases de dados (inclusive 'desconectado'). Este componente é parte da tecnologia MIDAS (google, por favor!) que principalmente visa desenvolvimento em várias camadas, sendo o TClientDataSet usado na parte de apresentação (interface), o DataSetProvider no meio e qualquer descendente de TDataSet (TADODataSet, TSQLDataSet, TBDEDataSet, etc) na parte de acesso ao servidor de banco de dados.

Além desta forma há várias outras de se trabalhar com o TClientDataSet - Isso é assunto para um (ou até mais) post inteiro dedicado a isso - Um aspecto muito interessante do TClientDataSet é que ele trabalha com dados no cache local do aplicativo, guardando as alterações feitas nos dados em um pacote transacional e aplicando tudo de uma vez no servidor quando ordenado. Outra forma é trabalhar totalmente desconectado, usando dados em memória ou de um arquivo XML. Isso é muito útil quando nós precisamos guardar parâmetros do aplicativo ou 'tabelas auxiliares' que não ficam no banco de dados.

MIDAS é uma tecnologia da Borland e se você usá-la para desenvolver deve enviar a biblioteca midas.dll junto com seu aplicativo - Quem usa Delphi 7 tem opção de compilar a MIDAS junto com o aplicativo: só adicionar a unit MidasLib na seção uses de qualquer unit do projeto.

Quem não quer (ou não pode) usar MIDAS não precisa se desesperar! O componente TADODataSet possui quase todas (senão todas) essas funcionalidades também. Com ele você pode:

- Trabalhar conectado com banco de dados;
- Enviar cada ação realizada ao banco de dados; ou
- Trabalhar no cache local e enviar um pacote transacional completo;
- Trabalhar com o DataSet em memória;
- Ler e gravar diretamente de um arquivo XML

Oba! XML! Legal! Vou fazer isso, e aquilo e zás, e zás.... Caaaaalma.....
Embora a parada do XML seja muito boa vou logo alertando: O Formato é o padrão do formato de XML ADO (não é ADO.NET) da Microsoft. Eu nunca testei, mas em teoria dá para interagir com um Recordset de uma aplicação VB ou ASP, porque é o mesmo objeto COM. Vou fazer este teste depois e mandar o resultado aqui.

Ah! Que droga! É verdade... mas o TClientDataSet é assim também. Ele usa um formato de XML padrão da Borland. Nada impede de você codificar por quilometragem e montar um super-hiper-mega-ultra programa que é o XML-o-matic que faz tudo... Eu e o Gerson estamos estudando uma forma de fazer tal coisa, mas isso é assunto para outro post (e outra viagem!).

Bem, para aqueles que tiveram paciência de ler até aqui, chegou a parte que todos estavam esperando: Vamos ver (mais ou menos) na prática.

Na Palheta ADO você encontra o ADODataSet. Ao analisar as propriedades dele repare na LockType. Os valores mais usados são ltOptimistic e ltBatchOptimistic.

O ltOptimistic é o modo de travamento de registro padrão que os outros DataSets operam e o ltBatchOptimistic também, mas com uma diferença entre eles: o ltBatchOptimistic trabalha com atualizações em cache local, enquanto o ltOptimistic leva cada alteração para o servidor de BD.

Então, para trabalhar com ele conectado no BD e a interface conectada diretamente nele, uma boa opção é usar o LockType como ltBatchOptimistic. Aí, os métodos Post e Delete não vão gravar direto no BD. Os dados vão efetivamente para o banco quando você (o DataSet) chamar o método UpdateBatch. Legal, né? Já dá pra fazer aquele mestre-detalhes complexo com um pacote transacional.

Se você trabalhar no esquema multicamadas (n-tier), onde vai usar ADODataSet na parte servidora, DataSetProvider para transmitir os dados de lá pra cá e daqui pra lá, e o ClientDataSet na parte da interface, uma boa pedida e deixar o ADODataSet como unidirecional. Com ele unidirecional aloca menos memória da aplicação servidora e faz o acesso mais rápido aos dados, já que ele só sabe mover o cursor para frente. Para fazer isso defina a propriedade CursorType como ctOpenForwardOnly. Ele trabalha como o SQLDataSet do DBExpress.

Caso você queira trabalhar com ele em memória ou com arquivo XML (ou seja, sem tomar conhecimento de servidor de banco de dados), você também pode. É Só abrir o Fields Editor (duplo-clique no componente) e ir adicionando campos da mesma forma que você cria campos calculados ou lookups, mas estes são do tipo fkData, ao invés de fkCalculated ou fkLookup. Aí, para poder ter acesso a estes dados em memória (e conectar a DBGrid, DBEdit, etc, etc e até fazer lookup é só chamar o método CreateDataSet do ADODataSet antes de trabalhar com ele.

Quando o ADODataSet está ativo (Active como True), é possível salvar o pacote de dados em formato XML ou ADTG, um formato binário proprietário da MS. Basta chamar o método SaveToFile do ADODataSet, especificando qual é o arquivo e qual o formato (pfADTG ou pfXML).

Quando você define a propriedade CommandType para ctFile você pode definir na propriedade CommandText o caminho para um arquivo XML ou ADTG com os dados (ou só a estrutura também) que ele passa a trabalhar diretamente neste arquivo. Aí, para gravar alterações é só chamar o método SaveToFile passando '' para o nome do arquivo (aí ele usa o CommandText) e o formato que está usando.

Acabou sendo um pouco mais longo do que eu pensava mas, mais uma vez, me desculpe pela grande falta nestas semanas e obrigado pela força de sempre. Como usual, a seção de comentários está à vontade. Não deixe de comentar, deixar sugestões, dicas e qualquer coisa que quiser...

Grande abraço e até a próxima.

Artigo completo (View Full Post)

terça-feira, 19 de junho de 2007

Modelo Cliente - Servidor


“... foi simplesmente espetacular o progresso que os computadores conheceram em um curto período de tempo. Nas duas primeiras décadas de sua existência, os sistemas computacionais eram acondicionados, geralmente, em uma grande sala com paredes de vidro(...). Uma empresa de médio porte ou uma universidade contava apenas com um ou dois computadores... ” (Tanenbaun S. Andrew, Redes de computadores)

Num primeiro momento, desenvolver aplicativos de bancos de dados para PC era uma abordagem de um único processo. Tanto o programa quanto os arquivos de “banco de dados” ficavam no mesmo computador e todo o esforço do desenvolvimento era concentrado na aplicação, ou seja, todo o tratamento, desde a entrada até a gravação física do registro, era implementado no aplicativo, como por exemplo: construção da interface gráfica (telas), as validações (checkes) e os algoritmos de classificação, busca, gravação, leitura e indexação.
Com o surgimento das redes, programadores audazes moveram os arquivos de dados para um servidor de arquivos, visando desta forma viabilizar o acesso de múltiplos usuários a mesma base de dados. Agora vários computadores poderiam compartilhar das informações contidas no banco de dados. Contudo, esses computadores teriam que possuir o software aplicativo (que continha todo o mecanismo de manipulação de dados descrito acima) instalado, porém os arquivos de bancos de dados agora estavam disponíveis para múltiplos usuários acessa-los simultaneamente. Até hoje se usa este modelo, e alguns sistemas que trabalham com banco de dados locais (Paradox, access, Dbase e ect..) são configurados desta forma, o modelo de servidores de arquivos.
Esta estratégia, amplamente difundida no passado, embora tenha trazido alguma inovação, muito mais no aspecto físico do que lógico, não se consolodou como um modelo definitivo, a partir do momento que trouxe mais demandas do que soluções. Como assim? Imagine a seguinte situação:


um jantar, ou ceia comunitária onde os convidados deveriam, cada um, trazer parte da comida e bebida, deposita-la numa única mesa e, ao mesmo tempo, outros convidados estariam se servindo de alimentos que já estariam na mesa. Podemos imaginar, a partir deste exemplo, as dificuldades que os participantes desta ceia deveriam estar enfrentando. Cada vez maior seria o problema quanto mais pessoas chegassem para participar da ceia, em pouco tempo o caos estaria estabelecido. È óbvio que sem uma forma de gerenciamento esta configuração fatalmente será insustentável. Os sistemas gerenciadores de banco de dados surgem com afinalidade de atender justamente esta necesidade.
No armazenamanto de dados flle-server, toda a inteligência do “banco” reside no software cliente. Embora que o arquivo de dados resida no servidor remoto, este servidor não tem inteligência para gerenciar esses dados.
No modelo cliente-servidor o banco de dados não é apenas um arquivo, ou melhor, não é uma pasta contendo vários arquivos(que seriam as tabelas e os índices). Mas sim um programa, um sistema que controla e gerencia o banco, onde reside toda a inteligência do banco de dados. Este programa prove um serviço de acesso, armazenamento e manipulação de dados. Podemos concluir então que: se existe processamento no banco agora, eu posso pegar os processos que antes estavam todos codificados no sotware cliente, e dividi-los com o programa de banco de dados.
O modelo client-server reduz significantemente o tráfego de rede, também provê uma melhor integridade no banco e o torna mais poderoso, já que todo o gerenciamento do software fica em único lugar.
Continua em ... Back-End

Artigo completo (View Full Post)

domingo, 17 de junho de 2007

Surface Computer



A galerinha do tio Bill acena pro mercado com uma surpresinha interessante. Na minha opinião já passou da hora de surgir alguma alternativa melhor, mais funcional e de melhor usabilidade, ao formato convencional dos dispositivos de interface do PC. Enquanto os projetos baseados em holografia ainda pertencem ao mundo da ficção, o Surface computer aparece com pose de elemento futurista e nos traz a expectativa de novas experiências de interatividade baseada no touch screen. Abusando do conceito de usabilidade intuitiva, tudo que se tem experimentado no que tange interação entre pessoas e sistemas, pessoas e pessoas, está totalmente comprometido, a um passo da se tornarem obsoletos. A interoperabilidade entre dispositivos também é afetada, por exemplo, através de wireless aparelhos como o Zune e Smartphones já são capazes de dar uma idéia do potencial dessa nova tecnologia. Vale gastar um tempinho em hotsite do Surface.




É uma idéia bastante promissora, que abre uma infinidade de possibilidades de interação. Indubitavelmente o universo multimídia não será o mesmo. Ganes, vídeos, áudio, na música, na arquitetura, projetos gráficos, ferramentas para diversos fins poderão ter um ganho em usabilidade tremendo a partir dessa tecnologia. Mas é claro que se tratando de MS, devido ao histórico da organização, sempre teremos o pé atrás quando a eficácia e qualidade do produto.
Supondo que ele alcance um desempenho satisfatório quando ao que se propõe, não esquecendo de mencionar a acessibilidade viável (ou seja, custo acessível), não tenho dúvida de que estaremos mais uma vez, através da informática, experimentando uma contundente intervenção da tecnologia na cultura, em todas as áreas.
Existem outros projetos que também nos aproximam dessa superfície de contato com o futuro, superfície de interação com o futuro:
O DiamondTouch da Mitsubishi, é uma boa notícia pra quem teme o monopólio da M$ nesse setor. A mesa da Mitsubishi não apenas é sensível ao toque mas lém disso também obedece comandos de voz. Que tal experimentar um partidinha de Warcraft III D?



Confira mais esse ....



Veja em:
Touch Screens for Many Fingers
Ministry of Tech
Especicamente:
Perceptive Pixel
Interactive Touchless Display




Confesso que a paradinha me emocionou!!! Para nós desenvolveddores, isso é mto bom! Isso representa mais trabalho. Novas forteiras, envolvendo uma abordagem nova o que provavelmente damandará soluções não convencionais, o que é bastante motivador e excitante.
Vamos agurdar cenas dos próximos capítulos .....


Esse assunto esta bombando na web, vários vídeos no youtube, artigos em blogs ...etc...
Veja mais




Artigo completo (View Full Post)

segunda-feira, 4 de junho de 2007

SQL

Structured Query language SQL

É uma linguagem de pesquisa declarativa e de programação para banco de dados relacional. O SQL foi desenvolvido no início da década de 70 nos laboratórios da IBM, no projeto System R, que tinha por objetivo demonstrar a viabilidade da implementação do modelo relacional proposto por E. F. Codd. O nome original da linguagem era SEQUEL, acrônimo para "Structured English Query Language".A linguagem SQL foi desenvolvida pela IBM, visando realizar operações em SGBDs. Ela é subdividida em quatro categorias:

  • Linguagem de definição de dados(DDL):
  • Linguagem de manipulação de dados(DML)
  • Linguagem de controle de dados (DCL)
  • Linguagem de controle de Transação(TCL)


DDL Data Defition Language:

  • CREATE – Para crier objetos de banco de dados.
  • ALTER – Alterar estrutura de objetos no banco de dados.
  • DROP – Excluir objetos no Banco de dados.
  • TRUNCATE –Exclui todos os registros de uma tabela.
  • RENAME – Renomeia objetos de banco de dados

Exemplos:

a) CREATE:
   Create table <Nome_da_tabela> (<Nome_do_campo>  <tipo> <tamanho> <requerido>); 
b) ALTER:
    Alter table <Nome_da_tabela> add <Nome_do_campo>  <tipo> <tamanho> <requerido>;  

c) DROP
Excluindo uma coluna
   Alter table <Nome_da_tabela> drop <Nome_do_campo>
;

Excluido uma tabela
   Drop table <Nome_da_tabela> 


DML Data Manipulation Language:

• SELECT – Seleciona dados.
• INSERT – Insere dados numa tabela
• UPDATE – Altera registros de uma tabela.
• DELETE – Apaga registros de uma tabela.

Exemplo:

d) Select:

Select From Where

e) Insert:

Insert Into Values

f) UpDate:
UpDate  Set =  ;

g) Delete:
Delete from  Where   ;



DCL Data Controul Language:
o GRANT – Concede privilégios a usuários sobre objetos do banco (gives user's access privileges to database)
o REVOKE – Retira privilégios de usuários (withdraw access privileges given with the GRANT command)
Exemplo:
h) Grant:

Grant on to

i) Revoke:
Revoke  on   from   


TCL

Transaction Control Language (TCL) Comandos que gerenciam manipulações através de DML sobre os registros de uma banco de dados. Esse gerenciamento e feito através de controle de transações. (statements are used to manage the changes made by DML statements. It allows statements to be grouped together into logical transactions).
o COMMIT – Confirma operação realizada. Aplica definitivamente, fisicamente a operação realizada.
o SAVEPOINT – Marca pontos onde a transação pode ser efetivada ou não.
o ROLLBACK – Cancela uma operação iniciada pelo START TRANSACTION.
o START TRANSACTION/ BEGIN TRANS – Incia uma transação.
o SET TRANSACTION – Configura uma transação, como nível de isolamento e seguimentos de Rollback.



Um Script de exemplo - Inerbase/ Fire Bird


CREATE DATABASE 'G:\\BancoCurso.gdb'
USER 'SYSDBA' PASSWORD 'masterkey'
PAGE_SIZE 4096;


/******************************************************************************/
/* DOMAIN */
/******************************************************************************/


CREATE DOMAIN MOEDA AS NUMERIC(15,2) DEFAULT 0;
CREATE DOMAIN BOOLEAN AS CHAR(1) DEFAULT 'F' CHECK(VALUE IN ('F','T'));


/******************************************************************************/
/* Tables */
/******************************************************************************/

CREATE TABLE CLIENTES (
ID_CLIENTE INTEGER NOT NULL,
NOME VARCHAR(60) NOT NULL,
CPF CHAR(11) NOT NULL,
ENDERECO VARCHAR(60) NOT NULL,
BAIRRO VARCHAR(40) NOT NULL,
CIDADE VARCHAR(40) NOT NULL,
ESTADO CHAR(2) NOT NULL,
DATACAD TIMESTAMP NOT NULL,
STATUS BOOLEAN
);



CREATE TABLE ITENS (
ID_PEDIDO INTEGER NOT NULL,
ID_PRODUTO INTEGER NOT NULL,
QUANTIDADE INTEGER NOT NULL,
PRECOVENDA MOEDA NOT NULL
);

CREATE TABLE PEDIDOS (
ID_PEDIDO INTEGER NOT NULL,
ID_CLIENTE INTEGER NOT NULL,
DATAPED TIMESTAMP NOT NULL
);

CREATE TABLE PRODUTOS (
ID_PRODUTO INTEGER NOT NULL,
DESCRICAO VARCHAR(60) NOT NULL,
PRECOCOMPRA MOEDA NOT NULL,
QUANTIDADE INTEGER NOT NULL
);


/******************************************************************************/
/* Primary Keys */
/******************************************************************************/

ALTER TABLE CLIENTES ADD PRIMARY KEY (ID_CLIENTE);
ALTER TABLE PEDIDOS ADD PRIMARY KEY (ID_PEDIDO);
ALTER TABLE PRODUTOS ADD PRIMARY KEY (ID_PRODUTO);
ALTER TABLE ITENS ADD PRIMARY KEY(ID_PEDIDO, ID_PRODUTO);


/******************************************************************************/
/* Foreign Keys */
/******************************************************************************/


ALTER TABLE ITENS ADD FOREIGN KEY (ID_PRODUTO) REFERENCES PRODUTOS (ID_PRODUTO);
ALTER TABLE ITENS ADD FOREIGN KEY (ID_PEDIDO) REFERENCES PEDIDOS (ID_PEDIDO);
ALTER TABLE PEDIDOS ADD FOREIGN KEY (ID_CLIENTE) REFERENCES CLIENTES (ID_CLIENTE);



/******************************************************************************/
/* ÍNDICES */
/******************************************************************************/

CREATE INDEX IDX_NOMECLI ON CLIENTES(NOME);
CREATE UNIQUE INDEX IDX_CPF_CLI ON CLIENTES(CPF);
CREATE INDEX IDX_DATAPED ON PEDIDOS(DATAPED);
CREATE UNIQUE INDEX IDX_DESCRICAO_PROD ON PRODUTOS(DESCRICAO);

/******************************************************************************/
/* VISÕES */
/******************************************************************************/


SET TERM ^ ;
CREATE VIEW TOTAL_VENDIDO_PRODUTO(Produto, QTDE_vendida,Valor_vendido) AS
SELECT
produtos.descricao, sum(itens.quantidade) ,SUM(itens.quantidade* itens.PRECOVENDA)
FROM
produtos, itens , pedidos
WHERE
produtos.id_produto = ITENS.id_produto AND
itens.id_pedido = pedidos.id_pedido

group BY
produtos.descricao


^

/******************************************************************************/
/* Generators */
/******************************************************************************/

CREATE GENERATOR GEN_ID_CLIENTE;

CREATE GENERATOR GEN_ID_PRODUTO;

/******************************************************************************/
/* Stored Procedures */
/******************************************************************************/

SET TERM ^ ;

CREATE PROCEDURE CALCULATOTALPEDIDO (
PNUMPEDIDO INTEGER)RETURNS (VSOMA NUMERIC(15,2))
AS
BEGIN
SELECT SUM(QUANTIDADE * PRECOVENDA) FROM ITENS WHERE ID_PEDIDO = :PNUMPEDIDO INTO :VSOMA;
suspend;
END
^


/******************************************************************************/
/* Triggers */
/******************************************************************************/

SET TERM ^ ;

/* Trigger: TRG_INCREMENTA_CLIENTE */
CREATE TRIGGER TRG_INCREMENTA_CLIENTE FOR CLIENTES
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
NEW.ID_CLIENTE = GEN_ID(GEN_ID_CLIENTE, 1);
END;
^


/* Trigger: TRG_INCREMENTA_PRODUTO */
CREATE TRIGGER TRG_INCREMENTA_PRODUTO FOR PRODUTOS
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
NEW.ID_PRODUTO = GEN_ID(GEN_ID_PRODUTO, 1);
END
^


Artigo completo (View Full Post)

 
BlogBlogs.Com.Br