Newsgroup: it.comp.lang.delphi
Titolo: Form all'interno di un panel

Ispirato da qualcosa letto da qualche parte, ho sperimentato una struttura 
dell'applicazione (di una parte di essa) dove un form ospita un treeView che 
fa da menu e un pannello a fianco dove, in funzione della scelta effettuata 
nel menu, viene visualizzato un form o l'altro.
Concettualmente è molto simile all' "Applicazione a pagine" di Marco B. Solo 
che lui usa dei frames.
Io le applicazioni le avevo già funzionanti, solo che ognuna apriva una 
diversa finestra, mentre con questa tecnica mi pare ci sia meno confusione 
per l'utente, perchè per lui c'è un'unica finestra che ospita l'applicazione 
da lui scelta nel menu, che è il panel all'interno del quale il form viene 
mostrato.
Non ho scelto la soluzione di Marco B.perchè non volevo pensare a come 
trasformare dei forms in frames, etc. e mi sembrava che così non ci fosse 
niente da fare. In effetti, qualche problemino c'è lo stesso,.
Ma vorrei sapere se qualcun altro ha sperimentato questa cosa, se trovate 
che ha un senso o no, sia dal punto di vista utente che della 
programmazione. Vorrei qualche commento insomma. Aspetto.. 
 

 programmazione. Vorrei qualche commento insomma. Aspetto..
 
A cosa ti riferisci di preciso? Alla scelta di aprire Form usando un TreeView?
Alla fine io non ho capito bene come è fatta la tua soluzione di preciso. :|
 
Ciao,
  Marco.
 
-- 
MARCO BREVEGLIERI
#Home: 
http://www.marco.breveglieri.name
 
#Blog: 
http://www.compilaquindiva.net
 

 programmazione. Vorrei qualche commento insomma. Aspetto..
 
Non so se ho capito bene, ma stai cercando di aprire le applicazioni 
in modo che la loro form venga inserita all'interno di 
un'altra applicazione "principale" che e' poi quella con l'albero
che ti consente poi di attivare una o l'altra applicazione?
 
Tempo fa ho sperimentato qualcosa del genere: si riesce a combinare
qualcosa. Si tratta di lanciare l'eseguibile esterno con il solito
CreateProcess, poi bisogna identificare la form principale del processo 
(e li e' la parte piu' difficile)  e poi "riparentarla" sulla tua
form principale. 
Un problema che ho incontrato e non sono riuscito a risolvere e' che le
applicazioni che lanci rimangono indipendenti, quindi mantengono
il focus e quando vuoi cliccare su una parte edlla tua form principale
(nel mio caso era una toolbar, nel tuo caso potrebbe essere l'albero)
serviva un click per spostare il focus da un'applicazione all'altra
e poi un secondo click per cliccare effettivamente sulla toolbar.
 
ciao
Giacomo

 form principale. 
 
Scusate: a cosa serve? 
 
A.
 

 Solo che lui usa dei frames.
 
Chiedo scusa, ma dove si può trovare qualcosa in più relativamente all' 
"Applicazione a pagine" ?
 
Grazie
 
 
 
 
 
-- 
Mai mettersi a discutere con un idiota:
- prima ti porta al suo livello e poi ti batte con l'esperienza;
- chi ascolta potrebbe non capire la differenza.
 

 "Applicazione a pagine" ?
 
Bisogna cercare nei thread un po' vecchi... molto vecchi (penso 2005), altrimenti ripesco l'esempio quando sono a casa e lo rimetto sul mio blog a buon rendere. :)


 Bisogna cercare nei thread un po' vecchi... molto vecchi (penso 2005), altrimenti ripesco l'esempio quando sono a casa e lo rimetto sul mio blog a buon rendere. :)
 
Se potessi dedicarci qualche minuto te ne sarei grato, intanto 
sguinzaglio google groups ;-)
 
Grazie.



Nel nostro caso l'idea era di dare al cliente un'interfaccia piu' 
omogenea, in modo che fosse indifferente se una certa funzionalita'
era implementata nell'eseguibile principale o in un exe esterno,
alla fine lui vede sempre una form dentro ad un tab.
 
ciao
Giacomo

Qualcuno mi ha chiesto a cosa serve. Per me serve a facilitare la vita 
all'utente, un pò come tentava di fare il concetto dell'applicazione MDI, 
che però non mi piaceva.
Grossolanamente, la cosa mi funziona. Tento di spiegarvi cosa ho fatto:
Il funzionamento per l’utente è il seguente:
 
