Array
(
)

atribuir duas procedures a um evento

Raserafim
   - 11 fev 2006

dá para atribuir duas procedures a ao evento onExit?

acontece o seguinte:
na minha aplicação tenho uma rotina que atribui para todos os componentes que tem o evento OnExit uma determinada procedure. sendo que estou precisando colocar em um componente no evento OnExit um determinado código. no entanto não funciona pois ao executar a aplicação este é sobrescrito pela rotina que atribui para todos os componentes.


Marco Salles
   - 11 fev 2006

eu nun sei se estendi direito , mas acho que voce pode usar um flag

Por exemplo , quando o componente receber o foco , no evento onenter voce atribui esta flag igual a true
No evento onexit geral voce testa este flag , se for verdadeiro voce executa

#Código

onexitGeral
begin
codigos comuns a todos os componentes
if flag then
faça algo em especial
flag:=False;
end



Raserafim
   - 11 fev 2006

marcos salles, não posso fazer desta forma pois esta minha rotina geral, uso ela também em outras aplicações, e portanto não pode ter nada em específico nela.


Marco Salles
   - 11 fev 2006


Citação:
marcos salles, não posso fazer desta forma pois esta minha rotina geral, uso ela também em outras aplicações, e portanto não pode ter nada em específico nela.


Se ela é geral , é usada em outras aplicaçoes , qual o problema se voce no componente onde voce quer acrescentar o código voce escrever


Citação:
eventoOnexitDoComponete
begin
executarProcedureOnExitGeral
ExecutarOqueQuero
end;


porque a se é que eu estou entendendo , a saida para isso tem ,
1) voce altera o codigo do eventoOnexit do Componente especifico , conforme mencionei acima ou
2)voce altera o codigoGeral para atender um caso especifico

Sera que eu estou entendendo direito ???


Raserafim
   - 11 fev 2006

o problema marcos salles, é que esta rotina é chamada no OnCreate dos forms, e então varre todo o form e atribui um procedimento ao evento OnExit de todos os componentes que tem este evento


Marco Salles
   - 11 fev 2006


Citação:
o problema marcos salles, é que esta rotina é chamada no OnCreate dos forms, e então varre todo o form e atribui um procedimento ao evento OnExit de todos os componentes que tem este evento


gostaria de entender melhor ...

Coloque um fragmento de codigo do evento OnCreateForm e o como voce faz para atribuir este evento OnExit a todos os componentes que tem esse evento


Raserafim
   - 14 fev 2006

na verdade eu digo os tipos de componentes que quero que sejam atribuidos. no OnCreate do form chamo a rotina geral, que varre todos os componentes do form e os que forem do tipo que eu defini então ele atribui um procedimento ao componente


Raserafim
   - 14 fev 2006

pensei na seguinte hipótese:

na rotina geral faço um código que crie uma procedure dinamicamente juntando as duas procedures. ex:

o Componente Edit1 teria em seu evento OnExit uma chamada a Edit1Exit.

ao abrir este form a rotina geral iria atribuir ao evento OnExit de todos os form a procedure ProcedGeral, sobrescrevendo a que já tinha.
a solução que vejo é: a rotina geral criaria uma procedure dinamicamente desta forma:

procedure Edit1Exit_Dinamica;
begin
Edit1Exit;
ProcedGeral;
end;


Marco Salles
   - 14 fev 2006

Deixa ver se eu entendi

vamos supor que se tenha dois edits nun form

os dois edits tem definidos um evento onexit a nivel de projeto

procedure TForm1.Edit1Exit(Sender: TObject);
begin
showmessage(´evevento OnExit do edit1´);
end;


procedure TForm1.Edit2Exit(Sender: TObject);
begin
showmessage(´evento onexit do edit2´);
end;

defino na secção private do formulário a procedure

procedure EditExit_Dinamica(sender:Tobject); que tem os mesmos paramentros do evento que sera substituido


