da un form Menu chiamo un altro form GestioneContabileAffGiu (non modale),
va tutto bene, eccetto che vorei evitare la dichiarazione globale di frm_GestioneContabileAffGiu: Tfrm_GestioneContabileAffGiu;
ed averla solo nella procedure.
dovrei riuscire a passare l'istanza frm_GestioneContabileAffGiu a LiberaGestioneContabileAffGiu
qualcosa di simile
frm_GestioneContabileAffGiu.act_Uscita.OnExecute := @LiberaGestioneContabileAffGiu(frm_GestioneContabileAffGiu);
es: se modifico cosi' procedure Tfrm_MenuAree.LiberaGestioneContabileAffGiu(Sender: TObject; var Rifer: TObject);
frm_GestioneContabileAffGiu.act_Uscita.OnExecute := @LiberaGestioneContabileAffGiu(Sender, frm_GestioneContabileAffGiu);
in compilazione
Error: Incompatible type for arg no. 1: Got "<procedure variable type of procedure(TObject;var TCloseAction) of object;Register>", expected "<procedure variable type of procedure(TObject) of object;Register>"
spero in qualche suggerimento.
//Actcion act_Uscita seve ad intercettare la pressione di un tasto cui e' associata la TAction act_Uscita nel form Tfrm_GestioneContabileAffGiu
//
procedure Tfrm_MenuAree.GestioneContabileAffGiu;
var frm_GestioneContabileAffGiu: Tfrm_GestioneContabileAffGiu;
begin
frm_GestioneContabileAffGiu := Tfrm_GestioneContabileAffGiu.Create(Self);
frm_GestioneContabileAffGiu.Parent := Self;
frm_GestioneContabileAffGiu.Top := 0;
frm_GestioneContabileAffGiu.Left := 0;
frm_GestioneContabileAffGiu.Width := Self.ClientWidth;
frm_GestioneContabileAffGiu.Height := Self.ClientHeight;
//
//se uso la dichiarazione locale frm_GestioneContabileAffGiu: Tfrm_GestioneContabileAffGiu;
//quando va ad eseguire LiberaGestioneContabileAffGiu frm_GestioneContabileAffGiu e' = nil
//
frm_GestioneContabileAffGiu.act_Uscita.OnExecute := @LiberaGestioneContabileAffGiu;
frm_GestioneContabileAffGiu.Show;
end;
il metodo close
procedure Tfrm_MenuAree.LiberaGestioneContabileAffGiu(Sender: TObject);
begin
//mi serve ricevere il riferimento frm_GestioneContabileAffGiu
//
frm_GestioneContabileAffGiu.Close;
//FreeAndNil(frm_GestioneContabileAffGiu);
end;
direi che non serve dichiarare un'istanza frm_GestioneContabileAffGiu,
se come penso si tratta di una scelta del tipo:
Form1 -> form base; Form2 -> formchild
dopo la Interface, nelle uses basta aggiungere la unit relativa a <frm_GestioneContabileAffGiu>
unit <MenuAree>;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils ....., <unit relativa a frm_GestioneContabileAffGiu> ...
type
{ Tfrm_MenuAree }
Tfrm_MenuAree = class(TForm)
l'istanza frm_GestioneContabileAffGiu e' già dichiarata nella
unit tramite la var frm_GestioneContabileAffGiu: Tfrm_GestioneContabileAffGiu;
tipicamente in modo simile
Tfrm_GestioneContabileAffGiu = class(TForm)
private
{ private declarations }
public
{ public declarations }
end;
var
frm_GestioneContabileAffGiu: Tfrm_GestioneContabile
implementation
{$R *.lfm}
end.
di conseguenza non serve dichiarare altro, naturalmente il form non deve essere presente
nella creazione automatica dei Form
verifca Opzioni Progetto->Form e se presente sposta tramitye la freccia => sul pannello Form Disponibili;
in caso contrario avrai un doppione quello creato all'avvio e quello creato a runtime
//
procedure Tfrm_MenuAree.GestioneContabileAffGiu;
begin
frm_GestioneContabileAffGiu := Tfrm_GestioneContabileAffGiu.Create(Self);
frm_GestioneContabileAffGiu.Parent := Self;
frm_GestioneContabileAffGiu.Top := 0;
frm_GestioneContabileAffGiu.Left := 0;
frm_GestioneContabileAffGiu.Width := Self.ClientWidth;
frm_GestioneContabileAffGiu.Height := Self.ClientHeight;
frm_GestioneContabileAffGiu.act_Uscita.OnExecute :=@LiberaGestioneContabileAffGiu;
frm_GestioneContabileAffGiu.Show;
end;
quando eseguira' questa parte, l'instanza sara' ancora visibile
procedure Tfrm_MenuAree.LiberaGestioneContabileAffGiu(Sender: TObject);
begin
frm_GestioneContabileAffGiu.Close;
FreeAndNil(frm_GestioneContabileAffGiu);
end;
Ciao a tutti.
Scusate se mi intrometto.
Per me basta solo gestire correttamente gli eventi della form e giocare con la struttura della LCL/VCL.
Allora, CloseAction permette di imposatare il comportamento alla richiesta di chiusura.
E' utile intercettarlo per sapere cosa succede, ma non indispensabile.
Allora Stefano, dichiari la form come child di un'altra form.
Vuoi intercettare correttamente la chiusura, per poter annullare il riferimento esterno alla form secondaria. (Ricapitolo solo per vedere se ho capito il problema).
Se sì, scatta la proposta oscena.
1) Dichiari una variabile nella form primcipale per la form secondaria come TForm.
2) Registri per l'eliminazione del componente il controllore (la form principale) con FreeNotification.
3) Sovrascrivi il metodo notification.
Occhio che questo metodo ha una marea di chiamate. Devi filtare per gli eventi di tipi "eliminazione" e mirare alla componente che ha indirizzo in memoria come la tua form.
Un if banalissimi, spiegato in termini astrusi ;)
if (Operation=...) and (Component = fFormSecondaria) then fFormSecondaria = null;
In questo modo lasci liberi i callback (eventi) della form (il sistema pemette di avere un solo callback nativo, il broad cast degli eventi è sempre fai-da-te-sperando-non-faccia-casini).
Questo è anche un modo molto comodo per fare il broad cast della creazione ed eliminazione dei componenti.
Quando accedi alla fFormSecondaria devi castare il riferimento al tipo della tua form.
Tfrm_GestioneContabileAffGiu(fFormSecondaria).xxxxx
O ti fai una funzioncina che ti semplifici il codice. Ma è esteticamente una pessima idea ;)
Stedano, se hai capito è un miracolo. Penso di essermi espesso malissssssssimo.
Ho scaricato l'esempio, e risulta piu' semplice del mio sistema.
Partendo dal tuo esempio, provo a creare una routine generica (CreaForm), passando il Form da creare,
pero' non accetta aForm
Error: Incompatible type for arg no. 1: Got "TForm", expected "TComponentClass"
per creare chiamo CreaForm , invece di Application.CreateForm(TForm2, FChild)
procedure TForm1.Button3Click(Sender: TObject);
begin
CreaForm(Form2);
//passo Form2 che e' un TForm
end;
ciclo generale di creazione
procedure CreaForm(sForm: TForm);
begin
//Error: Incompatible type for arg no. 1: Got "TForm", expected "TComponentClass"
Application.CreateForm(aForm, FChild); //errore in compilazione, nel parametro aForm
//se invece
Application.CreateForm(TForm2, FChild); //va bene
end;
ho modificato cosi':
procedure CreaForm(aForm: TComponentClass);
begin
Application.CreateForm(aForm, FChild);
FChild.Parent := Self;
FChild.Top := 0;
FChild.Left := 0;
FChild.Show;
FChild.FreeNotification(Self);
end;
e chiamo con CreaForm(<form da gestire>);
es: CreaForm(TForm2);
Puoi dichiarare un tipo :
TFormClass = class of TForm;
e usare questo come tipo del parametro.
Altrimenti la tua routine accetterebbe anche un ... TConnection. (Ad esempio)
EDIT:
Quello che non andava bene nella prima versione è che stavi dicendo al compilatore che deve attendersi una chiamata con passaggio d'istanza.
procedure CreaForm(aForm: TComponentClass); begin Application.CreateForm(aForm, FChild);
Qui, invece, stai dicendo che vuoi passare una classe, un tipo.
ho provato la nuova versione, e tutto bene, eccetto il controllo dei componenti interni al Form
type TFormClass = class of TForm; //dichiarazione
se dentro un Form ho un TPageControl con varie Pagine o un TPanel, non posso accedervi
CreaForm(TFrm_Prova); //creo il Form, ma non ho istanze per Tfrm_Prova
.... come accedo a TPanel o altro ?
<istanza>.pnlComunicazione.Visble := False; //per <istanza> non ho riferimenti
con il metodo "tradizionale" ho un'istanza frm_Prova
frm_Prova := Tfrm_Prova.Create(Self);
frm_Prova.pnlComunicazioni.Visible := False; //nasconde TPanel
//visualizzo le pagine che interessano
for i := 0 to frm_Prova.PageControl1.PageCount -1 do
begin
frm_Prova.PageControl1.Pages[i].TabVisible := True;
if i > 3 then frm_Prova.PageControl1.Pages[i].TabVisible := False;
end;
nuova versione
Tfrm_MenuAree = class(TForm)
procedure CreaForm(aForm: TFormClass);
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
procedure Tfrm_MenuAree.CreaForm(aForm: TFormClass);
begin
Application.CreateForm(aForm, FChild);
FChild.Parent := Self;
FChild.Top := 0;
FChild.Left := 0;
FChild.Show;
FChild.FreeNotification(Self);
end;
un'interfaccia di per se espone dei metodi;
anche implementando l'interfaccia, senza un'istanza specifica ad un Form non sara' possibile
controllare gli elementi interni (forse).
prova a dare un'occhiata al codice
unit unt_InterfaceTest;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Forms;
type TFormClass = class of TForm;
type IEventHandler = Interface
['{3D1B55A3-F2BD-422C-869B-BD63AF8FBDEF}']
procedure CreaForm(aForm: TFormClass);
end;
quindi implemento una classe che usi l'interface
type
{ TGenerale }
TGenerale = class(TInterfacedObject, IEventHandler)
private
FChild: TForm;
procedure CreaForm(aForm: TFormClass);
public
end;
type
{ Tfrm_MenuAree }
Tfrm_MenuAree = class(TForm)
....
private
{ private declarations }
clGenerale: TGenerale; //istanza alla classe TGenerale
...
procedure Tfrm_MenuAree.FormCreate(Sender: TObject);
begin
TFormClass.Create(Self);
try
clGenerale := TGenerale.Create;
end;
ora resta da sostituire Self con un riferimento diretto
procedure TGenerale.CreaForm(aForm: TFormClass);
begin
Application.CreateForm(aForm, FChild);
//TGenerale non e' la classe che gestisce i Form, non conosce Self
{FChild.Parent := Self; }
FChild.Parent := frm_MenuAree.PanelAppoggio;
FChild.Top := 0;
FChild.Left := 0;
FChild.Show;
{FChild.FreeNotification(Self);} //non ancora implementato nell'Interface
end;
vado a richiamare ilo metodo
clGenerale.CreaForm(TForm2);