Newsgroup: it.comp.lang.delphi
Titolo: CallBack da Form figlio

dopo la soluzione OOP , del ridimensionamento Form
(post Tform come parametro), sto provando ad applicare il concetto
al Form Figlio/Padre, ma sembra che non possa avere il controllo.
 
FormA deriva da frm_Appoggio
 
FormA disabilita alcuni controlli e crea FormB
al Close di FormB viene chiamato Close (su frm_Appoggio)
 
il FormB si chiude ma non ha appligli per comunicare con FormA e 
riabilitare i controlli,
salvo mettere su FormA, nella sezione (create di FormB)
 
FormB.act_Chiude.AbilitaControlli
 
so che le chiamate sono a senso unico, FormA -> FormB.
 
bisogna farsi una unit con Interfacce e definire i metodi che posso 
esere chiamati da FormA e FormB ?
 
unit Interfacce
  procedure ChiudePadre
     /   \
    /     \
FormA  FormB
         chiama ChiudePadre
 
FormA crea FormB := TFormB.Create(Self)
il FormB sarebbe distrutto da FormA.

 riabilitare i controlli,
 
Usa ShowModal sul form "figlio" e analizza il risultato di questo 
metodo. I form sono classi e devono restare disaccoppiate il più 
possibile. Costruire call back da B (figlio) ad A (padre) significa che 
A sa che esiste un figlio B, e il figlio B sa che esiste un padre A. Il 
primo aspetto è necessario, il secondo è evitabile.
 


non posso utilizzare Parent, che renderebbe inutilizzabili i 
JvSpeedButton (disabilitati)
 
senza Parent, risulta problematico il posizionamento del Form
FornB.BorderStyle := bsNone;
FormB.position := poDesigned
 
procedure TFormA.JvSpeedButton4Click(Sender: TObject);
begin
   inherited;
   FormB := TFormB.Create(Self);
   //Form3.Parent := Self;
   FormB.Top := FormA.Top + FormA.Panel1.Top + FormA.Panel1.Height + 5;
   FormB.Left := FormA.Left + FormA.Panel1.Left;
   FormB.Width := FormA.ClientWidth;
   FormB.Height := FormA.ClientHeight - FormA.Panel1.Height;
   FormB.ShowModal;
end;
 
si puo' evitare il conflitto tra Parent e ShowModal ?

 senza Parent, risulta problematico il posizionamento del Form
 
Spiegati. Che vuoi dire?
 
 


scopo: posizionare il nuovo FormB sotto Panel1 di FormA
 
dopo ShowModal non c'e' corrispondenza nelle posizioni Top;
mancano i Pixel relativi all'altezza del Titolo del Form
 
se uso GetSystemMetrics(SM_CYCAPTION) non risulta sotto Panel1
se aggiungo 31 pixel a FormB.Top, risulta posizionato sotto Panel1
 
Es1:
uso Parent e Show; FormA posizionato a 100,100
FormB risulta posizionabile relativamente a FormA
trovo FormB => Top 65 Left 0
 
   FormA.Top := 100;
   FormA.Left := 100;
   FormA.Panel1.Caption := IntToStr(FormA.Top + FormA.Panel1.Top + 
FormA.Panel1.Height);
   FormB := TFormB.Create(Self);
   FormB.Parent := Self;
   FormB.Top := FormA.Panel1.Top + FormA.Panel1.Height;
   FormB.Left := FormA.Panel1.Left;
   FormB.Width := FormA.ClientWidth;
   FormB.Height := FormA.ClientHeight - FormA.Panel1.Height;
   FormB.Panel1.Caption := IntToStr(FormB.Top);
   FormB.Show;//Modal;
 
Es2:
uso ShowModal
FormB risulta a Top 165 Left 100
ma viene visualizzato circa a meta di Panel1
 
   FormA.Top := 100;
   FormA.Left := 100;
   FormA.Panel1.Caption := IntToStr(FormA.Top + FormA.Panel1.Top + 
FormA.Panel1.Height);
   FormB := TFormB.Create(Self);
   //FormB.Parent := Self;
   FormB.Top := Forma.Top + FormA.Panel1.Top + FormA.Panel1.Height;
   //FormB.Top := FormA.Top + FormA.Panel1.Top + FormA.Panel1.Height + 31;
   //FormB.Top := FormA.Top + FormA.Panel1.Top + FormA.Panel1.Height + 
