Newsgroup: it.comp.lang.delphi
Titolo: passare TForm come parametro

passo come parametro un Form ereditato ad una procedure
nel parametro AForm passato, non posso accedere ai controlli propri del 
form frm_Accesso
come posso passare anche questi ?
 
^^^^
 
unit frm_Accesso
...
Tfrm_Accesso = class(Tfrm_Appoggio)
 
... var frm_ Accesso: Tfrm_Accesso;
 
 
plnToolBar - TPanel
ActionList - TActionList
 
sono definiti nel form Tfrm_Appoggio
 
nel form frm_Accesso, posso accedere a pnlToolbar e impostare la 
proprieta' "Visible"
 
^^^^^^^^^^^
uses ..unt_Funzioni;
 
begin
  clComuni := TPartiComuni.create;
  ....
  //passo il form alla procedure EspandiForm
  //
  clComuni.EspandiForm(frm_Accesso; ...);
 
end;
 
unit Funzioni;
 
uses Winapi.Windows, System.SysUtils, Variants, Dialogs, Vcl.Forms, 
StdCtrls, Buttons,
      ComObj, Grids, TypInfo, ComCtrls,
      Vcl.Controls, System.Classes, Vcl.Graphics;
 
type TPartiComuni = class
 
   public EspandiForm(AForm: TForm; ...);
...
 
procedure EspandiForm(AForm: TForm);
begin
   //AForm non puo' accedere ai controlli del Form ricevuto
 
   //queste assegnazioni vanno bene
   //AForm risulta istanziato
   iPosFormX := AForm.Top;
   iPosFormY := AForm.Left;
   iAltForm := AForm.Height;
   iLarForm := AForm.Width;
 
   //ad es: questa non posso assegnarla
   //
   AForm.pnlToolBar.Visible := false;
end;

Mescolare OOP e strutturato non va tanto bene.
Crei una tua classe form dalla quale tramite WFI erediterai i form che ti servono.
La tua classe form avra' un metodo virtuale DoExpand.
Quindi:OGNI FORM SAPRA' COSA DEVE FARE AL MOMENTO DELL'EXPAND.
 
 
type
  TMYForm = class(TForm)
  protected
     funtion DoExpand: integer; virtual;
  public
     funtion Expand: integer;
  end; 
 
implementation
 
function TMyForm.DoExpand: integer;
begin
  Result := 0;
end;
 
 
 
function TMyForm.Expand: integer;
begin
  Result := DoExpand;
end;
 
 
-----------
 
 
type
  TMYSexForm = class(TMyForm)
  protected
     funtion DoExpand: integer; override;
  public
  end; 
 
implementation
 
function TMySexForm.DoExpand: integer;
begin
  Result := inHerited DOExpand;
 
  Self.toolbar.width := 100;
  Self.somebutton.Left := 10;
  ...
end;
 
end.

>
grazie, provo la tua soluzione OOP, nel frattempo sono riuscito cosi':
 
  for i := 0 to AForm.ComponentCount do
     begin
       if AForm.Components[i].Name = 'pnlToolBar' then
         begin
           TForm(AForm.Components[i]).Visible := false;
           TForm(AForm.Components[i]).Align := alTop;
           TForm(AForm.Components[i]).Hint := 'Tutte le operazioni';
           break;
         end;
     end;
 
//aggiorna messaggi Hint della ActionList
//frm_Accesso.ActionList1.UpdateAction(act_Espandi);
 
ora vorrei inviare un UpdateAction(<nomeazione>)
aAzione: TAction;
 
     for i := 0 to AForm.ComponentCount do
       begin
        if AForm.Components[i].Name = 'act_Espandi' then
          begin
            aAzione := AForm.Components[i].Name;
 
//[DCC Error] unt_FunzioniComuni.pas(534): E2010 Incompatible types: 
//'TAction' and 'TComponentName'
 
            TForm(AForm.Components[x]).UpdateAction(aAzione);
            break;
          end;
       end;

 come posso passare anche questi ?
[...]
 
Se passi un form, e questo ha dei metodi, proprieta' etc, ovviamente
"passi" anche questi. Mi pare che il tuo problema sia come accedere a
metodi e proprieta' etc (sotto etc stanno ovviamente controlli,
componenti e quant'altro).
 
Le soluzioni al *quesito* sono molteplici:
a) brutta e sporca: ridefinisci la procedura per accettare non un
tform, ma alla classe che ti interessa. Ovviamente, dovrai avere una
procedura di gestione per ogni tipo di form. Pessimo.
b) passi alla procedura anche la classe, oltre all'istanza. In questo
modo dentro la procedura puoi fare un cast esplicito. Questo però non
risolve alcunche', perche' devi comunque sapere che la form di quella
classe ha un controllo che si chiama in quel modo. Pessimo come a)
c) introspezione: una form, dato che ha come progenitore TPersistent,
si porta dietro informazioni sulle proprie proprità. La procedura
ispeziona la form ricevuta e miracolosamente riesce a capire che deve
farne. Il problema è la parte "miracolosamente".
 