Citação:
type
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
procedure Edit1Exit(Sender: TObject);
procedure Edit2Exit(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
procedure EditExit_Dinamica(sender:Tobject); //definição

{ Private declarations }
public
{ Public declarations }
end;


defino também a procedure Geral


Citação:
var
Form1: TForm1;

implementation

{$R *.DFM}

procedure Geral;
begin
showmessage(´Faço o que quiser´);
end;


e finalmente no oncreate faço esta conexao da procedure onexit do edit2 com a procedure EditExit_Dinamica;

#Código

procedure TForm1.FormCreate(Sender: TObject);
begin
form1.Edit2.OnExit:=nil;
form1.Edit2.OnExit:=EditExit_Dinamica;
end;


finalmente voce deve testar ... :arrow: e so ai dar o seu parecer do que esta certo e do que esta errado dentro da sua necessidade..

quero destacar que existem rotinas que varrem todos os edits de todos os form , atribuindo automaticamente o novo evento EditExit_Dinamica aos componentes... Alem disso existe a propriedade tag dos componentes que pode ser usada para determinar , quais são os edits que terao seu evento alterado.. Tipo isso

procedure TForm1.FormCreate(Sender: TObject);
var
i:integer;
begin
for i:=0 to form1.ComponentCount-1 do
if form1.Components[i] is TEdit Then
if Tform1(form1.Components[i]).tag = 2 then ///seleção
begin
form1.Edit2.OnExit:=nil;
form1.Edit2.OnExit:=EditExit_Dinamica;
end;
end;

e claro que previamente esses edits a nivel de projeto , terao que ter os seu tag no valor igual a 2


Raserafim
   - 18 fev 2006

entenda uma coisa:
a rotina geral não está dentro do form. está em uma Unit que quero usar em outros projetos. também não existe declarado esta procedure dinamica EditExit_Dinamica.
esta procedure dinâmica foi uma idéia de sugestão para resolver o meu problema. mas que não sei implementar.
ou seja, seria uma procedure que eu iria criar em tempo de execução que concatenasse o procedimento que quero atribuir aos OnExit e o provável procedimento que poderá estar configurado já no componente em tempo de projeto de algum componente.

portanto é o seguinte:
imagine que vc tenha o seu projeto já prontinho. vc colocou alguns tratamentos no evento OnExit de seus Edits. sendo que vc quer ter o a funcionalidade que a minha Unit quer proporcionar. então eu lhe forneço o .DCU dela e te digo: é só vc fazer a chamada a tal procedimento no OnCreate.
pronto. é isso que quero fazer. mas se vc fizer isso a minha rotina foi sobrepro os seus eventos que já existiam no OnExit.
o que quero então é que a minha rotina consiga de alguma forma executar o código dela e mais o código que já existia no seu projeto.


Marco Salles
   - 18 fev 2006

entenda uma coisa:


Citação:
seria uma procedure que eu iria criar em tempo de execução


desculpe , mas para mim ta dificil de entender

Voce disse que esta conseguindo concatenar


Citação:
mas se vc fizer isso a minha rotina foi sobrepro os seus eventos que já existiam no OnExit.



Citação:
o que quero então é que a minha rotina consiga de alguma forma executar o código dela e mais o código que já existia no seu projeto
.

eu não sei como voce esta fazendo esta concatenação .. O que sei é que se estivessemos pensando em classe pai e classe filho , fariamos isto com as directivas Virtual , Override e Inherited

Mas , mostre o seu codigo talves alguem entenda e lhe responda

Boa sorte...


Raserafim
   - 21 fev 2006

Mascos Salles, apesar de eu achar que o código não é necessário para a resolução, mas aí vai pelo menos para melhor entendimento do problema:

criei uma Unit mais ou menos assim:
#Código


unit UFun_Form;


interface

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

type
TFun_Form = class(TForm)
private
procedure Funcionalidade (Sender: TObject);
public
procedure Funcao (Sender: TForm);
end;

var
Fun_Form: TFun_Form;
Frm: TForm;

implementation

procedure TFun_Form.Funcao (Sender: TForm);
var
C: Smallint;
begin
Frm := Sender;
with Sender do
begin
for C := 0 to ComponentCount - 1 do
begin
if (Components[C].ClassType = TEdit) then
begin
TEdit(Components[C]).OnExit := Funcionalidade;
end
end;
end;
end;

procedure TFun_Form.Funcionalidade(Sender: TObject);
begin
Beep; //apenas para simplificar o exemplo.
end;

end.


e em cada form do meu projeto declaro esta Unit, e no evento OnShow coloco:
#Código

Fun_Form.Funcao(Self);


resultado:
ao chamar o procedimento Funcao e passar como parâmetro o form que a chamou, consigo varrer o form e ver todos os componentes que são do tipo TEdit e com isso atribuir ao evento OnExit de cada um o procedimento Funcionalidade.
então neste exemplo iria acontecer o seguinte: ao sair de cada componente TEdit seria emitido um beep.

o problema:
ao chamar o procedimento Funcao ele vai atribuir o procedimento Funcionalidade aos eventos OnExit. e se eu em algum edit em particular eu quiser colocar masis algum código?
do jeito que está este código particular vai ser desprezado. sendo que eu não posso colocar nada em particular neste código que apresentei, pois que utilizar tb em outros projetos.

e eu não disse que eu consegui concatenar para criar uma procedure dinâmica, esta foi apenas uma hipótese que idealizei, mas não consegui implementar.


Raserafim
   - 21 fev 2006

Mascos Salles, apesar de eu achar que o código não é necessário para a resolução, mas aí vai pelo menos para melhor entendimento do problema:

criei uma Unit mais ou menos assim:
#Código


unit UFun_Form;


interface

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

type
TFun_Form = class(TForm)
private
procedure Funcionalidade (Sender: TObject);
public
procedure Funcao (Sender: TForm);
end;

var
Fun_Form: TFun_Form;
Frm: TForm;

implementation

procedure TFun_Form.Funcao (Sender: TForm);
var
C: Smallint;
begin
Frm := Sender;
with Sender do
begin
for C := 0 to ComponentCount - 1 do
begin
if (Components[C].ClassType = TEdit) then
begin
TEdit(Components[C]).OnExit := Funcionalidade;
end
end;
end;
end;

procedure TFun_Form.Funcionalidade(Sender: TObject);
begin
Beep; //apenas para simplificar o exemplo.
end;

end.


e em cada form do meu projeto declaro esta Unit, e no evento OnShow coloco:
#Código

Fun_Form.Funcao(Self);


resultado:
ao chamar o procedimento Funcao e passar como parâmetro o form que a chamou, consigo varrer o form e ver todos os componentes que são do tipo TEdit e com isso atribuir ao evento OnExit de cada um o procedimento Funcionalidade.
então neste exemplo iria acontecer o seguinte: ao sair de cada componente TEdit seria emitido um beep.

o problema:
ao chamar o procedimento Funcao ele vai atribuir o procedimento Funcionalidade aos eventos OnExit. e se eu em algum edit em particular eu quiser colocar masis algum código?
do jeito que está este código particular vai ser desprezado. sendo que eu não posso colocar nada em particular neste código que apresentei, pois que utilizar tb em outros projetos.

e eu não disse que eu consegui concatenar para criar uma procedure dinâmica, esta foi apenas uma hipótese que idealizei, mas não consegui implementar.


Michael
   - 21 fev 2006

Olá raserafim!

Múltiplos manipuladores para um mesmo evento não são permitidos em Delphi Win32. Essa característica está disponível apenas no .NET framework.

Porém, nada impede que vc faça algo assim:

#Código

(...)
if (Components[C].ClassType = TEdit) and not Assigned(TWinControl(Components[C]).OnExit) then
begin
TEdit(Components[C]).OnExit := Funcionalidade;
end;
(...)


A função Assigned não vai permitir que vc sobrescreva o manipulador do evento OnExit de um controle que já tenha implementado um. Cada TEdit que implementar seu próprio evento OnExit deve chamar a rotina Funcionalidade, antes ou depois do código, dependendo do que vc quer fazer. Para não ficar preso ao nome Funcionalidade, se ele já não for genérico, crie uma variável de ponteiro de procedure, e use-a para chamar a rotina dentro dos eventos OnExit específicos.

#Código
TForm1 = class(TForm)
private
FOnExitProc: TNotifyEvent;
(...)

procedure TForm1.FormCreate(Sender: TObject);
begin
FOnExitProc := Funcionalidade;
(...)
end;

procedure TEdit1.OnExit(Sender: TObject);
begin
FOnExitProc(Edit1);
// Código específico de Edit1
end;


[]´s


Marco Salles
   - 21 fev 2006


Citação:
Mascos Salles, apesar de eu achar que o código não é necessário para a resolução, mas aí vai pelo menos para melhor entendimento do problema:


Ajuda de mais.... Vale mais do que mil palavras


Citação:
Múltiplos manipuladores para um mesmo evento não são permitidos em Delphi Win32. Essa característica está disponível apenas no .NET framework.

Porém, nada impede que vc faça algo assim:


então como escreveu o nosso amigo michel , tecnicamente o delphi win.32 não permite uma solução mais tecnica do problema , porem como ele mesmo disse , nada impede que voce ache uma solução para o problema

e pensando nisso eu fiz assim :

1)
mudei os parametros da função Funcionalidade ,
Mudei tb de Privativo para protegido
intoduce a palavra chave virtual no método Funcionalidade;