GetSystemMetrics(SM_CYCAPTION);
   FormB.Left := FormA.Left + FormA.Panel1.Left;
   FormB.Width := FormA.ClientWidth;
   FormB.Height := FormA.ClientHeight - FormA.Panel1.Height;
   FormB.Panel1.Caption := IntToStr(FormB.Top) + ' - ' + 
IntToStr(FormB.Left);
   FormB.ShowModal;

 scopo: posizionare il nuovo FormB sotto Panel1 di FormA
 
Domanda: perché usare un form? Da un pezzo, in Delphi, esistono i
frame, che sono (e puoi usare come) componenti. Sono l'ideale per
metterci altri componenti e controlli e allo stesso tempo sono
posizionabili sulla form, senza dover gestire l'overhead di nuove
finestre etc.
 
In ogni caso, per rispondere al quesito, ogni form, alla Close, fra le
altre cose chiama l'eventuale metodo collegato all'evento OnClose.
Questo non necessariamente dev'essere un metodo del form che si sta
chiudendo, ma può essere assegnato anche ad altri (v. esempio in
fomdo).
 
Il principio ispiratore, comunque (specie vedendo il tuo codice),
dev'essere il disaccoppiamento, come consigliato anche da Andrea
Laforgia. Fà sempre finta che una classe non sappia *nulla* di
un'altra, se non i metodi pubblici, e vivrai molto meglio sia tu, sia
il tuo codice.
In particolare, una form [caps mode on] NON DEVE MAI [caps mode off]
sapere quali controlli ha un'altra form: se proprio proprio è
necessaria un'interazione, crea un metodo che fa il lavoro e rendilo
pubblico. Ma se ci ripensi meglio, puoi vedere che l'interazione non è
necessaria, eventualmente ridisegnando le classi.
 
// a sample written here: doesn't necessarily compiles as-is
 
procedure TFatherForm.MakeABaby();
var aSon: TChildForm;
    initInfos: TInitInfos;
begin
  aSon := TChildForm.Create(Self);
  initInfos := TInitInfos.CreateAndInit;
  try
    aSon.InitYourselfSoThatIDonTNeedToDoIt(initInfos);
  finally
    initInfos.Free;
  end;
  aSon.OnClose := HandleChildClosure;
  aSon.Show;
end;
 
procedure TFatherForm.HandleChildClosure(Sender: TObject);
begin
  if not (Sender is TChildForm) then
     ShowMessage('Impostore: Tu nun sei figghiu ''a mia')
  else
     ShowMessage('Figghiu| Ti chiudesti ah!!!');
end;
 
Saluti
Paolo Arosio

 sapere quali controlli ha un'altra form
 
Ah, quanto codice orribile e spaghettiforme in meno ci sarebbe se le
dichiarazioni dei controlli fossero /private/ invece che /pubbliche/
cosi' non indurrebbe in tentazione i neofiti! :)
 
ciao
G
 
PS.
si, so la ragione per cui sono pubbliche, era solo per dire... ;)
 

 cosi' non indurrebbe in tentazione i neofiti! :)
 
Di spaghettiforme noi stimiamo soltanto il FSM 
http://it.wikipedia.org/wiki/Pastafarianesimo
 
 
:-)
 
Saluti
Paolo Arosio

> 
http://it.wikipedia.org/wiki/Pastafarianesimo
 
 
maro' che simpatico.... :-D
 
A.

> finestre etc.
 
ok, uso i Frame, pero' qualcosa non mi torna:
 
quando creo un frame chiama Create di FrmBase;
ho bisogno di chiamare Create do frmProva
 
  frmTest := TfrmTest.Create(Self);
 
 
FrmBase = class(TFrame)
 
   public
     { Public declarations }
     constructor Create(AOwner: TComponent) ; override;
     destructor Destroy; override;
 
constructor TFrmBase.Create(AOwner: TComponent);
begin
   inherited Create(AOwner);
end;
 
destructor TFrmBase.Destroy;
begin
   inherited Destroy;
end;
 
FrmTest = class(TFrmBase)
 
   private
     { Private declarations }
 
     constructor Create(AOwner: TComponent) ; override;
 
constructor TfrmTest.Create(AOwner: TComponent);
begin
   inherited;
   <codice che mettevo su OnCreate d TForm>
end;
 
^^^^^^^^^^^^^^
cambio sistema, l'idea e' chiamare un metodo che a sua volta chiamera' 
il Costruttore.
 