Ciò detto, imho il tuo quesito (e il codice che hai postato) sono mal
posti. Se vuoi che le tue form abbiano un "comportamento" (come
Espandi) comune scrivi un'interfaccia ed implementala dove ti serve, o
più semplicemente scrivi una tExpandableForm che pubblica un metodo
Espandi, all'interno del quale ciascuna istanza delle sottoclassi
sappia cosa fare con i propri controlli.
 
Un'ultima cosa; dalla unit della form istanzi un TPartiComuni,
definito in un'altra unit, che deve sapere come gestire la form. Se
TPartiComuni e' una classe helper, puo' (e imo dovrebbe) risiedere
nella stessa unit della form. Se invece fosse proprio di utilita'
generale, riconsidererei le cose per ridurre il livello di
accoppiamento.
 
Saluti
Paolo Arosio

 if AForm.Components[i].Name = 'pnlToolBar' then
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 
Il problema e' questo if.
Oggi hai pnlToolBar, domani avrai altri 10 componenti su form1, altri 20 su form2 e cosi via, il tutto senza contare che fai un ciclo.
 
La soluzione che ti ho suggerito io evita codice sparpagliato chissa' dove che DEVE sapere come e' fatto ogni singolo form o quanto meno conoscere i nomi dei componenti. Senza contare che eviti un ciclo sulla collection Components.
 
A.


      end;
[...cut...]
 
Che ovviamente non hai testato per un form che *non* abbia un
componente chiamato pnlToolBar, altrimenti avresti avuto un
EOutOfRange (o come si chiama): XxxxxCount è il numero di Xxxxx; se
parti a contare da 0, devi iterare fino a XxxxxCount -1 per scorrere
tutti i componenti.
 
Saluti
Paolo Arosio

>> grazie, provo la tua soluzione OOP, nel frattempo sono riuscito cosi':
sto applicando la tua soluzione
nel DoExpand, assegno cio' che serve, il form non si sposta, la Toolbar 
resta non visible, la hint di act_Espandi non cambia valore.
 
riscontro che il Self si riferisce a frm_Accesso e non a frm_Invio.
 
 
Tfrm_InvioDati = class(Tfrm_Appoggio)
Tfrm_Invio = class(Tfrm_Appoggio)
...
 
procedure Tfrm_Accesso.EdUfficioButtonClick(Sender: TObject);
begin
   inherited;
   bEspanso := false;
 
   frm_Invio := Tfrm_Invio.Create(Self);
   //il padre di frm_Invio e' frm_Accesso
   frm_Invio.Parent := Self;
   ...
   frm_Invio.act_Espandi.OnExecute := EspandiForm;
   frm_Invio.Show;
end;
 
procedure Tfrm_Accesso.EspandiForm(Sender: TObject);
begin
   DoExpand;
end;
 
function Tfrm_Accesso.DoExpand: integer;
begin
   Result := inHerited DOExpand;
 
   Self.pnlToolBar.Visible := true;
   Self.Top := 0;
   Self.Left := 0;
 
   //ridimensiona frm_Accesso non frm_Invio
   Self.Height := 200;
 
   Self.act_Espandi.Hint := 'aaaa';
   Self.UpdateAction(act_Espandi);
end;
 

 end;
 
==> Questo deve diventare Tfrm_Invio.DoExpand
 
 
ciao
Giacomo

Il concetto di "self" e' spiegato nella guida in linea.
 
type
  TMYForm = class(TForm)
    procedure act_EspandiExecute(sender: TOBject);
  private
     funtion Expand: integer;
  protected
     funtion DoExpand: integer; virtual;
  public
 
  end;
 
implementation
 
 
procedure TMyForm.act_EspandiExecute(sender: TOBject);
begin
  expand;
end;
 
function TMyForm.Expand: integer;
begin
  Result := DoExpand;
end; 
 
 
function TMyForm.DoExpand: integer;
begin
  Result := 0;
end; 
 
 
 
procedure Tfrm_Accesso.EdUfficioButtonClick(Sender: TObject);
begin
   inherited;
   bEspanso := false;
 
   // BUG STRATOSFERICO.
   // SE L'UTENTE FA CLICK 100 VOLTE CREI 100 FORM 
 
   IF (NOT ASSIGNED(frm_Invio)) THEN
   BEGIN
     frm_Invio := Tfrm_Invio.Create(Self);
     //il padre di frm_Invio e' frm_Accesso
     frm_Invio.Parent := Self;
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
     // A   COSA SERVE QUESTA COSA? 
     ...
     // frm_Invio.act_Espandi.OnExecute := EspandiForm;
     // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  
     // NON TI SERVE PIU'
   END;
 
   frm_Invio.Show;
end; 
 
A.
 
 
 
 
 

>     IF (NOT ASSIGNED(frm_Invio)) THEN
e' vero, ma di norma setto il pulsante come enabled := false;
comunque molto meglio "if not assigned()", cosi' se dimentico di settare 
il pulsante, non crea n form.
 
ho applicato i suggerimenti al mio caso, mettendo DoExpand nel form di 
Base (frm_Appoggio) che tutti gli altri ereditano via VFI.
 
