quarta-feira, 27 de fevereiro de 2008

MethodAddress

Método definido em TObject, retorna o endereço de um método published. Ou seja, um método definido na seção “published”. Entretanto, evocar o “MethodAddress” não é algo tão trivial. É preciso criar uma variável do tipo “procedure” que receberá o ponteiro para o método retornado por “MethodAddress”.
Exemplo 1:


unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons;

type
TForm1 = class(TForm)
BitBtn1: TBitBtn;
procedure BitBtn1Click(Sender: TObject);
private

public

published
procedure MyZnMethod;
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.BitBtn1Click(Sender: TObject);
var
AuxProcedure: Procedure(Sender: TObject);
begin
AuxProcedure := Self.MethodAddress('MyZnMethod');
AuxProcedure(Self);
end;

procedure TForm1.MyZnMethod;
begin
Self.Caption := 'Estação ZN';
Self.Color := clAqua;
Self.Update;
Self.Canvas.TextOut(12, 130, 'Dummy MethodAddress Teste Estação ZN!!!');
end;

end.



Ok, muito simples! Só que se eu desejar evocar um método que está definido em outra classe terei de usar uma estratégia, pois o método MethodAddress, só conhece os métodos definidos na própria classe. Para exemplificar, vamos criar uma classe ‘TMyZnClassDummy’ e no mesmo evento OnClick do BitBtn1 evocar o método “Dummy” da nova classe, “TMyZnClassDummy”. Exemplo2:


unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons;

type
TForm1 = class(TForm)
BitBtn1: TBitBtn;
procedure BitBtn1Click(Sender: TObject);
private

public

ppublished
procedure MyZnMethod;
end;

type
TMyZnClassDummy = Class(TComponent)
private

protected
published
procedure Dummy;
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.BitBtn1Click(Sender: TObject);
var
AuxProcedure: Procedure(Sender: TObject);
AuxProcedureBlah: Procedure(Sender: TObject);
begin
AuxProcedure := Self.MethodAddress('MyZnMethod');
AuxProcedure(Self);

(*Testando o Blah*)
ShowMessage('Testando o Blah!!');
AuxProcedureBlah := MethodAddress('Dummy');
AuxProcedureBlah(Self)
end;

procedure TForm1.MyZnMethod;
begin
Self.Caption := 'Estação ZN';
Self.Color := clAqua;
Self.Update;
Self.Canvas.TextOut(12, 130, 'Dummy MethodAddress Teste Estação ZN!!!');
end;

{ TMyZnClassDummy }

procedure TMyZnClassDummy.Dummy;
begin
ShowMessage(Self.Name + ' Blah!!!!');
end;

end.


Como eu posso fazer para conseguir executar o método “Dummy”? Eu preciso (primeiro, se for o caso fazer uses da unit onde a classe, cujo o método desejo evocar, se encontra) criar na classe que vai chamar através do “MethodAddress” um outro método pblished, este por sua vez chamara o método definido na outra classe. Vou Criar no Form1 um método que evocará o método “Dummy” da classe “TMyZnClassDummy”.Exemplo:

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons;

type
TForm1 = class(TForm)
BitBtn1: TBitBtn;
procedure BitBtn1Click(Sender: TObject);
private

public

published
procedure MyZnMethod;
procedure ExeucteDummy;
end;

type
TMyZnClassDummy = Class(TComponent)
private

protected
published
procedure Dummy;
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.BitBtn1Click(Sender: TObject);
var
AuxProcedure: Procedure(Sender: TObject);
AuxProcedureBlah: Procedure(Sender: TObject);
begin
AuxProcedure := Self.MethodAddress('MyZnMethod');
AuxProcedure(Self);

(*Testando o Blah*)
ShowMessage('Testando o Blah!!');
(* Executo o Método procedure do Form1 "ExeucteDummy" *)
AuxProcedureBlah := MethodAddress('ExeucteDummy');
AuxProcedureBlah(Self)
end;

procedure TForm1.ExeucteDummy;
var
MyZnClassDummy: TMyZnClassDummy;
begin
MyZnClassDummy := TMyZnClassDummy.Create(Self);
try
MyZnClassDummy.Dummy;
finally
MyZnClassDummy.Free;
end;

end;

procedure TForm1.MyZnMethod;
begin
Self.Caption := 'Estação ZN';
Self.Color := clAqua;
Self.Update;
Self.Canvas.TextOut(12, 130, 'Dummy MethodAddress Teste Estação ZN!!!');
end;

{ TMyZnClassDummy }

procedure TMyZnClassDummy.Dummy;
begin
ShowMessage(Self.ClassName + ' Blah!!!!');
end;

end.

Baseado nisso, podemos criar um catálogo de métodos de classes distintas, os quais poderão ser exibidos numa interface, permitindo ao usuário uma forma de setup da aplicação. De maneira que ele possa definir que funcionalidade será executada a partir de uma determinada ação na interface. Sei que esse tipo de abordagem não é nada convencional, contudo acredito ela permita um flexibilização poderosa para algumas situações.


"A mente que se abre a uma nova idéia jamais voltará ao seu tamanho original". Albert Estein

Artigo completo (View Full Post)

terça-feira, 26 de fevereiro de 2008

Construção de Componentes - VI

Seguindo a mesma linha do último exemplo de criação de componentes, para consolidar os pontos discutidos, construiremos outro exemplo bem semelhante ao anterior mudando um pouco a abordagem quanto a funcionalidade do componente.
O principal objetivo deste será oferecer um solução abstrata para uma funcionalidade tipo “Localizar” (tipo um “find”) para um conjunto de registros listados num DBGrid. Basta clickar com o botão direito do mouse na coluna a qual se deseja fazer a busca, o componente dinamicamente cria um menu popup, com um item cujo a descrição seja “Focalizar [título da coluna]”. Efetuado o click sobe o item de menu, o sistema exibe uma janela de diálogo solicitando digitação do valor para busca e em seguida efetua a busca. Localizando no Grid o dado desejado.


Descrição da funcionalidade:

  1. Usuário clicka com o botão direito do mouse sobre a coluna do Grid, a qual deseja localizar um registro.
  2. Sistema exibe o popup menu com um item de localizar.
  3. Usuário clicka na opção de localizar.
  4. Sistema Exibe tela de diálogo para usuário digitar o valor a ser localizado.
  5. Usuário digita o valor e clicka em “Ok”, confirmando a solicitação de localizar.
  6. Sistema localiza, focando a célula onde se encontra o registro desejado.
Construindo o Componente

Se você não sabe iniciar, no Delphi, a construção de um componente siga as instruções dos artigos anteriores.

Codifique conforme código abaixo a classe TFinderDataZN.