creo un metodo pubblico Inizializza su TFrmBase e TFrmTest
 
TFrmBase = class(TFrame)
public
  procedure Inizializza(AOwner: TComponent);
 
procedure Tfrm_Base.Iniizializza(AOwner: TComponent); virtual
begin
   Create(AOwner);
end;
 
TFrmTest = class(TFrmBase)
public
  procedure Inizializza(AOwner: TComponent); override
 
procedure Tfrm_Uffici.Iniizializza(AOwner: TComponent);
begin
   Create(AOwner);
   <codice che mettevo su OnCreate d TForm>
end;
 
non vedo il metodo pubblico ...
frmTest := TfrmTest.Inizializza(Self); <- non esiste
 

> [...]
 
altra prova, nuovo progetto: 1Form , 1Frame, 1Frame ereditato
trovo che frm_Test sia inizializzato, non mi pare normale.
 
implementation
 
{$R *.dfm}
 
uses Unit3;
 
procedure TForm1.Button1Click(Sender: TObject);
var frm_Test: TFrmA;
begin
    //--- frm_Test <> nil
    if not Assigned(frm_Test) then
     begin
      frm_Test := TFrmA.Create(Self);
      frm_Test.Inizializza;
      frm_Test.Parent := Self;
      frm_Test.Top := 0;
      frm_Test.Left := 0;
      frm_Test.Show;
     end;
end;
 
unit Unit2;
 
interface
 
uses
   Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, 
System.Classes,
   Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs;
 
type
   TFrmBase = class(TFrame)
   private
     { Private declarations }
 
   public
     { Public declarations }
     procedure Inizializza; virtual;
   end;
 
implementation
 
{$R *.dfm}
 
{ TFrmBase }
 
procedure TFrmBase.Inizializza;
begin
//
end;
 
end.
 
unit Unit3;
 
interface
 
uses
   Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, 
System.Classes, Vcl.Graphics,
   Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Unit2;
 
type
   TFrmA = class(TFrmBase)
   private
     { Private declarations }
 
   public
     { Public declarations }
     procedure Inizializza; override;
   end;
 
var
   FrmA: TFrmA;
 
implementation
 
{$R *.dfm}
 
{ TFrmA }
 
procedure TFrmA.Inizializza;
begin
   inherited;
   ShowMessage('aaa');
end;
 
end.
 
// I Frame non vengono autocreati
//
program Project1;
 
uses
   Vcl.Forms,
   Unit1 in 'Unit1.pas' {Form1},
   Unit2 in 'Unit2.pas' {FrmBase: TFrame},
   Unit3 in 'Unit3.pas' {FrmA: TFrame};
 
{$R *.res}
 
begin
   Application.Initialize;
   Application.MainFormOnTaskbar := True;
   Application.CreateForm(TForm1, Form1);
   Application.Run;
end.

> [...]
ho risolto i problemi precedenti:
 
nella classe del Frame di appoggio, aggiungo il metodo virtual DoInizia;
nel Frame ereditato rendo DoInizia override;
quando la classe Base esegue create, richiama DoInizia
che puntualmente viene intercettato dalla classe Frame derivato, 
permettendo di eseguire operazioni locali.
 
anche il problema relativo all'istanza non = nil e' risolta, sicuramente 
dovuta a una errata assegnazione.
 
Alessandro.
 
type
   TFrame2 = class(TFrame)
   private
     { Private declarations }
 
   protected
     procedure DoInizia; virtual;
 
   public
     { Public declarations }
     constructor Create(AOwner: TComponent); override;
     destructor  Destroy; override;
   end;
 
implementation
 
{$R *.dfm}
 
{ TFrame2 }
 
constructor TFrame2.Create(AOwner: TComponent);
begin
   inherited Create(AOwner);
   DoInizia;
end;
 
type
   TFrameA = class(TFrame2)
   private
     { Private declarations }
     procedure DoInizia; override;
 
   public
     { Public declarations }
   end;
 
var
   FrameA: TFrameA;
 
implementation
 
{$R *.dfm}
 
{ TFrameA }
 
procedure TFrameA.DoInizia;
begin
   inherited;
   ShowMessage('aaaa');
end;
 
procedure TForm1.Button1Click(Sender: TObject);
begin
   if not Assigned(FrameA) then
    begin
     FrameA := TFrameA.Create(Self);
     FrameA.Parent := Self;
     FrameA.Show;
    end;
end;