Newsgroup: it.comp.lang.delphi
Titolo: Dubbi (probabilmente da nubbio) su struttura di una applicazione

Salve a tutti.
Oramai programma per diletto in delphi da molto tempo, ma finora ho
sempre realizzato applicazioni con singola form contenete componenti
fissi.
Ora vorrei creare un' applicazione un po' piu' complessa, che abbia una
struttura del seguente tipo:
 - Form principale divisa in due
 - Parte dx: serie di pulsanti
 - Parte sx: serie di componenti
 - Alla pressione di un determinato pulsante nella parte dx, nella
parte sx deve comparire un determinato raggruppamento di controlli,
diverso per ogni pulsante premuto a sx (come se fossero "pagine"
diverse)
 - Le diverse "pagine" devono poi poter comunicare tra loro
scambiandosi dati, impostazioni e quant'altro.
Spero di essere stato chiaro, per fare un esempio credo conosciuto da
molti, una struttura simile (come tipo di layout) a quella del
programma eMule (che ha i pulsantoni in alto).
Visto che non ho mai tentato una cosa simile, vorrei sapere che tipo di
oggetti devo creare e usare per realizzare qualcosa di strutturato,
visto che le singole "pagine" sono piuttosto articolate, e il programma
promette di essere piuttosto complesso :-)
Grazie in anticipo a chi mi sapra' dare qualche indicazione!
Ciao!

 scambiandosi dati, impostazioni e quant'altro.
[...]
Una volta ho utilizzato questo sistema:
ho usato un TPageControl mettendo le proprietà TabHeight e TabWidth = 1 per
fare scomparire le linguette (senza caption) e la proprietà Style = tsButton
per rendere il controllo trasparente. In alto a sx (ma lo puoi spostare su
uno dei quattro lati impostando TabPosition) ti resta un punto pressochè
invisibile anche se fastidioso.
Poi visualizzavo la Page interessata con PageControl1.ActivePageIndex := x.
I controlli comunicano tranquillamente tra di loro nelle diverse pagine.
Oppure potresti sovraporre diversi TPanel e visualizzare quello desiderato
con Panelx.BringToFront. Il risultato è ok, ma è un pò laborioso in fase di
design accedere ai TPanel per le eventuali modifiche.
Sicuramente però ci sono dei sistemi più "puliti".
Ciao
Valter

fare scomparire le linguette (senza caption)
Basta impostare TabVisible a False.

 Basta impostare TabVisible a False.
In generale si, ma non in questo caso.
Se impostiamo il TPageControl con tutte le Page con TabVisible a False e poi
vogliamo visualizzare una pagina questa comparirà con la linguetta visibile
non dando più l'effetto cercato...

non dando più l'effetto cercato...
Non è vero, devi usare Visible per mostrare a video la tabsheet
giusta.

 diverse)