unit FinderDataZN;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, DbGrids, ADODb, Db, Menus;

type
(* Para indicar a Classe se o Popup Menu foi outo-criado, ou já estava associado
ao DbGrid que "foi" associado ao TFinderDataZN *)
TPopupExistent = (peExternalAssociation, peInternalCreated, peInexistent);

TFinderDataZN = class(TComponent)
private
{ Private declarations }
protected
{ Protected declarations }
public
{ Public declarations }
published
Property ReturnValueStr: String read FReturnValueStr;
Property ReturnValueNum: Double read FReturnValueNum;
property Grid: TDBGrid read FGrid write SetGrid;
end;

procedure Register;

implementation

procedure Register;
begin
RegisterComponents('EstacaoZN', [TFinderDataZN]);
end;

end.


Codificando a principal propriedade “SetGrid”. Isto porque, essa propriedade vai preparar o Grid e configurar a classe para seu principal fim. Observe que no método “BuildMenuPopup” vou atribuir um evento ao OnClick do item de menu dinamicamente, da mesma forma que fizemos no artigo anterior, contudo neste momento vou deixar essa atribuição comentada. Pois, pretendo implementar a procedure “LocalizarClick” mais adiante. Preste a atenção na linha “/MyMenuitem.OnClick := LocalizarClick”, do método “BuildMenuPopup”, ela estará comentada. O mesmo serve para o método “SetPopupMenu”, visto que o evento PopupMenuPopup, o qual atribuirei ao evento “OnPopup” do Popup Menu associado ao Grid.


unit FinderDataZN;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, DbGrids, ADODb, Db, Menus;

type
(* Para indicar a Classe se o Popup Menu foi outo-criado, ou já estava associado
ao DbGrid que "foi" associado ao TFinderDataZN *)
TPopupExistent = (peExternalAssociation, peInternalCreated, peInexistent);

TFinderDataZN = class(TComponent)
private
FReturnValueNum: Double;
FReturnValueStr: String;
FGrid: TDBGrid;
FADataSet: TCustomADODataSet;
FPopupMenu: TPopupMenu;
FIsPopupExistent: TPopupExistent;
FSelectedColumn: TColumn;
FAFieldSearch: TField; // Será usado para setar foco

procedure SetGrid(const Value: TDBGrid);
procedure SetADataSet(const Value: TCustomADODataSet);
procedure SetPopupMenu(const Value: TPopupMenu;
const nAllowCreate: Boolean = False);

protected
procedure CreatePopupMenuItem(const NameItem,
CaptionItem: String); virtual;
procedure BuildMenuPopup; virtual;
procedure SetSelectedColumn(const Value: TColumn); virtual;
function GetSelectedColunm: TColumn; virtual;
public
{ Public declarations }
published
Property ReturnValueStr: String read FReturnValueStr;
Property ReturnValueNum: Double read FReturnValueNum;
property Grid: TDBGrid read FGrid write SetGrid;
end;

procedure Register;

implementation

const
PopupMenuItemName: array [0..1] of String = ('ConfigurarGridSep',
'fdLocalizar');
AMenuItemCaption = 'Localizar %s';

procedure Register;
begin
RegisterComponents('EstacaoZN', [TFinderDataZN]);
end;

{ TFinderDataZN }

procedure TFinderDataZN.BuildMenuPopup;
var
i: Integer;
MyMenuitem: TMenuItem;
begin

(* Verifco se o componente encontra-se em run time*)
if not (csDesigning in Self.ComponentState) then
begin
if Assigned(FPopupMenu) then
begin
for i := 0 to High(PopupMenuItemName) do
begin
if (FPopupMenu.Items.Count > 0) and (i = 0) then
CreatePopupMenuItem(PopupMenuItemName[i], '-');

if (i = 1) then
CreatePopupMenuItem(PopupMenuItemName[i],
Format(AMenuItemCaption, [FGrid.Columns[0].Title.Caption]));
end;

MyMenuitem := TMenuItem(Self.FindComponent(PopupMenuItemName[1]));
if assigned(MyMenuitem) then
//MyMenuitem.OnClick := LocalizarClick;

end;
end;
end;

procedure TFinderDataZN.CreatePopupMenuItem(const NameItem,
CaptionItem: String);
var
MyMenuitem: TMenuItem;
begin
MyMenuitem := TMenuItem(Self.FindComponent(NameItem));
if not assigned(MyMenuitem) then
begin
MyMenuitem := TMenuItem.Create(Self);
with MyMenuitem do
begin
Name := NameItem;
Caption := CaptionItem;
end;
FPopupMenu.Items.Add(MyMenuitem);
end;
end;

function TFinderDataZN.GetSelectedColunm: TColumn;
var
i: Integer;
AuxField: TField;
begin
Result := nil;
for i := 0 to Pred(FGrid.Columns.Count) do
begin
AuxField := FGrid.Columns[i].Field;
if Assigned(AuxField) then
if AuxField.FieldName = FGrid.SelectedField.FieldName then
Result := FGrid.Columns[i];
if Assigned(Result) then Break;
end;

end;

procedure TFinderDataZN.SetADataSet(const Value: TCustomADODataSet);
begin
FADataSet := Value;
end;

procedure TFinderDataZN.SetGrid(const Value: TDBGrid);
begin
if FGrid <> Value then
begin
FGrid := Value;

if FGrid <> nil then
begin
FGrid.FreeNotification(Self);
SetSelectedColumn(GetSelectedColunm);
FADataSet := TCustomADODataSet(FGrid.DataSource.DataSet);
(* Cuida da associação, menu popup, associada ao DBGrid *)
SetPopupMenu(FGrid.PopupMenu);
(* Monta os itens de menu, os quais nos referimos
na especificação do componente *)
BuildMenuPopup;

end;
end;
end;

procedure TFinderDataZN.SetPopupMenu(const Value: TPopupMenu;
const nAllowCreate: Boolean);
begin
if (FPopupMenu = Value) and (Value <> nil) then Exit;

If not Assigned(Value) or (nAllowCreate) then
begin
FPopupMenu := TPopupMenu.Create(Self);
FGrid.PopupMenu := FPopupMenu;
FIsPopupExistent := peInternalCreated;
end
else
begin
FPopupMenu := Value;
FIsPopupExistent := peExternalAssociation;
end;

if FPopupMenu <> nil then
begin
FPopupMenu.FreeNotification(Self);
//FPopupMenu.OnPopup := PopupMenuPopup;
end;
end;

procedure TFinderDataZN.SetSelectedColumn(const Value: TColumn);
begin
(* Armazena a coluna do Grid aqual foi clickada com o
botão direito do mouse, para capturar informações como: Titúlo e etc.. *)
FSelectedColumn := Value;

