Desenvolvimento - Delphi
Multicast Events no Delphi
Veja neste artigo como aplicar o conceito de multicast events no Delphi.
por Marco Antonio SallesMexer 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.