Newsgroup: it.comp.lang.delphi
Titolo: comunicazione tra moduli

sto provando una sorta di comunicazione centralizzata, con dei pulsanti
in un TFrame , svincolata dal Form contenitore.
 
quello che non risolvo e' il riconoscimento dell'evento avvenuto su 
Form3 da parte di Form4 (Form3.act_Pulsante.OnExecute := AzionePulsante)
 
la logica mi pare corretta, forse un TNotifyEvent sarebbe piu' ideoneo ?
 
grazie
 
Form1 - contenitore
Frame1 - contiene TButton
Form3 - smista , ha un TActionList e una action act_Pulsante
Form4 - Form ereditato da Form1
 
Form1 crea Frame1
Frame1 esegue le action e invia messaggio a Form3
Form4 dovrebbe intercettare l'evento scattato su Form3
 
ho fatto cosi':
 
procedure TForm1.FormCreate(Sender: TObject);
   Frame1 := TFrame1.Create(nil);
   Frame1.Parent ..
   ...
end;
 
constructor Frame1.Create(AOwner: TComponent);
begin
   inherited Create(AOwner);
   Form3 := TForm3.Create(nil);
end;
 
procedure TFrame1.act_InserisceExecute(Sender: TObject);
begin
   Form3.act_Pulsante.Execute;
end;
 
procedure TForm3.act_PulsanteExecute(Sender: TObject);
begin
  // da qui passa
end;
 
quando su Frame viene eseguita un'azione es: act_Azione1
viene eseguita l'azione act_Pulsante presente su Form3
 
   Form3.act_Pulsante.Execute;
 
fino a qui non trovo anomalie, fa quello che mi aspetto.
 
su Form4 non viene intercettato l'evento act_Pulsante
 
procedure Form4.AzionePUlsante(Sender: TObject);
begin
   // qui non passa mai
end;
 
procedure TForm4.FormCreate(Sender: TObject);
begin
   Form3 := TForm3.Create(nil);
   Form3.act_Pulsante.OnExecute := AzionePulsante;
end;

Facciamo un passo indietro: tu cosa devi fare?
 
A.
 
 

>
gestire una ToolBar (vari TButton);
in modo che il "messaggio" del tasto premuto arrivi al Form finale
(Form4 nel post iniziale) per poi poter agire di conseguenza.
 

Questa tecnica è sbagliata.
 
Devi creare un form di base con la toolbar e una tactionlist.
Nel form base, per ogni Taction crei un metodo *privato* ed un protetto dichiarato come virtual:
 
 
procedure TBaseForm.ExecuteSexAction(Sender: TObject)
begin
  DoExecuteSexAction(Sender);
end;
 
procedure TBaseForm.DoExecuteSexAction(Sender: TObject)
begin
  //
end;
 
 
Poi, via VFI erediti da form base. Nel nuovo form:
 
protected
  procedure DoExecuteSexAction(Sender: TObject); override;
 
...
 
 
procedure TMyFirdtChildForm.DoExecuteSexAction(Sender: TObject);
begin
  CallEscort;
  PrepareMoney;
  OpenDoor;
   ....
end;
 
A.    
 
 

> Questa tecnica � sbagliata.

grazie, avevo provato una via simile, ma non passava nel Form ereditato, 
ora capisco perche' "non dichiaravo override".
 

>[..]
 
noto che posso dichiarare anche procedure/funzioni diverse dal prototipo 
come DoGestione, funziona per caso o psi puo' considerare corretta ?
eviterei di effettuare sempre il controllo per sapere a quale TAction ha 
risposto.
 
   if (Sender is TComponent) then
     sNome := (Sender as TComponent).Name;
 
// dichiarazioni
 
type
   Tfrm_FormBase = class(TForm)
 
    protected
      //procedure DoGestione(Sender: TObject); override;
      procedure DoGestione(sOperazione: string); override;
 
procedure Tfrm_FormBase.act_InserisceExecute(Sender: TObject);
begin
   DoGestione('INS');
 
   //DoAvviaGestione(Sender);
end;
 
type
   Tfrm_Residenti = class(Tfrm_FormBase)
 
   protected
     procedure DoGestione(sOperazione: string); override;
     //procedure DoAvviaGestione(Sender: TObject); override;
 