if FSelectedColumn <> nil then
FAFieldSearch := FSelectedColumn.Field;
end;

end.




Codificando as procedures que serão atribuídas aos eventos :
“procedure LocalizarClick(Sender: TObject)” para efetuará a localização do registro desejado.

“procedure PopupMenuPopup(Sender: TObject) ”, para criar o caption, o título do item de menu, referente ao registro o qual será localizado.

protected
procedure CreatePopupMenuItem(const NameItem,
CaptionItem: String); virtual;
procedure BuildMenuPopup; virtual;
procedure SetSelectedColumn(const Value: TColumn); virtual;
function GetSelectedColunm: TColumn; virtual;
(* Eventos que serão atribuidos dinamicamente *)
procedure LocalizarClick(Sender: TObject); virtual;
procedure PopupMenuPopup(Sender: TObject);


Primeiro a implementação da nova procedure que vai setar o título o item de menu dinamicamente de acordo com o título da coluna do Grid:



procedure TFinderDataZN.PopupMenuPopup(Sender: TObject);
var
MyMenuitem: TMenuItem;
begin
MyMenuitem := TMenuItem(Self.FindComponent(PopupMenuItemName[1]));
if assigned(MyMenuitem) then
begin
SetSelectedColumn(GetSelectedColunm);
MyMenuitem.Caption := Format(AMenuItemCaption, [FSelectedColumn.Title.Caption]);
end;
end;


A funcionalidade de Localizar precisa exibir uma janela (tela) para que o usuário digite o valor desejado. Logo, precisamos, antes de codificar criarmos um novo form. Adicione a classe um novo Form, propriedade name = “FindDataDlgFormZN”, salve a unit com o nome de “FindDataDlgFrmZN”. Segue o código do dfm do form:

object FindDataDlgFormZN: TFindDataDlgFormZN
Left = 192
Top = 107
Width = 189
Height = 138
Caption = 'Localizar %s'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object Label1: TLabel
Left = 12
Top = 12
Width = 126
Height = 13
Caption = 'Digite o Código do Serviço'
end
object EdtDado: TEdit
Left = 12
Top = 33
Width = 159
Height = 21
TabOrder = 0
end
object PnlBottom: TPanel
Left = 0
Top = 67
Width = 181
Height = 44
Align = alBottom
BevelOuter = bvNone
TabOrder = 1
object BtnCancel: TBitBtn
Left = 100
Top = 12
Width = 75
Height = 25
TabOrder = 0
Kind = bkCancel
end
object BtnOk: TBitBtn
Left = 12
Top = 12
Width = 75
Height = 25
TabOrder = 1
Kind = bkOK
end
end
end

No form codifique o evento OnCloseQuery e um método público “Execute” conforme exemplificado abaixo:

unit FindDataDlgFrmZN;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons, ExtCtrls;

type
TFindDataDlgFormZN = class(TForm)
Label1: TLabel;
EdtDado: TEdit;
PnlBottom: TPanel;
BtnCancel: TBitBtn;
BtnOk: TBitBtn;
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
private
{ Private declarations }
public
function Execute: Boolean;
end;

var
FindDataDlgFormZN: TFindDataDlgFormZN;

implementation

{$R *.dfm}

procedure TFindDataDlgFormZN.FormCloseQuery(Sender: TObject;
var CanClose: Boolean);
begin
if (Self.ModalResult = MrOk) and (Trim(EdtDado.Text) = '') then
ModalResult := mrCancel;
end;

function TFindDataDlgFormZN.Execute: Boolean;
begin
Self.BorderStyle := bsDialog;
Self.FormStyle := fsNormal;
Self.Position := poMainFormCenter;

Result := (Self.ShowModal = mrOk);

end;

end.


Implementado o procedimento que vai gerenciar a localização do registro “function InputSearchValue”.

protected
procedure CreatePopupMenuItem(const NameItem,
CaptionItem: String); virtual;
procedure BuildMenuPopup; virtual;
procedure SetSelectedColumn(const Value: TColumn); virtual;
function GetSelectedColunm: TColumn; virtual;
(* Eventos que serão atribuidos dinamicamente *)
procedure LocalizarClick(Sender: TObject); virtual;
procedure PopupMenuPopup(Sender: TObject);
(*método que vai gerenciar a localização do registro *)
function InputSearchValue: String; virtual;
public
{ Public declarations }
published
Property ReturnValueStr: String read FReturnValueStr;
Property ReturnValueNum: Double read FReturnValueNum;
property Grid: TDBGrid read FGrid write SetGrid;
end;


Adicione na clausula “uses” da seção “implamentation” a unit da classe “TFinderDataZN”, a unit do form que acabamos de criar. Na seção “private” defina um novo campo FAFieldSearch: TField;

procedure Register;

implementation

uses FindDataDlgFrmZN;

const
PopupMenuItemName: array [0..1] of String = ('ConfigurarGridSep',
'fdLocalizar');
AMenuItemCaption = 'Localizar %s';



var
FindDataDlgForm: TFindDataDlgForm;
AuxCaption: String;
begin

if (FADataSet.IsEmpty) then Exit;


try
FindDataDlgForm := TFindDataDlgForm.Create(Self);

FindDataDlgForm.Caption := Format(FindDataDlgForm.Caption,
[FSelectedColumn.Title.Caption]);

FindDataDlgForm.Label1.Caption := FSelectedColumn.Title.Caption;

if FindDataDlgForm.Execute then
begin
Result := FindDataDlgForm.EdtDado.Text;
if FADataSet.Locate(FSelectedColumn.Field.FieldName, FindDataDlgForm.EdtDado.Text, []) then
begin
FAFieldSearch.FocusControl;
if FGrid.CanFocus then
FGrid.SetFocus
end;
end;

finally
FindDataDlgForm.Free;
end;


Agora, para finalizar , o método “LocalizarClick”.


procedure TFinderDataZN.LocalizarClick(Sender: TObject);
var
AValue: String;
AValueNum: Double;
begin

try
AValue := InputSearchValue;
except
on Exception do
AValue := '';
end;

end;


Não esqueça de descomentar as linhas dos métodos “BuildMenuPopup” e “SetPopupMenu”.

Segue o código completo do componente:

unit FinderDataZN;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, DbGrids, ADODb, Db, Menus;

type
(* Para indicar a Classe se o Popup Menu foi outo-criado, ou já estava associado
ao DbGrid que "foi" associado ao TFinderDataZN *)
TPopupExistent = (peExternalAssociation, peInternalCreated, peInexistent);

TFinderDataZN = class(TComponent)
private
FReturnValueNum: Double;
FReturnValueStr: String;
FGrid: TDBGrid;
FADataSet: TCustomADODataSet;
FPopupMenu: TPopupMenu;
FIsPopupExistent: TPopupExistent;
FSelectedColumn: TColumn;
FAFieldSearch: TField;