una cosa che non ho capito e' perche' servano 2 funzioni
DoExpand ed Expand.
 
 
 
 
 
 
 
 

 DoExpand ed Expand.
 
suggerisci almeno un'alternativa e ne parliamo.
 
A.
 

 DoExpand ed Expand.
 
E' un pattern abbastanza comune: Expand e' un metodo pubblico
che tutti possono chiamare, al suo interno Expand fa delle
operazioni ad uso interno e poi chiama DoExpand che e' un
metodo protected in modo che le form che ereditano possano
poi personalizzare questo metodo per fare cose
specifiche delle singole form che non puoi ovviamente mettere
nella form base.
 
ciao
Giacomo
 

Il 30/08/2012 11:42, Giacomo Degli Esposti ha scritto:

quindi se devo abilitare/rendere visibili dei controlli di un Form
devo creare nel form stesso sia Expand che DoExpand;
 
pnlDati e' accessibile dal form frm_Invio (deriva da frm_Appoggio)
frm_Appoggio non sa che pnlDati esiste, le operazioni su pnlDati vanno 
fatte su frm_Invio.
quello che ho fatto e' la strada corretta ?
 
ciao Alessandro
 
procedure Tfrm_Invio.act_EspandiExecute(Sender: TObject);
begin
   Expand;      //esegue operazioni locali
   inherited;   //esegue operazione comuni nel from padre
end;
 
function Tfrm_Invio.DoExpand: boolean;
begin
   //bespanso :variabile locale
   //
   if not bEspanso then
     begin
       bEspanso := true;
       pnlDati.Visible := true;
     end
    else
     begin
       bEspanso := false;
       pnlDati.Visible := false;
     end;
end;
 
function Tfrm_Accesso.Expand: boolean;
begin
   Result := DoExpand;
end;
 
//questa la parte comune che tutti chiamano, ho variato da integer a 
//boolean per verificare il flag bEspanso
 
function Tfrm_Appoggio.DoExpand: boolean;
begin
   if not bEspanso then
     begin
       bEspanso := true;
       Self.pnlToolBar.Visible := true;
       Self.StatusBar.Visible := true;
       Self.Top := 0;
       Self.Left := 0;
       Self.Height := iAltEspanso;
       Self.Width := iLarEspanso;
       Self.act_Espandi.Hint := 'Torna a Selezione';
     end
    else
     begin
       bEspanso := false;
       Self.pnlToolBar.Visible := true;
       Self.StatusBar.Visible := false;
       Self.Top := iTopOrg;
       Self.Left := iLeftOrg;
       Self.Height := iAltFormOrg;
       Self.Width := iLarFormOrg;
       Self.act_Espandi.Hint := 'Tutte le Operazioni';
     end;
   Self.UpdateAction(act_Espandi);
   Result := bEspanso;
end;
 
function Tfrm_Appoggio.Expand: boolean;
begin
   Result := DoExpand;
end;
 
procedure Tfrm_Appoggio.act_EspandiExecute(Sender: TObject);
begin
   Expand;
end;
 

 quello che ho fatto e' la strada corretta ?
 
Direi di si.
 
ciao
Giacomo

 devo creare nel form stesso sia Expand che DoExpand;
 
No. 
Dovresti pero' leggere un po per capire la differenza tra un metodo Virtuale ed uno statico.
 
  //bespanso :variabile locale
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  VARIABILE O ATTRIBUTO?
 
Se lo hai dichiarato nella sezione VAR del form *spostalo nella sezione private e gli metti una "F" davanti per indicare che e' un membro della classe e non una variabile globale (puah!)*
 
 
function Tfrm_Invio.DoExpand: boolean;
begin
  inherited;
  pnlDati.Visible := Not pnlDati.Visible;
  bEspanso := pnlDati.Visible;
end;
 
A.

> A.
 
ho fatto come dici;
pnlDati risulta visible, quando bEspanso = false
e ancora visible, anche quando bEspanso = true
 
pnlDati risulta visible = false, ma continuo a vederlo;
non ci sono elemetei di disturbo nel Form , es. OnFormResize
 
 
Tfrm_Invio =   Tfrm_Uffici = class(Tfrm_Appoggio)
     pnlDati: TPanel;
 
   private
     { Private declarations }
     FbEspanso: boolean;
 
   protected
     function DoExpand: boolean; override;
 
  end;
 
function Tfrm_Invio.DoExpand: boolean;
begin
   inherited;
   pnlDati.Visible := Not pnlDati.Visible;
   bEspanso := pnlDati.Visible;
   //provato anche con Repaint e Application.ProcessMessages
end;
 

>>
 
ignorate il precedente post, e' tutto regolare;
semplicemente non era pnlDati
ma pnlToolBar !!!
 
function Tfrm_Uffici.DoExpand: boolean;
begin
   inherited;
   pnlDati.Visible := Not pnlDati.Visible;
   pnlToolBar.Visible := pnlDati.Visible;
   FbEspanso := pnlDati.Visible;
 
   Result := FbEspanso;
end;
 
scusate e grazie dell'aiuto.