#Código

type
TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
protected
procedure Funcionalidade (Sender: TObject);virtual;
{ Private declarations }
public
procedure Funcao (form: TForm);
{ Public declarations }
end;


ate ai tudo bem, o resto continua o mesmo..

2)Parte

Citação:
e em cada form do meu projeto declaro esta Unit, e no evento OnShow coloco:


a)Não , agora esta unit tem que ser definida na uses da secção interface e nao mais na uses da secçao implementacion. Alem disso :

b)crie uma classe filha , note a introdução da palavra chave Override

#Código
Type
Meuformulario =Class (TForm1)
private
procedure Funcionalidade (sender: TObject);Override;
end;


:idea: :idea:
3)nesta classe de um ´CTRL+C´ para que o editor do delphi inclua automaticamente a definição .. Ira aparecer a palavra Chave Inherited
ficando mais ou menos assim:

#Código
procedure Meuformulario.Funcionalidade(sender: TObject);
begin
inherited;
case TEdit(sender).tag of
0:showmessage(´incluir metodos de nivel 0´);
1:showmessage(´incluir metodos de nivel 1´);
2:showmessage(´incluir metodos de nivel 2´);
end;
end;


:idea: :idea:
note que eu coloquei ainda a propriedade tag definindo diversos tipos de métodos.. é claro que os valores do tag tem que serem definidos a nivel de projeto