procedure SetGrid(const Value: TDBGrid);
procedure SetADataSet(const Value: TCustomADODataSet);
procedure SetPopupMenu(const Value: TPopupMenu;
const nAllowCreate: Boolean = False);

protected
procedure CreatePopupMenuItem(const NameItem,
CaptionItem: String); virtual;
procedure BuildMenuPopup; virtual;
procedure SetSelectedColumn(const Value: TColumn); virtual;
function GetSelectedColunm: TColumn; virtual;
(* Eventos que serão atribuidos dinamicamente *)
procedure LocalizarClick(Sender: TObject); virtual;
procedure PopupMenuPopup(Sender: TObject);
(*método que vai gerenciar a localização do registro *)
function InputSearchValue: String; virtual;
public
{ Public declarations }
published
Property ReturnValueStr: String read FReturnValueStr;
Property ReturnValueNum: Double read FReturnValueNum;
property Grid: TDBGrid read FGrid write SetGrid;
end;

procedure Register;

implementation

uses FindDataDlgFrmZN;

const
PopupMenuItemName: array [0..1] of String = ('ConfigurarGridSep',
'fdLocalizar');
AMenuItemCaption = 'Localizar %s';

procedure Register;
begin
RegisterComponents('EstacaoZN', [TFinderDataZN]);
end;

{ TFinderDataZN }

procedure TFinderDataZN.BuildMenuPopup;
var
i: Integer;
MyMenuitem: TMenuItem;
begin

(* Verifco se o componente encontra-se em run time*)
if not (csDesigning in Self.ComponentState) then
begin
if Assigned(FPopupMenu) then
begin
for i := 0 to High(PopupMenuItemName) do
begin
if (FPopupMenu.Items.Count > 0) and (i = 0) then
CreatePopupMenuItem(PopupMenuItemName[i], '-');

if (i = 1) then
CreatePopupMenuItem(PopupMenuItemName[i],
Format(AMenuItemCaption, [FGrid.Columns[0].Title.Caption]));
end;

MyMenuitem := TMenuItem(Self.FindComponent(PopupMenuItemName[1]));
if assigned(MyMenuitem) then
MyMenuitem.OnClick := LocalizarClick;

end;
end;
end;

procedure TFinderDataZN.CreatePopupMenuItem(const NameItem,
CaptionItem: String);
var
MyMenuitem: TMenuItem;
begin
MyMenuitem := TMenuItem(Self.FindComponent(NameItem));
if not assigned(MyMenuitem) then
begin
MyMenuitem := TMenuItem.Create(Self);
with MyMenuitem do
begin
Name := NameItem;
Caption := CaptionItem;
end;
FPopupMenu.Items.Add(MyMenuitem);
end;
end;

function TFinderDataZN.GetSelectedColunm: TColumn;
var
i: Integer;
AuxField: TField;
begin
Result := nil;
for i := 0 to Pred(FGrid.Columns.Count) do
begin
AuxField := FGrid.Columns[i].Field;
if Assigned(AuxField) then
if AuxField.FieldName = FGrid.SelectedField.FieldName then
Result := FGrid.Columns[i];
if Assigned(Result) then Break;
end;

end;

function TFinderDataZN.InputSearchValue: String;
var
FindDataDlgForm: TFindDataDlgFormZN;
AuxCaption: String;
begin

if (FADataSet.IsEmpty) then Exit;


try
FindDataDlgForm := TFindDataDlgFormZN.Create(Self);

FindDataDlgForm.Caption := Format(FindDataDlgForm.Caption,
[FSelectedColumn.Title.Caption]);

FindDataDlgForm.Label1.Caption := FSelectedColumn.Title.Caption;

if FindDataDlgForm.Execute then
begin
Result := FindDataDlgForm.EdtDado.Text;
if FADataSet.Locate(FSelectedColumn.Field.FieldName, FindDataDlgForm.EdtDado.Text, []) then
begin
FAFieldSearch.FocusControl;
if FGrid.CanFocus then
FGrid.SetFocus
end;
end;

finally
FindDataDlgForm.Free;
end;
end;

procedure TFinderDataZN.LocalizarClick(Sender: TObject);
var
AValue: String;
AValueNum: Double;
begin

try
AValue := InputSearchValue;
except
on Exception do
AValue := '';
end;

end;

procedure TFinderDataZN.PopupMenuPopup(Sender: TObject);
var
MyMenuitem: TMenuItem;
begin
MyMenuitem := TMenuItem(Self.FindComponent(PopupMenuItemName[1]));
if assigned(MyMenuitem) then
begin
SetSelectedColumn(GetSelectedColunm);
MyMenuitem.Caption := Format(AMenuItemCaption, [FSelectedColumn.Title.Caption]);
end;

end;

procedure TFinderDataZN.SetADataSet(const Value: TCustomADODataSet);
begin
FADataSet := Value;
end;

procedure TFinderDataZN.SetGrid(const Value: TDBGrid);
begin
if FGrid <> Value then
begin
FGrid := Value;

if FGrid <> nil then
begin
FGrid.FreeNotification(Self);
SetSelectedColumn(GetSelectedColunm);
FADataSet := TCustomADODataSet(FGrid.DataSource.DataSet);
(* Cuida da associação, menu popup, associada ao DBGrid *)
SetPopupMenu(FGrid.PopupMenu);
(* Monta os itens de menu, os quais nos referimos
na especificação do componente *)
BuildMenuPopup;

end;
end;
end;

procedure TFinderDataZN.SetPopupMenu(const Value: TPopupMenu;
const nAllowCreate: Boolean);
begin
if (FPopupMenu = Value) and (Value <> nil) then Exit;

If not Assigned(Value) or (nAllowCreate) then
begin
FPopupMenu := TPopupMenu.Create(Self);
FGrid.PopupMenu := FPopupMenu;
FIsPopupExistent := peInternalCreated;
end
else
begin
FPopupMenu := Value;
FIsPopupExistent := peExternalAssociation;
end;

if FPopupMenu <> nil then
begin
FPopupMenu.FreeNotification(Self);
FPopupMenu.OnPopup := PopupMenuPopup;
end;
end;

procedure TFinderDataZN.SetSelectedColumn(const Value: TColumn);
begin
(* Armazena a coluna do Grid aqual foi clickada com o
botão direito do mouse, para capturar informações como: Titúlo e etc.. *)
FSelectedColumn := Value;

if FSelectedColumn <> nil then
FAFieldSearch := FSelectedColumn.Field;
end;

end.


Artigo completo (View Full Post)

domingo, 24 de fevereiro de 2008