procedure Tfrm_Residenti.DoGestione(sOperazione: string);
begin
   ShowMessage(sOperazione);
end;
 
procedure Tfrm_Residenti.DoAvviaGestione(Sender: TObject);
var sNome: string;
begin
   if (Sender is TComponent) then
     sNome := (Sender as TComponent).Name;
   ...
end;
 

Confusione.
 
A.

>
ti riferisci alle 2 possibili dichiarazioni ?
 
1 - procedure DoGestione(Sender: TObject); override;
2 - procedure DoGestione(sOperazione: string); override;
 
e' vero mi confondono, perche' entrambe vengono riconosciute ed 
eseguite, con la diffrenza che con la 2 posso inviare un valore;
con la 1 nel modulo di destinazione mi arriva Sender e per sapere
a quale TAction si riferisce, e non ho altro modo che questo.
 
   if (Sender is TComponent) then
     sNome := (Sender as TComponent).Name;
 
la 2 e' sbagliata tecnicamente ?

 
No. Mi riferisco a:
 
1) non hai implementato i metodi come ti avevo suggerito nella 1a risposta.
Quindi, la domanda è: PERCHE'?
 
2) non puoi fare l'override di un metodo statico ne usare 2 volte lo stesso nome di metodo salvo usare una cosa descritta nella guida in linea.
Quindi, la domanda è: HAI LETTO LA GUIDA IN LINEA?
 
3) passare una stringa come parametro per un tipo di operazione; io userei un tipo enumerato o alla peggio un costante numerica
 
4) continuo a non capire a cosa ti serve il nome del componente/action
 
A parte cio, visto che quel codice non è compilabile, comincio a credere che sei un troll.
 
A


compilare 4 righe da copia/icolla, pretendi troppo, per quanto bravo tu sia.
quanto al troll, vi e' libert� dipensiero, libro di crederlo.
 

 per quanto bravo tu sia.
 
Io non sono bravo: ho solo commesso i tuoi stessi errori molti, forse troppo, ahime', anni fa.  Questa si chiama *esperienza*. La bravura e' tutt'altra cosa.
 
 
A.

> Io non lo farei, poi vedi tu.
vero , stai indicando di usare Costante o Enumeratore a monte,
nelle execute della action
 
procedure Tfrm_TFormBase.act_InserisceExecute(Sender: TObject);
begin
   AOperationType = motInsert;
end;
 
e nella DoGestione verificher� come hai scritto di seguito.
 
se non mi sono rincoglio... del tutto ho capito, salvo il dubbio su
Gestione / DoGestione.


    //arriva sempre nel DoGestione nel form ereditato}
 
Sei prp certo di questa cosa....?
 
A.


purtroppo si, non so per quale strana coincidenza, ma arriva.
comunque seguo la via corretta, che hai avuto la pazienza di scrivere.
 
type
   TOpPulsante = (Inserisce, Varia, Annulla, Elimnina, Conferma, Uscita);
 
private
     procedure Gestione(Sender: TObject; Const AOperationType: TOpPulsante);
 
protected
     procedure DoAvviaGestione(Sender: TObject; Const AOperationType: 
TOpPulsante); virtual;
 
procedure Tfrm_FormBase.act_InserisceExecute(Sender: TObject);
begin
   Gestione(Sender, Inserisce);
end;
 
procedure Tfrm_FormEreditato.DoAvviaGestione(Sender: TObject; Const 
AOperationType: TOpPulsante);
begin
   Case AOperationType of
     Inserisce:;
     Varia:;
     Annulla:;
     Elimnina:;
     Conferma:;
     Uscita:;
   end;
 
ci credo che non capivi il senso della 
action.name
, con Eumeratore tutto 
piu' semplice e leggibile.

    end;
 
Ma su questo case poi cosa chiami??
Non avrai mica del codice del tipo:
 
 
se form fatture fai A
else se form clienti fai B
....
 
A.


> ....
no, si limita a gestire lo stato dei ClientDataSet;
si trova gia' nel form fatture / clienti /etc , tramite l'override
della procedure DoGestione.
 


un problema che mi tormenta sono le call back
 