4)falta ainda eu criar uma variavel do tipo MeuFormulario

#Código
var
Form2: TForm2;
Novoformulario:Meuformulario;


:arrow:
e finamente eu istancio esta variavel , uso e libero no show como voce mesmo sugeriu

#Código
procedure TForm2.FormShow(Sender: TObject);
begin
formularioexato:=formulario.Create(self);
Formularioexato.Funcao(form2); ***********
freeandnil(formularioexato);
end;


note que no meu caso eu estou atribuindo aos edits do formulario2 (Form2) os evento onexit que eu quero

eu acho que o que voce quer é isso ai ..

boa sorte.


Raserafim
   - 27 fev 2006

masco salles valeu por algumas sugestões (que acabei acatando), mas ainda não é isso que quero. caso eu não consiga exatamente da forma que quero vou acabar utilizando como base o que vc colocou.
e Michael, acho que o nome que vc disse: ´Múltiplos manipuladores´ está bem próximo ou exatamente o que eu quero.

será que não estou conseguindo me expressar?


Michael
   - 02 mar 2006


Citação:
e Michael, acho que o nome que vc disse: ´Múltiplos manipuladores´ está bem próximo ou exatamente o que eu quero.


Eu disse tbm que múltiplos manipuladores de evento só existem no Delphi for .NET, ou melhor, no .NET framework, e não em Win32.

O código que eu postei é o mais perto disso que vc pode chegar. Não sei se vc chegou a testá-lo, mas desta forma a única coisa que vc irá precisar fazer a mais será chamar a função original dentro do evento que foi implementado individualmente.

Não estou tirando a utilidade da dica do colega Marcos Salles, claro que não. Porém, creio que seja mais intuitivo simplesmente implementar o evento dos componentes que vc queria que tenham um comportamento diferente do que setar a propriedade Tag deles. No fundo os conceitos são os mesmos, apenas as abordagens que são diferentes.

[]´s


Raserafim
   - 03 mar 2006

Michael, realmente não havia prestado tanta atenção na sua dica pois vi logo que não era exatamente o que procurava. mas olhando novamente vi que é a melhor alternativa caso realmente não consiga da forma como imagino.
gostaria de pedir mais uma contribuição, que acredito que será a solução para o que eu quero.
Tem alguma forma de criar e montar um procedimento em tempo de execuçao colocando as instrções que eu quiser tb em tempo de execução?
a idéia é criar um procedimento em tempo de execução que encapsule dois ou mais outros procedimento que foram criados em tempo de projeto.