Newsgroup: it.comp.lang.delphi
Titolo: Comunicazione bidirezionale form-frame

vorrei centralizzare una toolbar fatta di TSpeedButton su un TFrame;
il problema e' far conoscere al form che ospita il Frame, quale evento
e' scattato alla pressione di un pulsante.
Il frame gestisce l'evento, ma il form non lo sa.
Ovviamente il tutto senza usare variabili globali e timer. 

1) crea una classe di questo tipo qua:
Type
  TFrameEvents = class
  public
     // una property per ogni pulsante
     property OnFirstButton: TNotifyEvent read FOnFirstButton write
FOnFirstButton;
     ...
  end;
2) Al tuo form aggiungi un membro private di tipo TFrameEvents
3a) Sulla OnCreate, dichiari la creazione di una istanza di
TFrameEvents
** 3b) In alternativa, puoi dichiarare un tuo costruttore per il form
e fare dentro di esso la creazione di tale istanza.
4) Sempre nel form, dopo averla creata assegni i membri di
FrameEvents:
// il form ha un metodo per ogni pulsante della toolbar del frame...
FrameEvents.OnFirstButton := Self.DoSexWithCindyCrawford;
...
5) Assegni l'istanza di frameevents al frame che avra una property
dello stesso tipo
Self.Frame.FrameEvents := Self.FrameEvents;
6) Il frame, sul click del pulsante fara una cosa del tipo:
if (assigned(FrameEvents)) and  (Assigned(FrameEvents.OnFirstButton))
then
begin
  FrameEvents.OnFirstButton(Sender);
end;
7a) Sulla OnDestroy del form fai la free di FrameEvents
** 7b) In alterativa, dichiari un tuo distruttore per il form nel
quale fai la free di FrameEvents.
Una precisazione:
la comunicazione e' monodirezionale, non bidirezionale.
Il frame notifica al form che c'e' stato un click ma il frame non
riceve segnali di nessun tipo dal frame.
A.

Azz... ho scritto una cazzata.. Mi correggo:
Il frame notifica al form che c'e' stato un click ma il frame non
riceve segnali di nessun tipo dal *FORM*.

>[...]
grrazie molte al TNotifyEvent non ci avevo proprio pensato.
Maurizio 

> grrazie molte al TNotifyEvent non ci avevo proprio pensato.
Esiste gia' di base. Ma se serve puoi dichiararti un evento tuo..
A.

 Il frame gestisce l'evento, ma il form non lo sa.
Se la form deve saperlo, perché usare un frame?

   TFrameEvents = class
Non ne capisco il senso. Se la form deve essere a conoscenza degli
eventi del frame, e quindi essere fortemente accoppiata ad esso, usare
il frame non serve a nulla. Tanto vale spostare la toolbar
direttamente sul form.

>Se la form deve saperlo, perch� usare un frame?
per evitare di copiare TPanel che contiene TSpeedButton,
oltre a TActionList e TImageList su ogni Form.

"Alberto Salvati" ha scritto nel messaggio
[...]
ho provato a mettere in pratica ...
5) Assegni l'istanza di frameevents al frame che avra una property
dello stesso tipo
Self.Frame.FrameEvents := Self.FrameEvents;
qui non ho capito
ed infatti
  if (assigned(FrameEvents)) and  (assigned(FrameEvents.OnBtnChiudi)) then
trovo sempre = nil
unit unt_Test;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, unt_ToolBar;
type
  Tfrm_Test = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    FrToolBar: TFrm_ToolBar;
    EventoToolBar: TFrameEvents;
    ChiudiForm: TNotifyEvent;
  public
    { Public declarations }
  end;
var
  frm_Test: Tfrm_Test;
implementation
{$R *.dfm}
procedure Tfrm_Test.FormCreate(Sender: TObject);
begin
  FrToolBar := TFrm_ToolBar.Create(nil);
  FrToolBar.Parent := frm_Test;
  FrToolBar.Align := alTop;
  //creazione istanza classe TFrameEvents
  EventoToolBar := TFrameEvents.Create;
  //associa Evento del Frame al metodo ChiudiForm
  EventoToolBar.OnBtnChiudi := ChiudiForm;
  //assegna istanza degli eventi del Frame
  //.,...
end;
end.
unit unt_ToolBar;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ActnList, ImgList, Buttons, ExtCtrls;
type TFrameEvents = class
  private
    FOnBtnChiudi: TNotifyEvent;
  published
     // una property per ogni pulsante
     property OnBtnChiudi: TNotifyEvent read FOnBtnChiudi write 
FOnBtnChiudi;
 end;
type
  Tfrm_ToolBar = class(TFrame)
    Panel1: TPanel;
    ActionList1: TActionList;
    BtnChiudi: TSpeedButton;
    ImageList1: TImageList;
    ActChiudi: TAction;
    procedure ActChiudiExecute(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
var FrameEvents: TFrameEvents;
implementation
{$R *.dfm}
procedure Tfrm_ToolBar.ActChiudiExecute(Sender: TObject);
begin
  if (assigned(FrameEvents)) and  (assigned(FrameEvents.OnBtnChiudi)) then
  begin
    FrameEvents.OnBtnChiudi(Sender);
  end;
end; 


Perchè non costruisci una form con il tuo menu e poi la erediti ?
invece di usare il frame
^_Goblin_^
-- 
Ibis et redibis non morieris in bello
http://goblinland.myminicity.com/

^_Goblin_^
Ho gia' provato ed usato questa via,  e tramite VFI e' pratico, pero'
volevo capire se si poteva usare una tecnica migliore.
Maurizio


[/MODEON <Opinione personale>]
Se ti servono 5 form metti il tuo frame su 5 form diverse, se hai 
bisogno di un "qualcosa" fuori dal frame, ma che serve a tutte le form 
cosa fai ? duplichi n-volte il codice in n-form diverse?
Inserimento di bachi a questo punto è elevato all n-esima potenza
[/MODEOFF <Opinione personale>]


 var FrameEvents: TFrameEvents;
A.

> Non ne capisco il senso.
Io ho usato questa tecnica per un mio problema.
Ho un frame che contiene parecchie controlli ed un pulsante.
Al click del pulsante, associo un gestore esterno tramite in quale
leggo delle property che poi mi servono per fare un po di cose.
Ho usato un frame in quanto esso mi serve in molti posti, aka
contenitori di tipo diverso:
1) dentro dei form
2) dentro altri frame
3) dentro tabsheet di pagecontrol
e ogni contenitore potrebbe usare in modo diverso le informazioni
esposte dalle property del frame
In un contesto del genere usare WFI o altro avrebbe risolto solo parte
del mio problema.
Con questa soluzione posso usare il frame dove mi pare senza legami di
ereditarieta' e ho un solo contenitore per la logica dello specifico
dataentry gestito dal frame.
Aggiungo che le logiche di dataentry sono molto molto complesse.
Nella mia risposta, mea culpa, ho dato per scontato che chi ha aperto
il th si trovasse davanti un problema analogo al mio.
Certo, se lo scopo e' *solo* avere una toolbar, metterla su un form
radice di una gerarchia e' la soluzione ottimale.
A

 5) Assegni l'istanza di frameevents al frame che *avra una property dello stesso tipo *
Non serve aggiungere altro.
A.

 oltre a TActionList e TImageList su ogni Form.
Questo problema si risolve con la VFI (Visual Form Inheritance).
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 Io ho usato questa tecnica per un mio problema.
Fammi un esempio concreto, cos� capisco meglio.


 volevo capire se si poteva usare una tecnica migliore.
Migliore in base a quale principio?