Cifra – Tríades, Tétrades e Acordes Invertidos

A Cifra pode informar sobre a inversão do acorde. Toda via, cuidado, pois na teoria musical existem regras que determinam o que é, e como fazer inversão de acordes. Vamos ver um pouco sobre isso neste artigo.

Tríades: Tipo de acorde constituído por apenas três notas, dispostas em intervalos de terças superpostas. A classificação de intervalos define a terça sob duas classificações:

2 tons – terça maior.
1, 5 tom – terça menor.

Exemplo:

---- (2tons) ---- Mi -- (1,5 tom) -- Sol




Antes de falarmos de inversão vamos esclarecer alguns pontos que podem confundir quem está iniciando no assunto: Sobre as notas de um acorde.

1 – Fundamental: Nota que identifica, denomina, o acorde. Ela é sempre a nota mais grave do acorde quando ele se encontrar na posição fundamental.

2 – Baixo: É sempre a nota mais grave do acorde. Independente da posição ou inversão que ele se encontra no momento em que esta sendo executado. Considero que o conceito de baixo deve estar associado ao efeito sonoro que nota, pela sua altura, produz. Por exemplo, uma tríade cujo a sua nota mais grave esteja acima do sol 3 pode ser considerado um acorde onde baixo foi suprimido.

3 – Terça: Segunda nota da tríade ou tétrade quando ela se encontra na posição fundamental. A terça define o modo do acorde. O Modo informa se o acorde é maior ou menor.

4 – Quinta: Terceira nota da tríade ou tétrade, isto quando ela se encontra na posição fundamental. A quinta define se o acorde é alterado ou não.

Posição fundamental:

Uma tríade ou tétrade encontra-se na posição fundamental quando a fundamental é a nota mais grave. Em outras palavras, sobre esta configuração dizemos que o acorde não esta invertido. Exemplo: Mi maior na posição fundamental - E



OBS: Obrigatoriamente, a posição fundamental exige que a tríade esteja na posição fechada (pretendo discutir sobre posição do acorde mais tarde).

