Newsgroup: it.comp.lang.delphi
Titolo: XE2 intercettare Eventi su Package

Di solito quando da un form ne crea un'altro, posso intercettare gli 
eventi del nuovo Form.
 
es A:
 
senza package posso fare
 
frmX : TForm4;
frmX := TForm4.Create(nil);
frmX.act_Chiude.OnExecute := <procedura ...>
 
 
<procedura ....>
esegue le operazioni necessarie e distrugge
FreeAndNil(frmX);
 
con i Pacakge si puo' fare altrettanto ?
 
  AClass : TPersistentClass;
 
  AClass := TPersistentClass(FindClass('TForm4'));
 
  if AClass <> nil then
 
  se si puo' come trasformo questo
 
   with ComponentClass(AClass).Create(Application) as TCustomForm do
    begin
    end;
 
  nell'analogo di es A:

Somiglia molto a quello che segnalavo io:
La classe TCustomform non conosce "act_Chiude".
solo TForm4 conosco "act_Chiude".
Ergo:
 
1) per vedere "act_Chiude" devi fare un cast.
2) Per fare un cast la app deve conoscere tform4
 
Quiindi, in un caso del genere, avere il form "fuori" non serve a
niente... :-|
 
A.


Concordo. L'unico modo e' avere una classe astratta (o una interfaccia) 
quindi ti puoi scordare di accedere liberamente alle proprieta' 
della classe nel package.
 
Qui delphi risente del fatto che le unit definite in un unico file, mentre
in c/c++ avendo due file diversi per interfaccia e implementazione riesci 
a fare questo giochino in modo piu' agevole (in apparenza! perche' poi
a capire cosa succede quando hai dei casini ti diverti...)
 
ciao
G


se ho capito, mi serve una Unit (che contiene l'interfaccia) visibile 
sia dal Form che dal Package (avere nel required il modulo con 
l'interfaccia)
 
Maurizio

 l'interfaccia)
 
 
a) se usi un interfaccia, essa deve esporre tutti i metodi che ti
potrebbero servire e i tuoi form DEVONO implementarla.
Ricordati di esporre un metodo che ri restuisce il riferimento al
form:
 
IMYFormInterface = interface['{0EFA12BD-16FB-4131-A562-EB9BD8BD64B6}']
  function FaiQualcosa: integer;
  function FormReference: TForm; <<<<<<<<<<<<<<<<<
end;
 
TMyForm = class(TForm, IMyFormInterface)
...
 
In questo modo, se devi accedere al form e non te ne fotte delle
SPECIFICITA' DEL FORM, hai comunque il riferimento a TForm....
 
 
b) se usi una classe form radice, questa classe deve esporre tutti i
metodi che ti potrebbero servire e i tuoi form DEVONO ereditare da
essa:
 
TMyForm = class(TMyBaseForm)
....
 
A.
 
 
 
A.

> Concordo. L'unico modo e' avere una classe astratta (o una interfaccia)
 
..xche "astratta"? :-|
 
 
A.
 

 ..xche "astratta"? :-|
 
