Newsgroup: it.comp.lang.delphi
Titolo: Applicazione a Pagine

Parecchio tempo fa, per sviluppare un modulo di una mia applicazione,  ho 
adottato un'idea di Marco Breveglieri. In sostanza, c'č un main dove un 
treeView consente la selezione di pagine create dinamicamente e mostrate in 
un panel a fianco del treeView.
Le varie pagine sono delle frames. Senza addentrarmi nella tecnica, questo 
modulo adesso va modificato e in una delle pagine (che praticamente č come 
un form pur essendo una frame, dove c'č tutta la logica elaborativa), ho 
bisogno di effettuare una operazione (scrittura di dati su dataset) solo al 
momento in cui la pagina viene abbandonata (passando ad altra pagina o 
chiudendo il main).
Il problema č che non so come accorgermi di questo evento. Nel main mi 
accorgo che voglio passare ad altra pagina o chiudere, ma a quel punto sono 
nel main e non piů nella pagina.
Non so se mi sono spiegato  o se, senza conoscere questa tecnica, qualcuno č 
in grado di suggerire una possibile soluzione (se c'č). Aspetto fiducioso.. 
 
 
---
Questa e-mail č stata controllata per individuare virus con Avast antivirus.
https://www.avast.com/antivirus
 
 

 in grado di suggerire una possibile soluzione (se c'č). Aspetto fiducioso.. 
 
Nel main, quando selezioni una pagina, puoi eseguire il publish di un evento per tutti i subscribers interessati (i controller dei frame). Il controller di un determinato frame riceve l'evento e agisce di conseguenza. I tuoi controller possono implementare un'interfaccia INotifiable con un metodo notify(Data: Object) per esempio. L'operazione di subscribe da parte dei controller puo` essere una semplice registrazione in una lista da parte del main. Il main manterra` una lista di INotifiable e, ad ogni cambio pagina, notifichera` a tutti gli INotifiable.
 
In pseudocodice:
 
INotifiable: 
   procedure notify(ANewFrame: TFrame);
 
Main: 
   procedure registerNotifiable(ANotifiable: INotifiable) 
       myNotifiables.add(ANotifiable);
 
   procedure changeFrame(ANewFrame: TFrame)
       for (notifiable : myNotifiable) 
           notifiable.notify(ANewFrame);
 
Controller <- INotifiable:
   procedure notify(ANewFrame: TFrame)
       if (ANewFrame <> myControlledFrame)
          doYourOperation();           
 

 dinamicamente e mostrate in un panel a fianco del treeView.
 
Quando tu dici "dinamicamente" cosa intendi ??
Per esempio quando selezioni un item del treeview crei il frame e quando ne 
selezioni un'altro elimini il frame ?
Se questo e' il caso, prima di distruggere il frame fai la tua procedura di 
salvataggio.
Se questo non e' il caso (ovvero crei al momento il frame e cambiando gli 
item del treeview rendi visibile o meno il frame) la soluzione non e' poi 
molto diversa.
Nel senso che controlli la distruzione del tuo frame, se e' stato creato 
(perche' magari non hai fatto quella selezione) alla chiusura della form il 
frame viene per forza distrutto, in quella sede salvi le modifiche sul DB 
(nel frame destroy).
 
Se invece, altra possibilita', nella struttura ad albero il frame in oggetto 
puo' contenere delle informazioni visibili nelle altre "pagine", in modo 
piu' maccheronico (sia che l'albero lo popoli a design o run time) crei un 
"puntatore" che ti ricorda dove quel frame e' collegato alla struttura 
dell'albero (per esempio se questo frame e' aperto quando selezioni l'item 
(o sub item) 10 dell'albero) quando selezioni la voce (item 10) visualizzi 
il frame, quando ti sposti e selezioni un altro item (item<>10) controlli se 
il frame esiste ( If Assigned(MyFrame) ) e se esiste controlli se qualcosa 
e' stato fatto ( if MyFrame.changed ) e se e' stato fatto lo salvi sul DB.
 
Maccheronico, artigianale ma funzionale.
 
Ciao
 
Daniele
 

Il sistema è così congegnato: Il main form, ad ogni scelta nel treeview, 
richiama la proc che crea la frame (e che ti esemplifico così):
procedure TFormMain.LoadPage(APageClass: TPageFrameClass);
begin
  if (APageClass = TNewBudgetFrame) then
     FCurrentPage := APageClass.Create(Self,PathDB,cAnnoCon)
  ..................
end;
 
Nella unit della frame c'è il constructor (vedi esempio sotto), poi tutte le 
logiche operative in tante procedure.
constructor TNewBudgetFrame.Create(AOwner: TComponent; aDBName,aAnnoCon: 
string);
begin
  inherited Create(Owner);
  ..........
  FaiQualcosa;
end;
 
Se l'utente durante la fase di elaborazione abbandona la frame cliccando su 
un altro item della treeview, io devo intercettarlo per mettere in salvo il 
lavoro. Tra l'altro, la frame eredita da una frame di base, in cui risiede 
il destroy. Nè la frame di base, nè il main, conoscono nulla della frame 
sulla quale si è lavorato.
Ma che scemo, non basta prevedere la destroy direttamente nella 
NewBudgetFrame (in override) ed eseguire qui la finalizzazione del lavoro ? 
Mi viene in mente adesso. Non andrebbe bene?
 
 
---
Questa e-mail è stata controllata per individuare virus con Avast antivirus.
https://www.avast.com/antivirus
 
 

Nel main, quando selezioni una pagina, puoi eseguire il publish di un evento 
per tutti i subscribers interessati (i controller dei frame). Il controller 
di un determinato frame riceve l'evento e agisce di conseguenza. I tuoi 
controller possono implementare un'interfaccia INotifiable con un metodo 
notify(Data: Object) per esempio. L'operazione di subscribe da parte dei 
controller puo` essere una semplice registrazione in una lista da parte del 
main. Il main manterra` una lista di INotifiable e, ad ogni cambio pagina, 
notifichera` a tutti gli INotifiable.
In pseudocodice:
INotifiable:
   procedure notify(ANewFrame: TFrame);
Main:
   procedure registerNotifiable(ANotifiable: INotifiable)
       myNotifiables.add(ANotifiable);
   procedure changeFrame(ANewFrame: TFrame)
       for (notifiable : myNotifiable)
           notifiable.notify(ANewFrame);
Controller <- INotifiable:
   procedure notify(ANewFrame: TFrame)
       if (ANewFrame <> myControlledFrame)
          doYourOperation();
---
Volevo ringraziarti perchè apprezzo il tuo tentativo di aiuto, ma non saprei 
come implementare quanto descrivi. Sono troppo indietro.. 
 
 
---
Questa e-mail è stata controllata per individuare virus con Avast antivirus.
https://www.avast.com/antivirus
 
 

 lavoro. 
 
Devi fare come ti ho detto, e non dirmi che sei "troppo indietro", perche` se capisci il concetto di classe e metodi, e` tutto quello che ti serve.
 
Se proprio non sai lavorare con le interfacce, costruisci una classe astratta TNotifiable con un metodo notify(), da cui farai ereditare una class TFrameController a cui passi, nel costruttore, il frame da costruire. Questa classe si registrera` presso il main form. Il main form la infilera` in una lista di TNotifiable. Ogni volta che selezioni un nuovo frame, mandera` un messaggio a tutti i controller dei frame registrati, loopando sulla lista e invocando il metodo notify() su di essi. Si`, puoi usare il Destroy nel tuo caso specifico, ma il metodo che ti ho suggerito e` piu` utile perche` ti consente di ascoltare qualunque evento, non necessariamente per operazioni da eseguire alla distruzione del frame.

 come implementare quanto descrivi. Sono troppo indietro.. 
 
Non c'e` niente di complicato. Questo e` scritto per Lazarus, ma con poche modifiche lo adatti a Delphi:
 
unit Unit1;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls,
  StdCtrls, Contnrs;
 
type
  TNotifiable = class abstract
  public
     procedure Notify(Sender: TObject); virtual; abstract;
  end;
 
  { TLabelController }
 
  TLabelController = class(TNotifiable)
  private
    FLabel: TLabel;                         
  public
    constructor Create(TheOwnerAndParent: TWinControl; ALabelY, ALabelX: Integer);
    procedure Notify(Sender: TObject); override;
  end;
 
  { TForm1 }
 
  TForm1 = class(TForm)
    ListBox1: TListBox;
    procedure FormCreate(Sender: TObject);
    procedure ListBox1SelectionChange(Sender: TObject; User: boolean);
  private
    { private declarations }
    FNotifiables: TObjectList;
  public
    { public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.lfm}
 
{ TLabelController }
 
constructor TLabelController.Create(TheOwnerAndParent: TWinControl; ALabelY,
  ALabelX: Integer);
begin
  FLabel := TLabel.Create(TheOwnerAndParent);
  with FLabel do begin
    Parent := TheOwnerAndParent;
    Top := ALabelY;
    Left := ALabelX;
    Caption := 'Hello, I am a controlled label';
  end;
end;
 
procedure TLabelController.Notify(Sender: TObject);
begin
  FLabel.Caption := 'Something''s changed! ' + DateTimeToStr(Now);
end;
 
{ TForm1 }
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  ListBox1.Items.Add('paperino');
  ListBox1.Items.Add('topolino');
  ListBox1.Items.Add('pippo');
  FNotifiables := TObjectList.Create(true);
  FNotifiables.Add(TLabelController.Create(Self, ListBox1.Top, ListBox1.Left+ListBox1.Width+10));
  FNotifiables.Add(TLabelController.Create(Self, ListBox1.Top+50, ListBox1.Left+ListBox1.Width+10));
  FNotifiables.Add(TLabelController.Create(Self, ListBox1.Top+100, ListBox1.Left+ListBox1.Width+10));
end;
 
procedure TForm1.ListBox1SelectionChange(Sender: TObject; User: boolean);
var I: Integer;
begin
  for I := 0 to FNotifiables.Count-1 do
  begin
    TNotifiable(FNotifiables.Items[I]).Notify(Sender);
  end;
end;
 
end.
 

Grazie davvero dell'esempio, perchè così mi appare meno astruso. Ma già 
questo statement non lo capisco:
{$mode objfpc}{$H+}
 
Il resto adesso me lo studio e ci provo ...


Intanto, seguendo un'idea che mi aveva sollecitato il commento di Daniele, 
ho provato a creare una procedure destroy nella frame e ci ho messo il 
richiamo ad una routine che finalizza il lavoro fatto dall'utente scrivendo 
un dataset.
Ho provato ad eseguire e chiudendo il form che crea la frame, ho visto che 
il Destroy della frame è l'ultima cosa che viene eseguita, per cui la 
routine viene eseguita, ma ho perso il riferimento al dataset che è un 
componente del form..
Insomma, la soluzione sembrava semplice... 


Ma cosa c'entra? Quella è una direttiva di lazarus che puoi benissimo ignorare. Concentrati sul succo del codice. Mai possibile che non comprendi del codice così semplice? Come puoi lavorare IN Delphi? La soluzione che ti ho suggerito è la più efficace per quel che vuoi fare.

 Insomma, la soluzione sembrava semplice...
Non e' poi cosi' complicata ......
 
Ciao
 
Daniele
 

"4ndre4"  ha scritto nel messaggio 
news:7af5de3f-baaf-40b6...@googlegroups.com...
Se proprio non sai lavorare con le interfacce, costruisci una classe 
astratta TNotifiable con un metodo notify(), da cui farai ereditare una 
class TFrameController a cui passi, nel costruttore, il frame da costruire. 
Questa classe si registrera` presso il main form. Il main form la infilera` 
in una lista di TNotifiable. Ogni volta che selezioni un nuovo frame, 
mandera` un messaggio a tutti i controller dei frame registrati, loopando 
sulla lista e invocando il metodo notify() su di essi. Si`, puoi usare il 
Destroy nel tuo caso specifico, ma il metodo che ti ho suggerito e` piu` 
utile perche` ti consente di ascoltare qualunque evento, non necessariamente 
per operazioni da eseguire alla distruzione del frame.
...
Non ho avuto molto tempo in questi giorni, ma adesso sto cercando di 
implementare il tuo suggerimento ... 