Frm_FormBase = Class(TForm)
...
     private
       procedure Gestione(Sender: TObject; Const AOperationType: 
TOpPulsante);
 
     protected
       procedure DoGestione(Sender: TObject; Const AOperationType: 
TOpPulsante); virtual;
 
 
un menu crea FormA che prende il controllo
 
Tfrm_FormA = class(Tfrm_FormBase)
...
     private
       procedure Gestione(Sender: TObject; Const AOperationType: 
TOpPulsante);
       procedure Verifica(Sender: TObject);
 
     protected
       procedure DoGestione(Sender: TObject; Const AOperationType: 
TOpPulsante); virtual;
 
 
... ad un certo punto e' necessario aprire un'altro Form
 
     frm_FormB := TFormB.Create(self);
     ...
     frm_FormB.Show;
 
non posso fare ShowModal, perche' i controlli su FormB restano inattivi.
 
... quando viene confermata l'operazione devo tornare su questo form
     per fare altre operazioni non piu' legate a FormB.
 
se uso DoGestione esegue la verifica su FormB, ma non torna su FormA
 
se invece metto frm_FormB.act_Conferma.OnExecute := Verifica;
il controllo mi ritorna a FormA.
 
sicuramente e' un'aborto di operazione, ma non riesco a fare altrimenti.
 
 
 
Tfrm_FormB = class(Tfrm_FormBase)
...
     private
       procedure Gestione(Sender: TObject; Const AOperationType: 
TOpPulsante);
 
     protected
       procedure DoGestione(Sender: TObject; Const AOperationType: 
TOpPulsante); virtual;
 
 
procedure Tfrm_FormB.DoGestione(Sender: TObject;
   const AOperationType: TOpPulsante);
begin
   inherited;
 
   case AOperationType of
     Annulla: ;
     Conferma: begin
                 if CheckOperazioni then
                  begin
                   //scrive su db
                   Close;
                  end;
               end;
   end;
end;

> [..]
su
http://delphi.about.com/od/course/a/delphi_oop25.htm
 
http://delphi.about.com/library/weekly/code/DelphiOOchap12.pdf
 
 
ho trovato un modo per evitare il "circular reference'
 
il sistema proposto da Zarko Gajic in apparenza funziona,
altre volte ho letto di evitare questo tipo di incroci.
 
prendo la tecnica per valida e vado avanti, uso XE2
o si puo' fare in altro modo ?
 
non scrivo per il gusto di farlo o rompere, ma per cercare di migliorare.
 
FormA chiama Form2 alla pressione del pulsante Conferma
ritorna su Form1
 
/*------*/
unit unti1;
 
interface
 
uses
   Winapi.Windows, .... unit2;
 
Form1 = class(TForm)
 
   public
     { Public declarations }
     //espone Verifica che sarà usato dal callback
     procedure Verifica(Sender: TObject);
 
var Form1: TForm1
 
implementation
 
{$R *.dfm}
 
procedure TForm1.DoGestione(Sender: TObject; Const AOperationType: 
TOpPulsante);
begin
   Case AOperationType of
    Inserisce: begin
                 if not Assigned(Form2) then FormB := TForm2.create(Self);
                 Form2.Notify(Self);
               end;
 
procedure TForm1.Verifica(Sender: TObject);
begin
  ShowMessage('CalBack da Form2');
end;
 
/*----*/
unit unti2;
 
interface
 
uses
   Winapi.Windows, .... unit1;
 
Form2 = class(TForm1)
 
   protected
     FCaller: TForm1;
     procedure DoGestione(...); override;
 
   public
     { Public declarations }
     procedure Notify(Sender: TObject);
 
 
var Form2: TForm2
 
implementation
 
{$R *.dfm}
 
procedure TForm2.Notify(Sender: TObject);
begin
   FCaller := Sender as TForm1;  // remember FCaller to set up the callback
end;
 
sfrutto quanto fatto in precedenza con Enumerator
 
procedure TForm2.DoGestione(Sender: TObject;
   const AOperationType: TOpPulsante);
begin
   inherited;
 
   case AOperationType of
     Conferma: FCaller.Verifica(Self); //chiama metodo pubblico Verifica 
di Form1
   end;
end;