Desenvolvimento - Delphi

Multicast Events no Delphi

Veja neste artigo como aplicar o conceito de multicast events no Delphi.

por Marco Antonio Salles



Mexer em buraco de formigueiro sempre é uma má ideia. Cutucar a onça com vara curta então nem se fala. São ditados populares que mesmo sem termos praticado (acho eu) concordamos com eles. Existem muitos deste gênero e todos retratam a consequência de uma má ideia. E hoje eu tive uma delas, que seria simular o Multicast events em Delphi . Talvez eu me conformasse mais no formigueiro ou mexer com a onça, mas resolvi brincar com o Delphi. Mas chega de trocadilhos e metáforas e seguiremos em frente. Só para não perder o Style, quem está na chuva é para se molhar.

Algumas linguagens permitem que um evento chame vários métodos quebrando uma limitação que existe nativamente na VCL. Estamos falando de Multicast events, que no Prism é assim definido:

Listagem 1: Multicast events no Prism

Button1.Click +=Button_Click_1;
Button1.Click +=Button_Click_2;
Button1.Click +=Button_Click_3;

Quando o Botão for clicado, em um único evento, três métodos serão chamados. Podemos definir quais são esses eventos ainda em nível de projeto, o que eu acho fantástico e acredito que brevemente esta funcionalidade estará incorporada ao Delphi deixando este artigo obsoleto. Porém enquanto este dia não chega iremos propor aqui uma alternativa, que ao clicarmos em um Botão no Delphi sejam executados dois eventos, simulando o Multicast events do Prism .

Quero deixar aqui registrado de antemão, que escolhi o evento onClick de um Button, mas o conceito pode ser aplicado a qualquer evento. Também não estarei generalizando o exemplo, “Interfaceando” suas características, nem aplicando conceitos mais elaborados. O Modelo com um pouco mais de paciência pode ser expansível sem prejuízo nenhum à concepção original.

Vamos lá com algumas definições. Imagine que eu tenha três buttons em um formulários. O Buton1 e o Buton2 com um evento onClick definido em designed time e um terceiro button que não foi definido nada em seu evento onClick. Imagine ainda que eu precise que todos os Butons dos formulários compartilhem do mesmo evento que chamarei aqui de GeralClick(sender:TObject) cuja implementação segue.

Listagem 2: Evento onClick geral

procedure TForm1.GeralClick(Sender: TObject);
begin
//um exemplo simplório, mas imagine isto como um conjunto grande de
//instruções a serem executadas ...
Showmessage('Evento Geral que quer que seja executado');
end;

Por outro lado, os eventos onClick do Button1 e do Button2 respectivamente são:

Listagem 3: Evento onClick do Button1 e Button2

procedure TForm1.Button1Click(Sender: TObject);
begin
//Imagine isto como um conjunto grande de instruções que devem ser executadas
Showmessage('Evento Particular do Button1. Sempre executar');
end;

procedure TForm1.Button2Click(Sender: TObject);
begin

//Imagine isto como um conjunto grande de instruções que devem ser executadas
showmessage('Evento Particular do Button2 . sempre executar');
end;

Bem, acho que já deu para entender que o que queremos… Mas isto, como dissemos anteriormente, não é possível nativamente na VCL. Logo, temos que mexer com a onça. O que segue adiante não entenda como a única e nem a melhor forma apenas minha abstração pessoal e, diga-se de passagem, primitiva do problema original.

Surge a classe TSetEventos definida na unidade uMultiCastEvent cuja implementação segue:

Listagem 4: Classe TSetEventos

unit uMultiCastEvent;

interface

uses
classes , StdCtrls, controls, generics.collections;

Type
TMultiEventos = Array of TNotifyEvent;

Type
TSetEventos = class
strict private
FOnClick : TDictionary;
public
procedure ExecuteOnClik(sender:TObject);
procedure ExcecuteMultiCast(Aonwer:TWinControl;GeralClick:TNotifyEvent);
destructor destroy;override;
constructor create;
property OnClick:TDictionary read FOnClick write FOnClick;
end;

implementation

{ TSetEventos }

constructor TSetEventos.create;
begin
FOnClick :=TDictionary.create;
end;

destructor TSetEventos.destroy;
begin
FOnClick.Free;
inherited;
end;

procedure TSetEventos.ExcecuteMultiCast(Aonwer: TWinControl;GeralClick:TNotifyEvent);
var
C:TComponent;
eventos:TMultiEventos;
begin
for c in Aonwer do
if c is TButton then
begin
if (assigned(TButton(C).OnClick)) then
begin
SetLength(eventos,2);
eventos[0]:=TButton(C).OnClick;
eventos[1]:=GeralClick;
end
else
begin
SetLength(eventos,1);
eventos[0]:=GeralClick;
end;
self.OnClick.Add(TButton(C),eventos);
TButton(C).OnClick:=self.ExecuteOnClik;
end;
end;

procedure TSetEventos.ExecuteOnClik(sender: TObject);
var
eventos:TMultiEventos;
I: Integer;
begin
setlength(eventos,high(self.FOnClick.Items[sender])+1);
for I := Low(eventos) to High(eventos) do
begin
eventos[i]:=self.FOnClick.Items[sender][i];
eventos[i](sender);
end;

end;

end.

Bem, criamos um classe que será responsável por executar ou simular o Multicast Events no Delphi. Para saborear os bolinhos que esta classe disponibiliza, neste formulário onde estão definidos os buttons (Button1, Button2, Button3) com os respectivos manipuladores de eventos (Button1.click, Button2.click, Geralclick), damos uses a unidade uMultiCastEvent . Abaixo (um parcial) de como esta a unidade unit1 do form em questão.

Listagem 5: Código do Form1

unit Unit1;

interface

uses
 ........., uMultiCastEvent;

type
 TForm1 = class(TForm)
 Button1: TButton;
 Button2: TButton;
 Button3: TButton;
 procedure GeralClick(Sender: TObject);
 procedure Button1Click(Sender: TObject);

procedure Button2Click(Sender: TObject);
 procedure FormCreate(Sender: TObject);
 procedure FormClose(Sender: TObject; var Action: TCloseAction);
 private
 { Private declarations }
 FSetEventos:TSetEventos; //defina aqui o objeto que consumira a classe
 public
 { Public declarations }
 end;

Bem já definimos os três eventos , resta-nos agora instanciar o objeto e destrui-lo posteriormente. Isto será feito no onCreate do Form e no onClose.

Listagem 6: Eventos onCreate e onClose do form

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
FSetEventos.Free;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
FSetEventos:=TSetEventos.Create;
FSetEventos.ExcecuteMultiCast(self,GeralClick);
end;

Consideração Finais

  • Execute a aplicação e veja o resultado;
  • O Modelo apresentado é expansivel a outros controles e eventos sem maiores dificuldades;
  • Qualquer dúvida que por ventura possa existir, favor entrar em contato
  • O código não foi comentado para poupar espaço;
  • Caso necessite do projeto original , estarei disponibilizando a quem se interessar.

Amigos, vou ficando por aqui, quero agradecer a paciência, pela leitura e deixar registrado que se alguém utilizar desta fonte em algum meio de comunicação , por questões de gentileza , cordialidade bem como o respeito aos direitos autorais que faça menção os tópico Original . No mais meu muito obrigado e até a próxima.

Blog do autor

Marco Antonio Salles

Marco Antonio Salles - Um pouco de merchandising http://marcosalles.wordpress.com/ Se Deus não existe então Vale Tudo