Primeira Inversão:
Uma tríade encontra-se na primeira inversão quando a terça é a nota mais grave. Exemplo: Invertendo a tríade exemplificada na imagem anterior (Sol# - Si – Mi)




Segunda Inversão:
Uma tríade encontra-se na segunda inversão quando a quinta é a nota mais grave. Exemplo: Invertendo a tríade exemplificada na imagem anterior (Si – Mi – Sol#).




Considerações:
 - Um acorde pode ser invertido.
- Uma Tríade pode ser invertida, ela, além da posição fundamental, pode gerar duas inversões.
- Toda tríade é um acorde, mas nem todo acorde é uma tríade, ou mesmo se quer possuir uma em sua estrutura.


Eu usei o assunto sobre tríades para falar sobre inversão porque acredito ser a forma mais objetiva e pratica. Sendo esta estrutura de acorde simples, fica muito mais fácil introduzir o assunto através dela.

Cifrar inversão de acordes:
Cifrar uma inversão de acorde é muito intuitivo. Indicamos o acorde normalmente com a letra maiúscula (de acordo como explicamos no artigo anterior), caso o acorde seja menor acrescentamos o “m” minúsculo, para indicar a inversão coloca-se uma barra sucedida da letra correspondente a nota que esta no baixo.

Exemplo acorde maior:

C – Dó maior com a fundamental no baixo.
C/E – Dó maior na primeira inversão. Com a terça no baixo.
C/G – Dó maior na segunda inversão. Com a Quinta no baixo.

Exemplo acorde menor:

Em – Mi menor com a fundamental no baixo.
Em/G – Mi menor na primeira inversão. Com a terça no baixo.
Em/B – Mi menor na segunda inversão. Com a Quinta no baixo.

OBS: É importante lembrar que as cifras exemplificadas acima não indicam obrigatoriamente acordes em estrutura de tríades. Todas as cifras acima tranquilamente, dependendo do contexto corresponder aos seguintes acordes:




No caso das tétrades, no que tange inversão de acorde, segue o mesmo esquema. Contudo, só é permitido cifrar inversão de acorde com sétima menor. Visto que, em via de regra, não é permitido nota de tensão no baixo.
Cabe lembrar que, existe uma técnica de harmonização baseada em tríades ensinada em “Berklee College” no curso de arranjo (que o Ian traduziu com “Tríades Estranhas”), essa técnica se baseia em regras especificas, totalmente diferente da aplicação convencional de tríades, as quais favorecem e permitem inversões de acordes com notas de tensão no baixo.

Por hora é só ....

Artigo completo (View Full Post)

Toggle Bookmark - Navegação em Códigos

Dar manutenção em sistemas, sendo eficiente, depende também de uma certa habilidade em navegar no código fonte. Localizar rapidamente, ir para outro ponto e retornar, identificando partes específicas que deverão res modificadas, durante esse processo poder identificar (se possível) as outras partes onde essa, suposta, alteração irá refletir, definitivamente não é algo trivial. A maioria das IDEs possuem alguns mecanismos de auxílio a essa navegação, possibilitando que isso seja feito com um grau maior de rapidez e eficiência. Os Finders (Crtl+F) e Grap Search (GExpert) são muito importantes neste contexto. Um outro mecanismo que não vivo sem é o mecanismo de “bookmark”.



VB 6

No VB 6 para marcar uma linha de código, para posteriomente localizá-la (Automaticamente/rapidamente) acesse o menu Edit | Bookmarks | Toggle Bookmark. A linha onde o cursor estiver posicionado será marcada por uma retângulo azul claro (aqua) na margem esquerda. Só que no VB 6 os Bookmarks não podem ser nomeados.
Para retornar a uma linha de código marcada com um bookmark acesse o menu Edit | Bookmarks and then select Next Bookmark. O Cursor irá automaticamente para o próximo bookmark definido. Se por acaso o cursos estiver no último bookmark de um módulo ele será possicionado no primeiro do módulo seguinte.
Para limpar todos os bookmarks acesse o menu Edit | Bookmarks | Clear All Bookmarks.


Delphi

No Delphi, seja no BDS ou em versões anteriores, os bookmarks são hierarquizados por números. Na linha a qual deseja marcar digite alternadamente “Ctrl”, em seguida “k” sucedido de um número. Para retornar ao ponto marcado, digite “Ctrl” + [O Número correspondente ao bookmark]. Para desmarcar um bookmark repita as mesmas teclas que digitou para marcar.

Netbeans

No Netbeans, existe um menu específico para navegação. O mecanismo de marcar bookmarks e navegar entre eles é semelhante ao do Vb6. As teclas de atalho mudam:

Toggle Bookmark” – finca no item menu “Navegação” (Ou com o botão direito sobre a margem direita da janela do editor de código). A tecla de atalho é Ctrl + Shift + “m”.
Next Bookmark” - finca no item menu “Navegação” (Ou com o botão direito sobre a margem direita da janela do editor de código). A tecla de atalho é Ctrl + Shift + “.” (ponto).
Next Bookmark” - finca no item menu “Navegação” (Ou com o botão direito sobre a margem direita da janela do editor de código). A tecla de atalho é Ctrl + Shift + “,” (Vírgula).

Artigo completo (View Full Post)

quinta-feira, 21 de fevereiro de 2008

Erro no processamento de XML: declaração xml não está

Erro no processamento de XML: declaração xml não está no início da entidade externa

Probleminha bizonho esse!
Essa mensagem de erro estava retornando ao acessar a URL do RSS de um site. Pra piorar, lá pelas tantas observei que o XML gerado, pelo script PHP, funcionava no IE, contudo, no Mozila, não. No inicio imaginei logo que pudesse ser incompatibilidade com o Mozila, tipo alguma tag que estava usando buggava o bagulho ... Mas, que nada ....


Para resolver o problema:

Veja o código fonte do XML que o seu script de servidor (seja JSP, PHP, ASP, ou mesmo Delphi) gerou (chame a URL http://SeuXMLouRSS ... o Browser vai exibir a mensagem de erro e veja o fonte) e verifique se há espaços em branco ou outras coisas esquisitas antes da declaração:
  
"<?xml version=....".


Caso verdadeiro, se houver, o Firefox não vai conseguir interpretar o XML. A mensagem de erro é bem clara:

Posição: [tal ...]
Número da linha 1, Coluna 2:

Portanto, verifique que vai haver linhas em branco no fonte. No meu caso, o fonte estava assim:


.
.
//Aqui tem espaço em braco
<?xml version="1.0" encoding="ISO-8859-1" ?>




<rss version="2.0">
<channel>
.
.


Depois de uma pesquisa rápida no Google, num Fórum um louco mencionou a questão das linhas em branco. Quando consegui fazer com que o script PHP fizesse isso:



<?xml version="1.0" encoding="ISO-8859-1" ?>
<rss version="2.0">
<channel>
<title>Blablablah- Notícias</title>
<link>http://www.bleng.com.br</link>
.
.


Sucesso!! O bagulho funfou!!!
Veja como ficou o script PHP .....


<?
header("Content-type: application/xml"); echo "<?xml version=\"1.0\"
encoding=\"ISO-8859-1\" ?>\n";
include("../../Conn/ZN_Conexao.php");
$sql = "SELECT
blah, Bleng, Landjah
FROM
Wandjah
WHERE
blah = '2'
ORDER by bleng DESC
LIMIT 5";
$query = mysql_query($sql);

?>
.
.
.

Artigo completo (View Full Post)

segunda-feira, 18 de fevereiro de 2008

Cifra

Pré-requisito:

Para um entendimento pleno do sistema de notação musical “Cifra” e necessário o conhecimento prévio dos seguintes assuntos:

* Intervalo.
* Escala Diatônica:
o Maior.
o Menor Natural.
o Menor Harmônica.
o Menor Melódica.
* Ciclo de Quartas e de Quintas.


Definição:

Trata-se de uma simbologia universal desenvolvida para representar um acorde e/ou uma situação harmônica. Ela não deve, de modo geral, induzir ou mesmo predeterminar qualquer informação sobre a posição do acorde, exceto quando se refere a uma inversão do baixo, ou em alguns casos específicos (esses casos devem ser tratado como exceção, não como forma geral). Até hoje na música ainda não foi definido um padrão único de cifragem. Teóricos e estudiosos, ainda lutam pela adoção e difusão de um padrão mais homogêneo. Por isso, e bastante comum encontrarmos divergência de opiniões e simbologias diferentes para cifragem. Um nome de destaque nesse contexto é o professor Ian Guest.

Objetivo:

A Cifra traz na sua essência o objetivo de indicar o “modo” do acorde, a escala e a função harmônica do momento. Com o uso da Cifra evita-se a notação do acorde em pauta, com isso ganhamos em legibilidade e interpretação do trecho musical. Além disso, a utilização da Cifra enfatiza a criatividade do músico, na medida em que ela da liberdade para o mesmo escolher a posição do acorde mais favorável a sua sensibilidade em relação ao tema, o qual executa, bem como os recursos delimitados por seu instrumento.

Devemos evitar ao Cifrar um acorde:

1) Over informação.

Utilização de símbolos que possam, a primeira vista, confundir o leitor, provocando um interpretação equivocada do acorde.

2) Dispensa-se: O emprego de sinais matemáticos ou quaisquer outros que não possuam sentido musical. Exemplo: Operador de soma “+” e operador de subtração “”.

Uma cifragem de difícil entendimento, bem como as que foram escritas com over informação, não significam um alto nível de conhecimento de harmonia. Muito pelo contrário, justamente porque a inteligência do emprego da cifragem é refletido na fácil visualização e interpretação do significado lógico dos movimentos harmônicos.
É fundamental que a programação visual de uma música cifrada seja clara, de fácil entendimento.


Cifrando Acordes:
Usamos as sete primeiras letras, maiúsculas, do alfabeto para representar as sete notas musicais. Partindo da nota Lá até a nota Sol, respectivamente:

  1. Lá = A
  2. Si = B
  3. Dó = C
  4. Ré = D
  5. Mi = E
  6. Fá = F
  7. Sol = G


Na Cifra, a letra maiúscula que indica o carde, informa quem é a nota fundamental do acorde. Ou seja, a nota mais grave (que dá nome ao acrode) quando o acorde se encontrar no estado fundamental. Quando a fundamental for uma nota acidentada acrescentamos a letra Maiúscula um sinal de sustenido (#) ou bemol (b) imediatamente a direita da mesma. Exemplo:

* C# (Dó sustenido)
* Eb (Mi bemol)

Quanto ao modo do acorde

Acorde Maior: Simplesmente não é usado nenhum símbolo que indique isso. Ou seja, é usado somente a letra maiúscula. Em caso de acidente, como mencionado acima, usamos o sustenido e o bemol imediatamente a direita da letra.

Acorde Menor: Para isso usamos a letra “m”, em minúsculo, imediatamente a direita da letra (e o símbolo de acidente, se for o caso). Exemplo:

Cm (Dó menor)

Fm (Fá menor)

Bbm (Si bemol menor)

C#m (Dó sustenido menor)


OBS: Todo acorde subentende uma ou mais escalas, na cifragem de acordes é imprescindível que a simbologia usada deixe muito claro qual a escala (ou quais são as escalas) sobre a qual se estrutura o acorde cifrado.

Notas adicionais nos acordes:

Para indicar a amplitude de um acorde podemos usar algarismos. Os números representam o grau da nota adicional. Embora não seja obrigatório o uso desse recurso, pois o uso de notas adicionais pode ser feito implicitamente. Lembre-se que a Cifra não se ocupa de informar a forma ou quantidade de notas no acorde, pois como foi dito anteriormente a liberdade para o músico montar o acorde cifrado é precedente. Toda via, em muitos casos é conveniente fazer isso explicitamente, principalmente quando a presença da nota adicional não for uma coisa obvia.

Cifras para notas adicionais explicitas:

* Sétimo Grau: A classificação para o sétimo grau define dois intervalos: Refere-se ao sétimo grau da escala sobre a qual o acorde é construído.
A) Sétima Maior: Usa-se o algarismo “7” sucedido da letra “M” maiúsculo. Exemplo:

+ C7M – Dó maior com sétima maior (Escala mior).
+ F#7M – Fá sustenido maior com sétima maior (Escala maior).
+ Ebm7M - Mi bemol menor com 7 maior (escalas menor harmônica ou melódica).

B) Sétima Menor: Usa-se apenas o algarismo “7”. Exemplo:

+ C7 – Dó maior com sétima menor (Escala maior).
+ F#7 – Fá sustenido maior com sétima menor (Escala Maior).
+ Em7 – Mi menor com sétima menor (Escala menor natural).


* Nono Grau: A classificação para o nono grau define três intervalos: Referem-se ao nono grau da escala sobre a qual o acorde é construído.
A) Nona Maior: Usa-se apenas o algarismo “9”. Exemplo:
  + D9 – Ré maior com nona maior (Escala Maior).

B) Nona Menor: Usa-se o algarismo “9” precedido do símbolo de bemol “b”
entre parênteses. Exemplo:

+ D7(b9) – Ré maior com sétima menor e bemol nove (Escala menor
harmônica ou melódica).
+ Ab7(b9) – Lá bemol maior com sétima menor e bemol nove (Escala menor
harmônica ou melódica).
C) Nona Aumentada: Exclusiva para acordes dominantes. Usa-se o algarismo “9” precedido do símbolo de sustenido “#” entre parênteses. Exemplo:
  + D7(#9) – Ré maior com sétima menor e nona aumentada (Escala menor harmônica ou
melódica).
+ Ab7(#9) – Lá bemol maior com sétima menor e nona aumentada (Escala menor
harmônica ou melódica).

* Quarto Grau: A classificação para o quarto grau define dois intervalos: Refere-se ao quarto ou décimo primeiro grau da escala sobre a qual o acorde é construído, convencionalmente para acorde maiores usamos o quarto grau como referência, ao passo que para acordes menores usamos o décimo primeiro.
A) Quarta Justa: Usa-se o algarismo “4” ou “11”. Exemplo:
  + C4 – Dó maior com Quarta (Escala maior, implicitamente define a supressão do
terceiro grau nesta escala neste acorde).
+ F#4 – Fá sustenido maior com sétima maior (Escala maior, implicitamente
define a supressão do terceiro grau da escala neste acorde).
+ Ebm11 - Mi bemol menor com décima primeira maior (escalas menor
harmônica, melódica ou natural).

B) Quarta Aumentada: Exclusivamente só aparece em acordes maiores. Usa-se
apenas o algarismo “#11” entre parêntese. Exemplo:
  + C7(#11) – Dó maior com sétima menor e décima primeira aumentada (Escala menor
melódica).
+ F#7M(#11) – Fá sustenido maior com sétima Maior e décima primeira aumentada
(Escala Maior).

* Décimo terceiro: Refere-se ao sexto ou décimo terceiro grau da escala sobre a qual o acorde é construído, convencionalmente para acordes maiores dominantes usamos o décimo terceiro grau como referência, ao passo que para os demais acordes (não dominantes) usamos o sexto. A classificação para o décimo terceiro grau define dois intervalos:
A) Décima terceira ou sexta: Usa-se o algarismo “6” ou “13”. Exemplo:
   + C6 – Dó maior com sexta (Escala maior, função harmônica não dominante).
+ Ab13 – Lá bemol treze (Escala maior ou menor harmônica, função harmônica
dominante, significa o mesmo que C7(13)).
+ Dm6 – Ré menor com sexta (escala menor natural, ou melódica).

B) Décima terceira Menor ou Bemol treze, sexta menor ou bemol seis: Exclusivo
para acordes menores ou maiores com função harmônica dominante. Usa-se o algarismo “6” ou “13” sucedido do sinal de bemol “b” entre parêntese. Exemplo:
    + Cm(b6) – Dó menor com sexta menor, ou bemol seis (Escala menor, natural ou
harmônica).
+ Ab7(b13) – Lá bemol com sétima menor e bemol treze (Escala menor, natural
ou harmônica).


Considerações finais:

* Toda alteração ou acidentes sobre qualquer grau da escala, numa cifragem deverá ser grafado entre parênteses. Exemplo:

