Italian community of Lazarus and Free Pascal

Programmazione => Generale => Topic aperto da: moessner - Aprile 20, 2022, 12:19:28 pm

Titolo: l'uso dell form
Inserito da: moessner - Aprile 20, 2022, 12:19:28 pm
Salve a tutti,

sto cercando di utilizzare 2 form.

La principale    f_cla    che contiene una listbox e
una modale     f_ins_cla   che permette di inserire un nuovo   item con   listbox.Items.add ('aaa')

Nella form principale ho inserito dopo implementation l'uso della unit realtiva all form modale.

Quando dalla form modale cerco di inserire il nuovo item mi dice :

Errore    indentifier not found   relativo alla form principale. 

Immagino che essendo nella form modale  non la conosca.

Come posso risolvere la cosa ?

Grazie per l'aiuto fina da ora.ù
moessner - Mario Piva 
Titolo: Re:l'uso dell form
Inserito da: nomorelogic - Aprile 20, 2022, 04:02:04 pm
ciao

se ci mostri anche il codice che ti da errore ci aiuti ad aiutarti ;)

da quello che leggo usi la form modale per inserire un elemento nella listbox contenuta nella form principale...
probabilmente l'errore lo ottieni perché nella unit della form modale non hai messo in uses la form principale

mettere comunque la uses di cui sopra ti darà quasi sicuramente un altro errore (referenza circolare)
nel senso che se UnitB dipende da UnitA, allora UnitA non può dipendere da UnitB

generalmente i dialog usati per inserire i dati non dovrebbero avere in uses la unit del chiamante
quindi il suggerimento è quello di predisporre un metodo nella classe della form principale che:
- istanzia la form secondaria (quella modale) per inserire i dati
- se la form modale è confermata, si prelevano i dati dalla form modale e li si processa
- si distrugge l'istanza della form modale

prova in questo modo che riduci le dipendenze ed isoli le form per l'inserimento dati

ciao
nomorelogic


Edit:
esempio (non compilato)
Codice: [Seleziona]
implementation
uses FormPerDati;

procedure TForm1.AddElementInListBox;
var x: TFormPerDati;
begin
  x:=TFormPerDati.Create(self);
  try
    x.Caption :='Inserisci qualcosa';
    if x.ShowModal = mrOk then begin
       ListBox1.Items.Add(x.Edit1.Text);
    end;
  finally
     FreeAndNil(x);
  end;

end;



Titolo: Re:l'uso dell form
Inserito da: moessner - Aprile 20, 2022, 04:42:25 pm
Grazie per l'attenzione.
Vi allego le due unit, spero che bastino.

//______________________________________________
unit u_classi;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ComCtrls,
  Buttons, LCLType ;


type

  { Tf_cla }

  Tf_cla = class(TForm)
    bIns: TBitBtn;
    bDel: TBitBtn;
    lCla: TLabel;
    lb: TListBox;
    sb: TStatusBar;
    procedure bDelClick(Sender: TObject);
    procedure bInsClick(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure lbClick(Sender: TObject);

  private

  public

  end;

var
  f_cla: Tf_cla;

implementation

uses u_ed_cla ;

{$R *.lfm}

{ Tf_cla }

procedure Tf_cla.FormShow(Sender: TObject);
begin
  sb.simpleText := 'Totale classi : ' + intToStr ( lb.count );
  bDel.Enabled := false ;
end;

procedure Tf_cla.lbClick(Sender: TObject);
begin
   if ( lb.ItemIndex <> -1 ) then
     bDel.Enabled := true
   else
     bDel.Enabled := false ;
end;


//______________________________________________
procedure Tf_cla.bInsClick(Sender: TObject);
begin
  f_ins_cla.showModal ;
  f_ins_cla.free ;
end;

procedure Tf_cla.bDelClick(Sender: TObject);
var
  i : integer ;
begin
  for i:=0 to lb.items.count-1 do
    if lb.Selected then
      if messageDlg ('Importante', 'Sei sicuro di voler cancellare la classe selezionata ?', mtConfirmation,
              [mbYes, mbNo, mbIgnore],0) = mrYes
       then
         begin


           lb.Items.Delete (i);
         //  lb.Items.beginUpdate;
          // lb.Items.endUpdate;
         end ;
//  lb.refresh ;
end;

end.
           



unit u_ed_cla;

{$mode ObjFPC}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, Buttons,
  ComCtrls ;

type

  { Tf_ins_cla }

  Tf_ins_cla = class(TForm)
    bok: TBitBtn;
    bcal: TBitBtn;
    e_cla: TLabeledEdit;
    sb: TStatusBar;
    procedure bcalClick(Sender: TObject);
    procedure bokClick(Sender: TObject);
    procedure e_claChange(Sender: TObject);
  private

  public

  end;

var
  f_ins_cla: Tf_ins_cla;

implementation

{$R *.lfm}

{ Tf_ins_cla }

procedure Tf_ins_cla.e_claChange(Sender: TObject);
begin
  if ( e_cla.text = '' ) then
    bOk.enabled := false
  else
    bOk.enabled := true ;
end;

procedure Tf_ins_cla.bcalClick(Sender: TObject);
begin

//f_ins_cla.close ;
end;

procedure Tf_ins_cla.bokClick(Sender: TObject);
begin
  //f_cla.lb.item.Add ( e_cla.text ) ;
  f_ins_cla.close ;
end;

end.



Grazie ancora
moessner - mario piva
Titolo: Re:l'uso dell form
Inserito da: nomorelogic - Aprile 20, 2022, 07:25:52 pm
prova a dichiarare in Tf_ins_cla un puntatore di tipo TListBox

Codice: [Seleziona]
unit u_ed_cla;

{$mode ObjFPC}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, Buttons,
  ComCtrls ;

type

  { Tf_ins_cla }

  Tf_ins_cla = class(TForm)
    bok: TBitBtn;
    bcal: TBitBtn;
    e_cla: TLabeledEdit;
    sb: TStatusBar;
    procedure bcalClick(Sender: TObject);
    procedure bokClick(Sender: TObject);
    procedure e_claChange(Sender: TObject);
  private

  public
     riferimento_lb: TListBox:   //   <---- aggiunta questa dichiarazione
  end;

var
  f_ins_cla: Tf_ins_cla;

implementation

{$R *.lfm}

{ Tf_ins_cla }

procedure Tf_ins_cla.e_claChange(Sender: TObject);
begin
  if ( e_cla.text = '' ) then
    bOk.enabled := false
  else
    bOk.enabled := true ;
end;

procedure Tf_ins_cla.bcalClick(Sender: TObject);
begin

//f_ins_cla.close ;
end;

procedure Tf_ins_cla.bokClick(Sender: TObject);
begin
  riferimento_lb.items.Add ( e_cla.text ) ;     // <- usi la listbox del form principale tramite il puntatore
  f_ins_cla.close ;
end;

end.

poi, nel sorgente della form principale:
Codice: [Seleziona]
procedure Tf_cla.bInsClick(Sender: TObject);
begin
  f_ins_cla.riferimento_lb := self.lb ;     //    <--- prima di lanciare la form secondaria, valorizzi il puntatore alla TListBox
  f_ins_cla.showModal ;
  f_ins_cla.free ;
end;


non ho provato il codice ma penso che sia semplice da capire come sistemare
resta comunque valido il consiglio della prima risposta ;)



