atribuir duas procedures a um evento

Delphi

11/02/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.


Raserafim

Raserafim

Curtidas 0

Respostas

Marco Salles

Marco Salles

11/02/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

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



GOSTEI 0
Raserafim

Raserafim

11/02/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.


GOSTEI 0
Marco Salles

Marco Salles

11/02/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.


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

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


GOSTEI 0
Raserafim

Raserafim

11/02/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


GOSTEI 0
Marco Salles

Marco Salles

11/02/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


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


GOSTEI 0
Raserafim

Raserafim

11/02/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


GOSTEI 0
Raserafim

Raserafim

11/02/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;


GOSTEI 0
Marco Salles

Marco Salles

11/02/2006

Deixa ver se eu entendi

[b:6daa48510e]vamos supor que se tenha dois edits nun form[/b:6daa48510e]

[b:6daa48510e]os dois edits tem definidos um evento onexit a nivel de projeto[/b:6daa48510e]

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


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

[b:6daa48510e]defino na secção private do formulário a procedure[/b:6daa48510e]

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

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

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;

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


[b:6daa48510e][color=darkred:6daa48510e]finalmente voce deve testar [/color:6daa48510e][/b:6daa48510e]... :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 [b:6daa48510e]tag[/b:6daa48510e] 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;

[b:6daa48510e]e claro que previamente esses edits a nivel de projeto , terao que ter os seu tag no valor igual a 2[/b:6daa48510e]


GOSTEI 0
Raserafim

Raserafim

11/02/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.


GOSTEI 0
Marco Salles

Marco Salles

11/02/2006

entenda uma coisa:

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


desculpe , mas para mim ta dificil de entender :cry: :cry: :cry:

[b:cdff9b0c75]Voce disse que esta conseguindo concatenar [/b:cdff9b0c75]

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
.

eu não sei como voce esta fazendo esta concatenação .. O que sei é que se estivessemos pensando em [b:cdff9b0c75]classe pai e classe filho [/b:cdff9b0c75], fariamos isto com as directivas [b:cdff9b0c75][color=darkblue:cdff9b0c75]Virtual , Override e Inherited[/color:cdff9b0c75][/b:cdff9b0c75]

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

Boa sorte...


GOSTEI 0
Raserafim

Raserafim

11/02/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:
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:
  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.


GOSTEI 0
Raserafim

Raserafim

11/02/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:
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:
  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.


GOSTEI 0
Michael

Michael

11/02/2006

Olá [b:dd9a4fb5f1]raserafim[/b:dd9a4fb5f1]!

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:

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


A função [b:dd9a4fb5f1]Assigned [/b:dd9a4fb5f1]não vai permitir que vc sobrescreva o manipulador do evento [b:dd9a4fb5f1]OnExit [/b:dd9a4fb5f1]de um controle que já tenha implementado um. Cada [b:dd9a4fb5f1]TEdit [/b:dd9a4fb5f1]que implementar seu próprio evento [b:dd9a4fb5f1]OnExit [/b:dd9a4fb5f1]deve chamar a rotina [b:dd9a4fb5f1]Funcionalidade[/b:dd9a4fb5f1], antes ou depois do código, dependendo do que vc quer fazer. Para não ficar preso ao nome [i:dd9a4fb5f1]Funcionalidade[/i:dd9a4fb5f1], 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 [b:dd9a4fb5f1]OnExit [/b:dd9a4fb5f1]específicos.

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


GOSTEI 0
Marco Salles

Marco Salles

11/02/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:


[b:4a2b9db8d8]Ajuda de mais.... Vale mais do que mil palavras[/b:4a2b9db8d8]

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 :

[color=blue:4a2b9db8d8][b:4a2b9db8d8]1)
mudei os parametros da função Funcionalidade ,
Mudei tb de Privativo para protegido
intoduce a palavra chave virtual no método Funcionalidade;[/b:4a2b9db8d8][/color:4a2b9db8d8]

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

[color=red:4a2b9db8d8]2)Parte[/color:4a2b9db8d8]
e em cada form do meu projeto declaro esta Unit, e no evento OnShow coloco:


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

b)crie uma [b:4a2b9db8d8]classe filha [/b:4a2b9db8d8], note a introdução da palavra chave[b:4a2b9db8d8][color=darkred:4a2b9db8d8] Override[/color:4a2b9db8d8][/b:4a2b9db8d8]

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


:idea: :idea:
[b:4a2b9db8d8]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:[/b:4a2b9db8d8]

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[b:4a2b9db8d8][color=darkred:4a2b9db8d8] tag [/color:4a2b9db8d8][/b:4a2b9db8d8]definindo diversos tipos de métodos.. [b:4a2b9db8d8]é claro que os valores do tag tem que serem definidos a nivel de projeto[/b:4a2b9db8d8]

[b:4a2b9db8d8][color=blue:4a2b9db8d8]4)falta ainda eu criar uma variavel do tipo MeuFormulario[/color:4a2b9db8d8][/b:4a2b9db8d8]

var
  Form2: TForm2;
  Novoformulario:Meuformulario;


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

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


[b:4a2b9db8d8]note que no meu caso eu estou atribuindo aos edits do formulario2 (Form2) os evento onexit que eu quero[/b:4a2b9db8d8]

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

boa sorte.


GOSTEI 0
Raserafim

Raserafim

11/02/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?


GOSTEI 0
Michael

Michael

11/02/2006

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 [b:4d26773b64]Marcos Salles[/b:4d26773b64], 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 [b:4d26773b64]Tag [/b:4d26773b64]deles. No fundo os conceitos são os mesmos, apenas as abordagens que são diferentes.

[]´s


GOSTEI 0
Raserafim

Raserafim

11/02/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.


GOSTEI 0
POSTAR