C'è un Main che gestisce le scelte che si fanno nel menu (Treeview) che 
consistono nel lancio di un programma o l'altro. All’avvio viene 
visualizzato per default, nel panel, uno dei programmi.
Il clic su un nodo del TreeView ha come effetto che il form visualizzato 
viene sostituito da quello scelto con il clic.
Da ciascun form si esce solo facendo una diversa scelta nel menu. Non 
vengono utilizzati i bottoni di uscita forniti dai vari programmi, che anzi 
devono essere disabilitati (vedi 1), ma il passaggio ad un altro programma 
non deve avvenire senza aver utilizzato le procedure di chiusura previste 
dal programma da cui si  esce (vedi 2).
 
// 1 - Libera la istanza del form creato in precedenza (quindi l’unico 
Assigned) prima di creare il nuovo form che va lanciato
  if Assigned(FormGestConti) then
  begin
      FormGestConti.BtnCloseClick(FormGestConti);  // (2)
      FreeAndNil(FormGestConti);
  end;
// 2 - Carica la pagina corrispondente al nodo selezionato (Lancia il 
programma)
if Node.Text = 'Estratto Conto' then
begin
   FormEstratti := TFormEstratti.Create(Self);
   DisplayFormInsideContainer(FormEstratti);
end;
//  Come si inserisce il Form all’interno del Panel
procedure TFormContiMain.DisplayFormInsideContainer(aForm: TForm);
begin
    aForm.Parent:= PagePanel;
   aForm.BorderStyle:= bsNone;
   aForm.Align:= alClient;
   aForm.Show;
end;
 
Non sono un bravo programmatore e quindi sono sicuro che si può fare di 
molto meglio.. ma questa è l'idea.
Cosa ne dite ? 
 

 Bisogna cercare nei thread un po' vecchi... molto vecchi (penso 2005), altrimenti ripesco l'esempio quando sono a casa e lo rimetto sul mio blog a buon rendere. :)
 
Ho cercato (forse male) ma non ho trovato niente.
Non voglio sembrarti scortese, ma se potessi - quando hai tempo - 
ritrovare la tua documentazione...
 
Grazie molte.


 ritrovare la tua documentazione...
 
Purtroppo non ho molto tempo al momento. :|
Appena riesco aggiornerò il thread.
 
Ciao!


 Appena riesco aggiornerò il thread.
 
Nessuna fretta, l'importante è che non lo dimentichi ;-)


Tempo fa avevo preso spunto dalla soluzione proposta da Marco, che ringrazio ancora. L'accrocchio (perchè non sono un bravo programmatore) funzionava come ci si aspetta, tuttavia sono sicuro si possa migliorare. Approfitto quindi per condividere la soluzione.
 
Alla base c'è un Frame-modello nel quale sono definite le funzionalità standard e da cui derivano i Frame veri e propri che costituiscono l'applicazione a pagine.
Questo il codice:
 
****************************************
unit FraPaginaModello;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ComCtrls, ToolWin, PngImageList, ImgList, ExtCtrls;
 
type
  TPaginaModello = class(TFrame)
    tlb: TToolBar;
    tlbSalva: TToolButton;
  private
    { Private declarations }
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;
 
  TPaginaFrame = class of TPaginaModello;
 
 
implementation
 
 
Uses
  FormA, Modulo1, FraPaginaHome;
 
constructor TPaginaModello.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  // codice di apertura
end;
 
 
destructor TPaginaModello.Destroy;
begin
  // codice di chiusura
  inherited;
end; 
 
 
{$R *.dfm}
 
end.
****************************************
 
 
 