non è affatto una domanda da niubbo. E' uno dei problemi principali di chi 
deve scrivere una grossa applicazione. Sì perchè mica puoi caricare 
all'avvio tutte le 200 finestre che hai progettato.
Se cerchi con google nei gruppi (ora non posso farlo perchè sono sulla rete 
interna fasteweb) parole tipo "modularizzazione applicazione delphi" con 
aggiunta di "package" e/o "interfacce", dovresti trovare qualche 
discussione precedente. Anche sul server di Marco Cantù ci dovrebbe essere 
del materiale vecchio. C'era anche un articolo su BDN a proposito di 
package e interfacce ma non ho sottomano il link.
Posto che:
- l'approccio MDI non mi soddisfa
- non si può far apparire una form all'interno di un'altra form
- quando l'applicazione supera la soglia del "non banale" il codice diventa 
tanto ed è un'assoluta necessita suddividerlo su più unit (anche per 
mantenere un buon incapsulamento e velocizzare la partenza dell'app)
- se usi un PageControl con 30 pagine, all'avvio verranno creati e caricati 
tutti i controlli delle 30 pagine!
- il "modello eMule" piace anche a me
..io mi sono trovato bene con l'approccio per interfacce e frame creati a 
run time solo quando servono. Giusto per darti un semplice esempio pratico 
(ridotto molto all'osso, scarnificato!), dichiaro questi tipi in una unit 
condivisa:
type
  ICommon = interface
    ['{5A9F653F-B15E-40C3-B356-09E504F5A33B}']
    procedure Sync;
    procedure Activate;
    function CanDeactivate: Boolean;
    function CanClose: Boolean;
  end;
  IData = interface
    ['{0D3D802E-A592-4DF5-8625-FCFBAE09112C}']
    procedure Edit;
    procedure CancelEdit;
    procedure Append;
    procedure Next;
    procedure Prior;
  end;
//i tipi di "vista"
  TView = (
    vNone,
    vClientiElencoPrivati,
    vClientiElencoDitte,
    vClientiDettagli,
    vClientiStampa,
    vContrattiElenco,
    vContrattiDettagli,
    vContrattiStampa,
    vAltroOpzioni,
    vAltroVenditori,
    vAltroComuni,
    vAltroProvince
  );
  TCustomFrameClassArray = array[TView] of TCustomFrameClass;
  TCustomFrameArray = array[TView] of TCustomFrame;
(*************************************************************************)
(*  oggetto Global, che incorpora caratteristiche comuni dell'applicazione
(*************************************************************************)
  TGlobal = class
  private
    FOptions: TOptions;    	    	//questo implementa la persistenza 
delle opzioni dell'applicazione (tra le altre cose, memorizza la "vista" 
corrente e la mostra al prossimo avvio dell'applicazione)
    FFrames: TCustomFrameArray;    	//la struttura che contiene i 
riferimenti alle "viste"
    FAllowChangePage: Boolean;    
  public
    constructor Create;
    destructor Destroy; override;
    function CanCloseAll: Boolean;  
    property View: TView read GetView write SetView;    	 //riferimento 
alla vista corrente
    property CurrentFrame: TCustomFrame read GetCurrentFrame; //riferimento 
al frame corrente
    property AllowChangePage: Boolean read FAllowChangePage;  	//se è 
possibile cambiare "vista" (o pagina)
  end;
Naturalmente la variabile Global (pubblica a livello di applicazione) di 
tipo TGlobal va inizializzata e finalizzata:
initialization
  Global:= TGlobal.Create;
finalization
  Global.Free;
Nella sezione implementation inizializzo un'array di classi di frames, 
ciascuno corrispondente a una "vista"
  FrameClasses: TCustomFrameClassArray = (
    nil,                          //vNone
    TfraElenco,                   //vClientiElencoPrivati
    TfraElenco,                   //vClientiElencoDitte
    TfraClientiDettagli,          //vClientiDettagli
    nil,                          //vClientiStampa
    TfraElenco,                   //vContrattiElenco
    TfraContratto,                //vContrattiDettagli
    TfraContrattiStampa,          //vContrattiEtichette
    TfraOpzioni,                  //vAltroOpzioni
    TfraElenco,                   //vAltroVenditori
    TfraElenco,                   //vAltroComuni
    TfraElenco                    //vAltroProvince
  );
..che non è altro che una lista di classi (definite ciascuna nella unit di 
ciascun frame), tipo questa:
unit FrameClientiDettagli;
type
  TfraClientiDettagli = class(TFrame, ICommon, IData)
//segue tutto il codice del frame
//qui si può fare un buon lavoro per incapsulare i controlli del frame
//che anzichè essere campi published (come fa Delphi per comportamento 
//predefinito) si possono far diventare campi privati - con l'aggiunta
//di altri accorgimenti - il lavoro è piuttosto noioso
Continuiamo coi metodi di TGlobal, con questa vado a creare la "vista" - ma 
solo se non è stata già creata, altrimenti la attivo e la mostro:
//Host è dove il frame verrà mostrato, ingrandito a riempire tutto lo 
spazio
function TGlobal.FrameFactory(AView: TView; Host: TWinControl): 
TCustomFrame;
var
  FrameClass: TCustomFrameClass;
begin
  Assert(Assigned(Host));
  if Assigned(FFrames[AView]) then
    Result:= FFrames[AView]
  else    //bisogna creare il frame x la prima volta
    begin
      FrameClass:= FrameClasses[AView];
      Assert(Assigned(FrameClass)); //assicuriamoci che la classe sia 
assegnata
      Result:= FrameClass.Create(Host);
    { nota che assegniamo sempre un nome al componente creato per evitare 
conflitti
      nel caso ne vengano create più istanze }
      Result.Name:= GetNameOf(AView);
      Result.Parent:= Host;
      Result.Align:= alClient;
      FFrames[AView]:= Result;
    end;
end;
Questo implementa la scrittura della proprietà View e imposta la vista 
corrente (solo se è permesso il cambio pagina, cioè il frame precedente 
dice che CanDeactivate è possibile - questo serve per es. se si lavora su 
database e ci sono dei dati che devono essere convalidati prima di passare 
da una vista all'altra):
procedure TGlobal.SetView(const Value: TView);
var
  f: TCustomFrame;
  CommonIntf: ICommon;
begin
  FAllowChangePage:= True;
  if Assigned(CurrentFrame) and CurrentFrame.GetInterface(ICommon, 
CommonIntf) then
    FAllowChangePage:= CommonIntf.CanDeactivate;
  if FAllowChangePage then
  begin
    FOptions.View:= Value;  
//se il frame non esiste, prima lo creiamo - in ogni caso lo mostriamo
//riempiendo tutto un TPanel della form principale - lo "spazio di lavoro"
//dell'applicazione
    f:= FrameFactory(Value, fmMain.pnlMain); 
    f.BringToFront;
    if f.GetInterface(ICommon, CommonIntf) then
    begin
      CommonIntf.Activate;
      CommonIntf.Sync;
    end;
  end;
end;
In questo modo, il codice della form principale si riduce davvero a qualche 
centinaio di righe. Per attivare le viste si possono usare i modi più 
disparati, da una TToolBar (stile eMule) a una TJvOutlookBar (componenti 
della JVCL) alle actions, un TActionManager ecc ecc
Per finire..
Con questa vado a controllare, quando l'utente preme la X della mainform, 
che tutti i frame mi diano il permesso di chiudere:
function TGlobal.CanCloseAll: Boolean;
var
  v: TView;
  CommonIntf: ICommon;
begin
  Result:= True;
  for v:= Low(TView) to High(TView) do
    if Assigned(FFrames[v]) and FFrames[v].GetInterface(ICommon, 
CommonIntf) then
      if not CommonIntf.CanClose then
      begin
        Result:= False;
        CommonIntf.Activate;
        Break;
      end
end;
Implementazione della proprietà in lettura di CurrentFrame:
function TGlobal.GetCurrentFrame: TCustomFrame;
begin
  Result:= FFrames[FOptions.View]
end;
..e di View:
function TGlobal.GetView: TView;
begin
  Result:= FOptions.View;
end;
Per ultimo, ricaviamo il "nome" della vista col sistema "stringa da tipo 
enumerato":
//richiede che in uses ci sia TypInfo (Delphi 7)
function GetNameOf(AView: TView): string;
var
  P: PTypeInfo;
begin
  P:= TypeInfo(TView);
  Result:= GetEnumName(P, Ord(AView))
end;
Questo era solo uno spunto, ci sono almeno due direzioni in cui si possono 
fare delle estensioni/sviluppi:
- incapsulare i frame in dei run-time package da caricare volta per volta 
col dynamic loading (questo comporta risolvere il problema di "esportare 
interfacce da un package caricato dinamicamente" - che non ho ancora 
affrontato anche se ho letto che si può fare);
- implementare un pattern Observer/Observable specie quando ci sono 
applicazioni le cui viste dipendono le une dalle altre.
-- 
Mauro Falzari 
 
  La teoria è quando si sa tutto ma non funziona niente. 
  La pratica è quando funziona tutto ma non si sa il perchè. 
  In ogni caso si finisce sempre a coniugare la teoria con la pratica: 
  non funziona niente e non si sa il perchè. 
   (Albert Einstein)

per la persistenza delle opzioni ti posto questo che uso comunemente in 
tutte le mie applicazioni.
unit ApplicationOptions;
(*************************************************************************)
(*  Mauro Falzari - 2004/2006
(*************************************************************************)
{   
- Classe TBaseAppOptions:
  serve come base per derivare delle classi, il cui scopo
  è quello di salvare e leggere le opzioni dell'applicazione, al posto dei 
vecchi file INI.
  Il meccanismo usato è la persistenza degli oggetti con businness objects 
su file XML,
  può esser fatto lo streaming di qualunque tipo di dato (anche tipi 
enumerati e tipi set - ma non per esempio di TCollection o TList).
  La classe base implementa la lettura di FileName dal file XML,
  al momento della creazione dell'oggetto e il salvataggio al momento della 
distruzione.
  USO:
  derivare da TBaseAppOptions e implementare come proprietà published
  read/write o read only ogni opzione che si vuole rendere persistente
  (è sufficiente implementarla con dei campi privati).
  Dopo il Create, tutti i campi published della classe derivata saranno 
riempiti
  automaticamente. Se il file XML non viene trovato al momento del Create,
  i campi avranno le proprietà di default (Boolean=False, Set=[], 
String='',
  Integer=0, Enumerated=il primo tipo della lista e così via).
- Classe TAppOptions:
  implementa un contatore che serve a tener traccia del numero di volte che
  è stata avviata l'app.
  Registra anche la data e ora della prima apertura del programma e data e 
ora
  del suo ultimo utilizzo. Salva e ripristina la posizione della form.
  Per esempio nell'evento OnShow della form principale si usa:
    FOptions.RestoreWindowRect(fmMain);
  ..e nell'OnDestroy:
    FOptions.StoreWindowRect(fmMain); }
interface
uses
  BCBase, Forms;
type
  TBaseAppOptions = class (TBCWeakBO)
  private
    FFileName: string;
  protected
    procedure LoadDefaultValues; virtual;   //fare l'override di questa per 
impostare valori di default
  public
  //FileName dev'essere un nome completo di path;
  //se FileName è vuoto, assegna di default il nome del file 
dell'applicazione cambiato in estensione XML;
    constructor Create(const FileName: string = ''); reintroduce; virtual;
  //crea il file nella sottocartella SubFolder, relativa rispetto al path 
dell'applicazione;
  //se FileName è vuoto, assegna di default il nome del file 
dell'applicazione cambiato in estensione XML
    constructor CreateInSubFolder(const SubFolder: string; FileName: string 
= '');
    destructor Destroy; override;
    procedure Load;   //ricarica i dati da filename
    procedure Save;    //salva i dati su filename
    property FileName: string read FFileName;   //read only
  end;
  TAppOptions = class(TBaseAppOptions)
  private
    FSessionCounter: Cardinal;
    FFirstOpening: TDateTime;
    FLastClosing: TDateTime;
    FWindowLeft: Integer;
    FWindowTop: Integer;
    FWindowWidth: Integer;
    FWindowHeight: Integer;
    FLastOpening: TDateTime;
    FSessionOpening: TDateTime;
    FPreviousUsageTime: TDateTime;
    FWindowState: TWindowState;
    function GetSessionMeanUsageTime: TDateTime;
    function GetSessionTime: TDateTime;
    function GetTotalUsageTime: TDateTime;
  public
    constructor Create(const FileName: string = ''); override;
    destructor Destroy; override;
    procedure ClearStats;
    procedure StoreWindowRect(AForm: TForm); virtual;
  //nota: se la finestra era iconizzata o massimizzata non memorizziamo le 
dimensioni
    procedure RestoreWindowRect(AForm: TForm); virtual;
  //nota: se la finestra era iconizzata, la ripristiniamo normale
    property SessionOpening: TDateTime read FSessionOpening;
  { il tempo d'uso totale diviso per il numero delle sessioni }
    property SessionMeanUsageTime: TDateTime read GetSessionMeanUsageTime;
  { la durata della sessione in corso, nel momento in cui viene letta la 
proprietà }
    property SessionTime: TDateTime read GetSessionTime;
  { la durata totale di utilizzo, incluso la durata della sessione 
corrente, nel momento in cui viene
    letta la proprietà}
    property TotalUsageTime: TDateTime read GetTotalUsageTime;
  published      { devono essere obbligatoriamente tutte published 
read/write }
    property SessionCounter: Cardinal read FSessionCounter write 
FSessionCounter;
    property FirstOpening: TDateTime read FFirstOpening write 
FFirstOpening;
    property LastClosing: TDateTime read FLastClosing write FLastClosing;
    property LastOpening: TDateTime read FLastOpening write FLastOpening;
  { la durata totale di tutte le sessioni precedenti }
    property PreviousUsageTime: TDateTime read FPreviousUsageTime write 
FPreviousUsageTime;
    property WindowLeft: Integer read FWindowLeft write FWindowLeft;
    property WindowTop: Integer read FWindowTop write FWindowTop;
    property WindowHeight: Integer read FWindowHeight write FWindowHeight;
    property WindowWidth: Integer read FWindowWidth write FWindowWidth;
    property WindowState: TWindowState read FWindowState write 
FWindowState;
  end;
//restituisce il nome completo del file dell'applicazione cambiato di 
estensione 'XML'
function GetXML_FileNameOfApplication: string;
implementation
uses
  SysUtils, MfUtils;
//restituisce il nome completo del file dell'applicazione cambiato di 
estensione 'XML'
function GetXML_FileNameOfApplication: string;
begin
  Result:= ChangeFileExt(Application.ExeName, '.xml');
end;
{ TBaseAppOptions }
constructor TBaseAppOptions.Create(const FileName: string);
begin
  inherited Create;
  if IsEmpty(FileName) then
    FFileName:= GetXML_FileNameOfApplication
  else
    FFileName:= FileName;
  Load;
end;
constructor TBaseAppOptions.CreateInSubFolder(const SubFolder: string;
  FileName: string);
begin
  if IsEmpty(FileName) then
    Create(ForceSubDirOfApp(SubFolder) + 
ExtractFileName(GetXML_FileNameOfApplication))
  else
    Create(ForceSubDirOfApp(SubFolder) + FileName)
end;
destructor TBaseAppOptions.Destroy;
begin
  Save;
  inherited Destroy;
end;
procedure TBaseAppOptions.Load;
begin
  if FileExists(FileName) then
    LoadFromXMLFile(FileName)
  else
    LoadDefaultValues;
end;
procedure TBaseAppOptions.LoadDefaultValues;
begin
end;
procedure TBaseAppOptions.Save;
begin
  if Length(Trim(FFileName)) > 0 then
    SaveToXMLFile(FFileName);
end;
{ TAppOptions }
procedure TAppOptions.ClearStats;
begin
  FSessionCounter:= 0;
  FFirstOpening:= Now;
  FPreviousUsageTime:= 0;
end;
constructor TAppOptions.Create(const FileName: string);
begin
  inherited Create(FileName);
  FSessionOpening:= Now;
  if FSessionCounter = 0 then
    FFirstOpening:= Now;
  Inc(FSessionCounter);
end;
destructor TAppOptions.Destroy;
begin
  FLastClosing:= Now;
  FLastOpening:= FSessionOpening;
  FPreviousUsageTime:= FPreviousUsageTime + (Now - FSessionOpening);
  inherited Destroy;
end;
function TAppOptions.GetSessionMeanUsageTime: TDateTime;
begin
  Result:= FPreviousUsageTime / FSessionCounter;
end;
function TAppOptions.GetSessionTime: TDateTime;
begin
  Result:= Now - FSessionOpening;
end;
function TAppOptions.GetTotalUsageTime: TDateTime;
begin
  Result:= FPreviousUsageTime + GetSessionTime;
end;
procedure TAppOptions.RestoreWindowRect(AForm: TForm);
begin
//esegue il restore della finestra solo se non è la prima sessione di 
utilizzo del programma
  if FSessionCounter > 1 then
  begin
    if FWindowWidth = 0 then
      FWindowWidth:= 100;
    if FWindowHeight = 0 then
      FWindowHeight:= 100;
    if FWindowState <> wsMinimized then
      AForm.WindowState:= FWindowState;
    if FWindowState = wsNormal then
      AForm.SetBounds(FWindowLeft, FWindowTop, FWindowWidth, 
FWindowHeight);
  end
end;
procedure TAppOptions.StoreWindowRect(AForm: TForm);
begin
  if AForm.WindowState = wsNormal then
    with AForm do
    begin
      FWindowLeft:= Left;
      FWindowTop:= Top;
      FWindowWidth:= Width;
      FWindowHeight:= Height;
    end;
  FWindowState:= AForm.WindowState;
end;
end.
**********************************************************
Esempio d'uso:
**********************************************************
uses ApplicationOptions;
type
  TOptions = class(TAppOptions)
  private
    FDatabaseFileName: string;
    FPageIndex: Integer;
    FView: TView;
    FOutlookBarWidth: Integer;
    FClientiPrivatiRowID: Integer;
    FNavigatorFrameHeight: Integer;
    FFontSize: Integer;
    FNavigatorGlyphSize: TGlyphSize;
    FClientiDitteRowID: Integer;
  protected
    procedure LoadDefaultValues; override;
  published
    property OutlookBarWidth: Integer read FOutlookBarWidth write 
FOutlookBarWidth;
    property PageIndex: Integer read FPageIndex write FPageIndex;
    property DatabaseFileName: string read FDatabaseFileName write 
FDatabaseFileName;
    property View: TView read FView write FView;
    property ClientiPrivatiRowID: Integer read FClientiPrivatiRowID write 
FClientiPrivatiRowID;
    property ClientiDitteRowID: Integer read FClientiDitteRowID write 
FClientiDitteRowID;
    property NavigatorFrameHeight: Integer read FNavigatorFrameHeight write 
FNavigatorFrameHeight;
    property NavigatorGlyphSize: TGlyphSize read FNavigatorGlyphSize write 
FNavigatorGlyphSize;
    property FontSize: Integer read FFontSize write FFontSize;
  end;
**********************************************************
BCBase.pas fa parte del pacchetto EOS che avevo trovato (2004) su 
SourceForge.net. Rilasciato sotto licenza GNU. Segue l'header della unit:
{**************************************************************************
****}
{   EOS - Enterprise Open Source Accounting Project                            
}
{   Copyright (C) 2002 "The EOS Group Developers"                              
}
{   All rights reserved.                                                       
}
{                                                                              
}
{                                                                              
}
{   see COPYING.TXT for copyright and licence details                          
}
{                                                                              
}
{**************************************************************************
****}


 tutti i controlli delle 30 pagine!
brrrrrrrrrrrr non ci voglio neanche pansare :)
Acqua 

 per un grosso progetto che usa anche runtime packages, interfacce
una form come controllo figlio di un'altra form (Parent)?
-- 
Mauro Falzari 
 
  La teoria č quando si sa tutto ma non funziona niente. 
  La pratica č quando funziona tutto ma non si sa il perchč. 
  In ogni caso si finisce sempre a coniugare la teoria con la pratica: 
  non funziona niente e non si sa il perchč. 
   (Albert Einstein)

 per un grosso progetto che usa anche runtime packages, interfacce
hai incontrato problemi con l'esportazione di interfacce da runtime 
packages caricati dinamicamente?
-- 
Mauro Falzari 
 
  La teoria č quando si sa tutto ma non funziona niente. 
  La pratica č quando funziona tutto ma non si sa il perchč. 
  In ogni caso si finisce sempre a coniugare la teoria con la pratica: 
  non funziona niente e non si sa il perchč. 
   (Albert Einstein)

 una form come controllo figlio di un'altra form (Parent)?
Ho fatto copia-incolla delle singoli parti, non dovrei aver commesso errori:
  TTBBaseForm = class(TForm)
  private
    FAsChild: Boolean;
  protected
    procedure CreateParams(var Params: TCreateParams); override;
    procedure Loaded; override;
  private
    FTempParent: TWinControl;
  public
    constructor Create(AOwner: TComponent); overload; override;
    constructor Create(AOwner: TComponent; AParent: TWinControl); 
reintroduce; overload;
  end;
constructor TTBBaseForm.Create(AOwner: TComponent);
begin
  FAsChild := False;
  inherited Create(AOwner);
end;
constructor TTBBaseForm.Create(AOwner: TComponent; AParent: TWinControl);
begin
  FAsChild := True;
  FTempParent := AParent;
  inherited Create(AOwner);
  FParamList := TTBParamsList.Create;
  SetDefaultValues;
end;
procedure TTBBaseForm.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  if FAsChild then
    Params.Style := Params.Style or WS_CHILD;
end;
procedure TTBBaseForm.Loaded;
begin
  inherited;
  if FAsChild then
  begin
    align := alClient;
    BorderStyle := bsNone;
    BorderIcons := [];
    Parent := FTempParent;
  end;
end;
Acqua 

 packages caricati dinamicamente?
No :|
Acqua 

> - non si può far apparire una form all'interno di un'altra form
e perche no ? anzi, questo è l'aproccio consigliato da cantu per non 
dover usare i frame...
Ciauz..
ZioGian

 giusta.
Hai ragione :-)



non ho letto l'approccio di Marco ma se tu mi potessi dare qualche 
consiglio in merito, te ne sarei davvero grato.
la proprietà Parent delle form non mi pare che funzioni, almeno con D7...


 end;
bello, ma non ho TTBParamsList :-)


 struttura del seguente tipo [...]
Non so se il mio intervento è effettivamente utile, visto che Mauro ti 
ha già fornito un esempio che è molto più completo, in ogni caso ti 
segnalo anche la mia soluzione, presente sia sul mio sito personale (in 
firma) che sul sito Delphi & Dintorni (
http://tinyurl.com/zhz8q
) basata 
sui Frame e compilabile sia su Win32 che su .NET Framework, illustrata 
anche dal punto di vista teorico, per creare un'applicazione strutturata 
"a pagine" (come Outlook, insomma).
Ciao,
   Marco.
-- 
MARCO BREVEGLIERI
  (
http://www.marco.breveglieri.name
)

togliendo
  //FParamList := TTBParamsList.Create;
  //SetDefaultValues;
sono in effetti riuscito a far girare il tuo codice, ma non riesco a far 
apparire una form secondaria (Form2) dentro un Panel della form principale:
implementation //codice della mainform
{$R *.dfm}
uses Unit2;
var
  Form2: TForm2;
procedure TForm1.FormShow(Sender: TObject);
begin
  Form2 := TForm2.Create(Panel1);
end;
..sarà di sicuro perchè mancano quelle due righe!
-- 
Mauro Falzari 
 
  La teoria è quando si sa tutto ma non funziona niente. 
  La pratica è quando funziona tutto ma non si sa il perchè. 
  In ogni caso si finisce sempre a coniugare la teoria con la pratica: 
  non funziona niente e non si sa il perchè. 
   (Albert Einstein)

 end;
Come puoi vedere dal codice esiste un overload del Create. Devi usare il 
Create che ha in ingresso sia L'Owner che il Parent.
....
public
    constructor Create(AOwner: TComponent); overload; override;
    constructor Create(AOwner: TComponent; AParent: TWinControl);
....
Cosě facendo la form la puoi usare come ti pare e piace... :)
Se la vuoi usare all'interno di un TPanel devi usare il secondo costruttore 
altrimenti usi il primo come hai sempre fatto.
quindi la versione corretta, per innestare una form all'interno di Panel1, č 
Form2 := TForm2.Create(AOwner, Panel1);
Acqua

 Panel1, è Form2 := TForm2.Create(AOwner, Panel1);
in effetti avevo provato anche in quel modo ma non mi era mica riuscito!
O mi sono rinco...nito io dietro a una cosa così semplice, cosa molto 
probabile.
Riporto il codice:
//form principale, con un TPanel
unit Unit1;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, 
Forms,
  Dialogs, ExtCtrls;
type
  TForm1 = class(TForm)
    Panel1: TPanel;
    procedure FormShow(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
var
  Form1: TForm1;
implementation
{$R *.dfm}
uses Unit2;
var
  Form2: TForm2;
procedure TForm1.FormShow(Sender: TObject);
begin
  Form2 := TForm2.Create(Panel1, Panel1);
//nè funzia così:
  Form2 := TForm2.Create(Self, Panel1);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
  Form2.Free;
end;
end.
///////////////////////////////////////////////
// form secondaria, con una label e un button
unit Unit2;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, 
Forms,
  Dialogs, StdCtrls;
type
  TTBBaseForm = class(TForm)
  private
    FAsChild: Boolean;
  protected
    procedure CreateParams(var Params: TCreateParams); override;
    procedure Loaded; override;
  private
    FTempParent: TWinControl;
  public
    constructor Create(AOwner: TComponent); overload; override;
    constructor Create(AOwner: TComponent; AParent: TWinControl); 
reintroduce; overload;
  end;
  TForm2 = class(TTBBaseForm)
    Label1: TLabel;
    Button1: TButton;
  end;
implementation
{$R *.dfm}
constructor TTBBaseForm.Create(AOwner: TComponent);
begin
  FAsChild := False;
  inherited Create(AOwner);
end;
constructor TTBBaseForm.Create(AOwner: TComponent; AParent: TWinControl);
begin
  FAsChild := True;
  FTempParent := AParent;
  inherited Create(AOwner);
  //FParamList := TTBParamsList.Create;
  //SetDefaultValues;
end;
procedure TTBBaseForm.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  if FAsChild then
    Params.Style := Params.Style or WS_CHILD;
end;
procedure TTBBaseForm.Loaded;
begin
  inherited;
  if FAsChild then
  begin
    align := alClient;
    BorderStyle := bsNone;
    BorderIcons := [];
    Parent := FTempParent;
  end;
end;
end.
//non mi dà errori, ma nel panel non vedo la Form2


 //non mi dà errori, ma nel panel non vedo la Form2
Dopo aver creato la form... usi il metodo Show?
Acqua 

 Dopo aver creato la form... usi il metodo Show?
ah ah ah...grande! 
mi ero completamente dimenticato dello show. 
questi sono gli effetti su un uomo costretto a forza in ufficio a 
programmare in VB(A)!!
grazie di tutto..


 programmare in VB(A)!!
AAAAAAAAAAAAAAAAarrrrrrrrrrrrrrrGGGGGGGGGGGGG!!!! :D:D:D
Acqua ;) 

 grazie di tutto..
Quasi rinunciavo ad uscire per fare un'applicazione e spedirti il tutto per 
mail.
Ormai scarica la posta. ;)
Acqua 

 Ormai scarica la posta. ;)
ma sei matto?
e il 
mauro_...@despammed.com
 non va più da molto tempo ormai (despammed 
lo hanno tirato giù).
casomai scrivimi a 
mauroorua...@fastwebnet.it
 (togli mauro allo 
specchio)


 ma sei matto?
Matto? Spero ancora di no :), ma fino a un paio d'anni fa stavo serate 
intere a postare ...
Per quanto riguarda il "ranzare" ....mmmm....
Baciamo le mani,
Acqua