o A7M(#11) – Lá maior com sétima maior e décima primeira aumentada.
o Ebm7(b5) – Mi bemol menor com quita diminuta e sétima menor (Ou Mi bemol
menor meio diminuto).
o G7(b13) – Sol maior com sétima menor e bemol treze.

* É proibido cifragem de inversão de acorde com notas de tensão no baixo, pois essa simbologia não define nenhuma função harmônica, ou na maioria das vezes o som do acorde significa algum outro acorde convencional. Exemplo:

o G7M(#11) /F#
As notas que compõem essa cifra significam um F#m11(b9) ou um F#4(b9).


Como você pôde observar, uma correta interpretação de um trecho harmônico cifrado em muitas situações vai depender de um sólido conhecimento prévio de analise harmônica.

Artigo completo (View Full Post)

sexta-feira, 15 de fevereiro de 2008

Syntax Highlight para Bloggers

What about, this?

Yes, we have!!! Not banana, however ...


Syntax Highlight é uma funcionalidade, presente em alguns editores de texto, que tem a finalidade de tornar o conteúdo digitado nele mais legível (textos e códigos mais inteligíveis). O que ele faz é formatar o texto automaticamente, no imediato momento em que ele esta sendo digitado, com cores, fontes e estilos diferentes de maneira a destacar a categoria das palavras, diferenciando símbolos, sinais ou números digitados uns dos outros. Isso é um auxílio fundamental para programadores, porque essa funcionalidade destaca a estrutura tanto das linguagens de programação, quanto as de marcação. Alem destacar também os erros de sintaxe que podem eventualmente ocorrer durante a implementação de um programa.
Portanto, devemos considerar que o Syntax Highlight é uma forma estratégica, que explora um recurso didático para prover maior legibilidade destacando o contexto do código digitado num editor. Isso é extremamente conveniente para para outros contextos extra editores de texto também. Como no caso de web pages, pois formatar texto no HTML cru, na base do ponteiro e da marreta, não é tarefa pra qqr um. Isso, sem comentar o fato que mesmo assim fica uma "M" (hehehehh).


Já faz algum tempo que tenho conversado com o Felipe sobre conseguirmos um para o Estação ZN. Essa coisa de ficar manualmente destacando as palavras reservadas e comentários, estava me dando um trabalho absurdo. Eu sei que maluquice minha fazer isso, mas agora eu posso ver o meu código formatadinho, sem overhead de trabalho, e isso faz mto feliz!! Hehhehehe ....

Indo ao que interessa:
Eu usei o componente do “uncle Google”: SyntaxHighlighter. Como vocês poderão ver, ele é totalmente escrito em Javascript e CSS, muito simples de implementar, bem fácil de entender e o melhor de tudo: É eficiente, funciona, e suporta diversas linguagens!!!
Aqui vc poderá encontrar um tutorial de como usar no seu blog evitando um probleminha de inconpatibilidade com o a tag "
" em função da formatação de estilo do "Blogger" (embora , baste para isso vc dar uma olhada no fonte do Estação ZN -- últimas linhas).
Eu simplesmente, descaradamente, copiei o que ele descreveu (hehhehe ... cara, I just don’t have enough time).
O Felipe postou um comentário sobre e colocou exemplos.
Ah! vc vai precisar fazer upload dos fontes do componente para algum servidor. Eu usei o Google Pages ("uncle Google" patrocinado geral) .
So ... enjoy yourself!!!





Artigo completo (View Full Post)

quarta-feira, 13 de fevereiro de 2008

Olha aí a galera do Estação ZN trabalhando

Olá novamente caros amigos do blog.

Com 1 ano de vida o ZN está melhorando a cada dia. Agora nossa novidade é Syntax Highlight! Gerson meus parabéns! Ficou ótimo. E foi uma honra pra mim ver a ferramenta funcionando primeiro em meus posts.

Agora nossos códigos postados no ZN vão ficar assim:

Delphi

function Soma(const a: Integer; const b: Integer): Integer;
begin
Result := a + b;
end;


C#

public int Somar(int a, int b) {
return a + b;
}


Java

public int somar(int a, int b) {
return a + b;
}


XML

<dados>
<codigo>1</codigo>
<nome>Felipe</nome>
</dados>


O ZN que já era muito bom (hehe) agora ficou ainda melhor. Mais uma vez valeu e parabéns Gersão! Grande abraço para todos

Artigo completo (View Full Post)

domingo, 10 de fevereiro de 2008

Apresentando dados em XML com XSL

Olá a todos novamente. Depois de um bom tempo fora as coisas se ajeitaram e o tempo acabou sobrando.

Comemoramos 1 ano do Estação ZN - Parabéns aos que postam e muitíssimo obrigado aos que dedicam um pedaço de seu tempo para ler.

O projeto começou com o intuito de ajudar a nós mesmos e também todos que compartilham das idéias, dúvidas e do material apresentado aqui.

Bem, agora vamos falar do assunto do post: Exibindo um documento XML formatado com folhas de estilo XSL

A maneira padrão de apresentar informações para o usuário na Web é o HTML. Esta linguagem começou orientada à formatação do texto a ser exibido para o usuário. Atualmente, com CSS o foco mudou um pouco: agora o objetivo é a informação, e usamos os estilos adequados à entidade que queremos exibir. Então, nas nossas páginas dinâmicas, nós produzimos HTML já formatado via código para exibir os dados.

Está se tornando cada vez mais comum o uso de WebServices (aplicações remotas invocadas através de HTTP e usando o padrão XML para troca de informações) para integrar aplicações na Web, além de outras tecnologias e paradigmas que usam o formato XML para compor resultados vindos do banco de dados. A questão é: como vamos exibir para o usuário as informações que ele quer/precisa ver de forma que ele entenda e que se "encaixe" no layout do site? Simples, vamos "destrinchar" o XML e a partir dele criar um documento HTML formatado, tudo via código. Brincadeira! Hehe...

É aqui que entra em cena as folhas de estilo para XML, as XSL ou XSLT (dois nomes, mesma coisa). Estas folhas de estilo diferem um pouco do CSS porque, enquanto o CSS criar regras de formatação para alguns elementos e classes para serem aplicadas, o XSL funciona como um "documento de apresentação", ou seja, um documento HTML onde indicamos onde cada elemento do documento XML vai aparecer. Como assim? Vamos ver na prática as duas implementações:

HTML:

folha de estilos: estilos.css


p {
font: normal 11px arial;
color: black;
}

.info-cliente {
font: bold arial 15px;
color: red;
}

#grid {
background: #eaeaea;
}


documento HTML: doc.html


<html>
<head>
<style type="text/css">
@import url(estilos.css);
</style>
</head>

<body>
<p>Parágrafo</p>

<div class="info-cliente">Formatação info-cliente</div>

<div id="grid">Grid</div>
</body>
</html>



Aqui o foco do documento é o layout e a informação é disposta junto com o ele.

Vamos ver agora um exemplo de XML com XSL:

folha de estilos: dados_cliente.xsl


<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method='html' version='1.0' encoding='iso-8859-1' indent='yes'/>
<xsl:template match="/">
<html>
<h1>Dados do cliente</h1>

<b>Código:</b> <xsl:value-of select="cliente/codigo"/><br>
<b>Nome:</b> <xsl:value-of select="cliente/nome"/>
</html>
</xsl:template>
</xsl:stylesheet>


documento xml: dados_cliente.xml


<?xml version="1.0" encoding="iso-8859-1"?>
<?xml-stylesheet type="text/xsl" href="dados_cliente.xsl"?>
<cliente>
<codigo>1</codigo>
<nome>Felipe Guerço</nome>
</cliente>


Usando XML + XSL nosso documento de dados contém apenas a informação. Tudo relacionado à formatação entra na folha de estilos, que deixa de ser um arquivo só com definições de fontes, cores e outras formatações e passa a ser um documento completo de formatação dos dados.

Com XSL podemos fazer várias coisas legais. Ele nos oferece bastante recursos para exibir informações inclusive fazendo loop de vários "registros" dentro do XML.

Como o objetivo do post é dar uma visão geral sobre a tecnologia e mostrar suas vantagens, fico por aqui. Mas em breve trarei mais posts sobre recursos e aplicações práticas. Aquele abraço e até a próxima.

Artigo completo (View Full Post)

 
BlogBlogs.Com.Br