Qui un Frame ereditato (una pagina vera e propria dell'applicazione):
 
****************************************
 
unit FraPaginaProtocolli;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, FraPaginaModello, ComCtrls, ToolWin, ExtCtrls, Grids, StdCtrls;
 
type
  TPaginaProtocolli = class(TPaginaModello)
    panMobile: TPanel;
    tlbChiudi: TToolButton;
    tlbAggiungi: TToolButton;
    tlbModifica: TToolButton;
    tlbElimina: TToolButton;
    gridProtocollo: TDBGrid;
    procedure tlbChiudiClick(Sender: TObject);
    procedure tlbFiltriClick(Sender: TObject);
    procedure tlbAggiungiClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    constructor Create(AOwner: Tcomponent); override;
  end;
 
var
  PaginaProtocolli: TPaginaProtocolli;
 
implementation
 
uses FormA, Modulo1, FraPaginaProtocollo, FormAutorizzazioniTipi;
 
{$R *.dfm}
 
constructor TPaginaProtocolli.Create(AOwner: TComponent);
begin
  inherited;
  mdl.sdsProtocollo.Open;
  panMobile.Height := 15;
end;
 
// questo il codice contenuto nella FormA per aprire una pagina
 
procedure TPaginaProtocolli.tlbAggiungiClick(Sender: TObject);
begin
  inherited;
  frmA.ApriPagina(TPaginaProtocollo, 'NuovoProtocollo', 'Nuovo Protocollo');
end;
 
// questo il codice contenuto nella FormA per chiudere una pagina
procedure TPaginaProtocolli.tlbChiudiClick(Sender: TObject);
begin
  inherited;
  frmA.ChiudiPagina;
end;
 
end.
 
****************************************
 
 
 
Nella FormA ho messo:
- una toolbar anzichè una tree (per avere più spazio)
- un componente rkSmartTabs che potete trovare qui 
http://rmklever.com/
 
  che in pratica crea delle linguette con pulsante di chiusura
  molto personalizzabili
- un PageControl (chiamato ContenitorePagine)
 
Questo il codice saliente della FormA:
 
****************************************
 
implementation
 
{$R *.dfm}
 
Uses
  Modulo1, FraPaginaHome, FraPaginaDitte, FraPaginaProtocolli;
 
 
procedure TfrmA.ApriPagina(ATipoPagina: TPaginaFrame;
  ANomeScheda: string; ATitoloTab: string);
var
  z: Integer;
  NewTab: TTabSheet;
  NewPan: TPanel;
  xPagina: TPaginaModello;
 
begin
  // verifico che la pagina chiamata non sia gia aperta
  for z := 0 to ContenitorePagine.PageCount - 1 do begin
    if ContenitorePagine.Pages[z].Name = ANomeScheda then begin
      // se gia aperta la attivo
      ContenitorePagine.ActivePageIndex := z;
      // ed attivo anche la relativa rkTab
      rkTab.ActiveTab := z;
      exit;
    end;
  end;
 
  // creo la nuova pagina
  NewTab := TTabSheet.Create(ContenitorePagine);
  With NewTab do Begin
    PageControl := ContenitorePagine;
    Name := ANomeScheda;
    TabVisible := False;
  End;
 
  // Aggiungo una rkTab alla Form principale
  // e le assegno il nome passato alla procedura
  frmA.rkTab.AddTab(ANomeScheda);
  // poi le assegno il titolo passato alla procedura
  frmA.rkTab.Tabs[frmA.rkTab.ActiveTab] := '';
  frmA.rkTab.Tabs[frmA.rkTab.ActiveTab] := ATitoloTab;
 
  NewPan := TPanel.Create(NewTab);
  With NewPan do Begin
    Parent := NewTab;
    Name := 'Pannello' + ANomeScheda;
    Align := alClient;
    Caption := '';
  End;
 
  xPagina := ATipoPagina.Create(nil);
  xPagina.Name := 'Pagina' + ANomeScheda;
  try
    // Dispone la pagina all'interno del pannello contenitore
    xPagina.Parent := NewPan;
    // Forza la pagina ad occupare lo spazio disponibile
    xPagina.Align := alClient;
    ContenitorePagine.ActivePage := NewTab;
  except
    raise;
  end;
end;
 
procedure TfrmA.ChiudiPagina;
var
  i: Integer;
begin
  // chiudo la Pagina attiva
    i := frmA.rkTab.ActiveTab;
    frmA.ContenitorePagine.Pages[i].Free;
    frmA.rkTab.DeleteTab(i);
    frmA.ContenitorePagine.ActivePageIndex := frmA.rkTab.ActiveTab;
end;
 
****************************************
 
 
Resto a disposizione per eventuali chiarimenti.
 
---
Giovanni Fantuzzi
 

xche hai le uses in implementation? 
 
A.

Onestamente non c'è motivo.
In passato mi trovavo a combattere con i riferimenti circolari, così ho preso l'abitudine di lasciare mettere a Delphi i suoi rif. nella interface, i miei li mettevo nella implementation.. e buona notte.
--
Giovanni
 

Segnalo un sistema alternativo per mettere delle Form all'interno di un PageControl (o di un panel), decisamente meno caotico di quello da me descritto sopra.
 
risultato:
http://codegearguru.com/video/033/FormDocking2.html
 
 
prima parte della lezione:
http://codegearguru.com/video/032/FormDocking.html
 
 
Giovanni