Scusa, cazzata mia: ho scritto astratta ma intendevo "classe base" da mettere nella gerarchia di classi tra TForm e le form del progetto (quindi ovviamente non astratta)... :( 
 
ciao
G

> ....
 
il mio scopo e' creare un ponte (Interfaccia) tra due form che non sono 
in comunicazione.
 
es: Form2 e Form4 non si vedono, unit3 (con Interface fa da ponte)
 
all'interfaccia devo passare il riferimento ad un Form, ma l'unico form 
che "conosco" e' quello da cui chiamo, quindi Form2 o Form4.
 
come posso da Form2 riferimi a Form4 trammite Interface,
senza aggiungere uses unit4 ?
 
Maurizio
 
^^^^
unit Unit3;
 
interface
 
uses
   Vcl.Forms;
 
type IMyInterface = Interface(IInterface)
   ['{0AFC1D25-3598-4A03-A9CB-ACC2B504915E}']
   function Verifica: Boolean;
   function RiferimentoForm: TForm;
End;
 
implementation
 
end.
 
 >>>>>>>>>>>>>> usa il ponte (unit3)
 
unit Unit2;
 
interface
 
uses
   Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, 
System.Classes, Vcl.Graphics,
   Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, unit3;
 
type
   TForm2 = class(TForm, IMyINterface)
     Button1: TButton;
     procedure Button1Click(Sender: TObject);
   private
     { Private declarations }
       function Verifica: Boolean;
       function RiferimentoForm: TForm;
       procedure ChiudeForm(Sender: TObject);
   public
     { Public declarations }
   end;
 
var
   Form2: TForm2;
 
implementation
 
{$R *.dfm}
 
{ TForm2 }
 
procedure TForm2.Button1Click(Sender: TObject);
begin
   RiferimentoForm;
end;
 
procedure TForm2.ChiudeForm(Sender: TObject);
begin
// FreeAndNil(RiferimentoForm);
end;
 
function TForm2.RiferimentoForm: TForm;
begin
   ---> giustamente solleva eccezione, non essendoci un Form specificato
   RiferimentoForm.Create(Application);
   RiferimentoForm.Show;
end;
 
function TForm2.Verifica: Boolean;
begin
//
end;
 
end.
 
 >>>>>>>>>>>>>> usa il ponte (unit3)
 
unit Unit4;
 
interface
 
uses
   Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, 
System.Classes, Vcl.Graphics,
   Vcl.Controls, Vcl.Forms, Vcl.Dialogs, unit3, Vcl.StdCtrls;
 
type
   TForm4 = class(TForm)
     Button1: TButton;
   private
     { Private declarations }
   public
     { Public declarations }
   end;
 
type TClasseForm4 = class(TForm, IInterface)
   private
     function Verifica: Boolean;
     function RiferimentoForm: TForm;
   public
 
   end;
 
var
   Form4: TForm4;
 
implementation
 
{$R *.dfm}
 
{ TClasseForm4 }
 
function TClasseForm4.RiferimentoForm: TForm;
begin
//
end;
 
function TClasseForm4.Verifica: Boolean;
begin
//
end;
 
end.

 in comunicazione.
 
xche?
 
A.


perche' se il form (o datamodule) e' presente su un Package, anche 
volendo non posso vederlo.
 
magari esistono altre tecniche che non conosco.
 
Maurizio
 
 

 magari esistono altre tecniche che non conosco.
 
Puoi adottare questa tecnica:
 
In una unit definisco una interfaccia/classe base e un oggetto che implementa un pattern Factory che crea oggetti derivati da quel tipo base/che implementano quell'interfaccia.
 
Dentro ai package, definisco le mie classi derivate dalla classe base e nella parte initialization eseguo un Register per inserirle nella factory.
 
Quando ho bisogno di una form invoco la creazione tramite la factory:
Molto a grandi linee, qualcosa del genere (ho usato una classe ma va bene anche usare interfacce):
 
 
unit base;
...
type
  TMyForm = class(TForm) 
    function Verifica : boolean;
  end;
  TMyFactory = class
    procedure RegisterMyForm( Nome : string; Tipo : TFormClass );
    function CreaIstanza( Nome : string ) : TMyForm;
  end;
...
unit NelPackage1;
 
uses
  base; // devo derivare da MyForm e devo avere accesso alla factory.
 
type
  TMyForm1 = class( TMyForm )
  ...
  end;
 
implementation
  Factory.RegisterMyForm( 'miaform', TMyForm1 );
end.
 
...
unit CheChiama;
 
uses base; // non devo mettere NelPackage1 nelle unit incluse...
...
var
  Form : TMyForm; // accedo solo tramite classe base! 
 
 
  Form := Factory.Creaistanza( 'miaform' );
  Form.ShowModal(); // eccetera...
  Form.Verifica(); // uso solo metodi/proprieta' della classe base!
 
 
 
ciao
Giacomo

> [..]ciao Giacomo
 
intanto grazie, approfondisco, provo e se non riesco chiedo ancora.
 
Maurizio
 

 volendo non posso vederlo.
 
Ok. domanda diretta:
 
PERCHE' FORM1 DEVE VEDERE FORM2??
 
A.


per poter accedere ai metodi ed eventi.
 
Maurizio
 

 per poter accedere ai metodi ed eventi.
 
 
accedere a metodi ed eventi per fare cosa?
 
A.


dai, che lo sai anche meglio di me cosa si fa con due form in comunicazione.
 
comunque , se ho Form1 che vede Form2 (tramite uses unit2), per 
intercettare un'evento (es: OnFormClose o altro definito trami 
TActionList), devo creare un'istanza su Form1 per Fomr2 ed e' necessario 
che ci sia comunicazione.
 
se invece Form1 non vede Form2 (perche' si trova su un package), serve
un qualcosa che faccia da tramite, ed ovviare il fatto che il Form sul 
pacakge non e' istanziabile direttamente.
 
oppure, visto un progetto in Delphi5 che tra Form e DataModule non vi 
era visibilità, per accedere era necessario passare dal modulo interfaccia.
il codice non era accessibile, non so come avessero fatto e perche' 
questi strati separati, il Db era Orcale.
 
Maurizio


Che db era non e' importante. La separazione invece si. Diciamo che si tratta
di un modo di lavorare che nel breve sembra inutile/scomodo/... ma nel lungo
periodo rende piu' semplice capire e modificare il codice. E' segno di
una progettazione piu' accurata.
 
La conseguenza di cio' e' che se hai bisogno di accedere in modo cosi'
forte alle proprieta' e metodi di un'altra form/datamodule non stai
separando abbastanza le cose, dovresti trovare un sistema piu' generale
ed astratto di lavorare che ti consenta di lavorare in modo che ogni
modulo sappia il meno possibile di quello con cui interagisce: la mia
Form1 non deve lavorare per forza con il datamodule2, ma con un qualsiasi
datamodule che implementi certe funzionalita'. 
La unit "ponte" sicuramente va in questa direzione (cp il mio esempio in cui 
anche io ho messo una unit "base" )
 
Giacomo

 con i Pacakge si puo' fare altrettanto ?
 
Con i package puoi fare tutto ciò che si può fare senza.
 
Il problema vero è che, a mio avviso, non c'è motivo per fare una simile scelta architetturale. :|
 
-- 
MARCO BREVEGLIERI
#Home: 
http://www.marco.breveglieri.name
 
#Blog: 
http://www.compilaquindiva.net