Edit:
credo che se clicchi per la seconda volta sul bottone, dovresti ottenere un errore in quanto al primo passaggio distruggi l'istanza con la Free
Titolo: Re:l'uso dell form
Inserito da: DragoRosso - Aprile 21, 2022, 12:32:22 am
mettere comunque la uses di cui sopra ti darà quasi sicuramente un altro errore (referenza circolare)
nel senso che se UnitB dipende da UnitA, allora UnitA non può dipendere da UnitB

Per evitare quello che dici, basta mettere le Uses nella sezione implementation. In quel caso non vengono generati riferimenti circolari, in quanto viene usata la unit esclusivamente per riferimento in compilazione. Nella sezione Interface non possono esserci riferimenti circolari.

Se uso una unità in Interface, l'altra unità può riferirsi alla prima solo nella sezione IMPLEMENTATION.

In genere, se il progetto viene ben costruito, ben poche unità del progetto andranno nella sezione Interface di altre, in genere solo perchè queste unità definiscono ad esempio tipi nuovi comuni nell'intero progetto, oppure costanti ad uso globale.

L'unità di riferimento di una "dialog" o una "form modale" non è detto che debba essere inserita nella sezione Interface, anzi in genere non ha molto senso.

E non serve neanche "distruggere" le istanze, a meno che l'occupazione di memoria non sia un problema. L'istanza della Form2 ad esempio esiste sempre, solo che viene nascosta alla chiusura. Ad ogni chiamata non ne vengono istanziate di nuove.

L'unica accortezza è che nell'evento Show della Form2 "form modale" è utile andare ad "azzerare" tutti i campi testuali o di immissione che sono eventualmente presenti al fine di non visualizzare dati magari presenti dalla precedente chiamata non coerenti.

Unit1
Codice: [Seleziona]
unit Unit1;

{$mode objfpc}{$H+}

interface     

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls;

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    ListBox1: TListBox;
    procedure Button1Click(Sender: TObject);
  private

  public

  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

Uses Unit2;

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);
begin
  Form2.ShowModal;
end;

end.

Unit2
Codice: [Seleziona]
unit Unit2;

{$mode ObjFPC}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls;

type

  { TForm2 }

  TForm2 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private

  public

  end;

var
  Form2: TForm2;

implementation

{$R *.lfm}

Uses Unit1;

{ TForm2 }

procedure TForm2.Button1Click(Sender: TObject);
begin
  Form1.ListBox1.AddItem('Pippo', self);
  Close;
end;

end.

In genere, quello che viene fatto nella Unit2 non è proprio il massimo, è sempre bene evitare di aggiornare un componente del chiamante con chiamata diretta (anche se è consentito e lecito) quando si è in modalità modale ... possono accadere delle cose non proprio bellissime.
Questo perchè il "motore dei messaggi di Windows", chiamata anche "pompa" ... qui sono grezzo al massimo ... rimane parzialmente "inchiodata" quando si è in modalità modale (la Form2 comanda, la Form1 è in una specie di stasi) e quindi qualsiasi interazione con la Form1 potrebbe non produrre i risultati attesi.

Anche per il tramite del "puntatore" come indicato da @nomorelogic si soffre della stessa "problematica".

Sarebbe cosa buona in realtà che le due form si scambino ad esempio delle "aree" di memoria (di qualsiasi tipo: record, array, etc ..) e la Form1 con la risposta OK della Form2 esegua l'elaborazione dei dati.

Spero di essere stato esauriente.

Ciao