Question sur fonction assigned() [Résolu]

Messages postés
273
Date d'inscription
samedi 13 juin 2009
Statut
Membre
Dernière intervention
18 avril 2015
- - Dernière réponse : thierrybo
Messages postés
17
Date d'inscription
lundi 16 juin 2003
Statut
Membre
Dernière intervention
12 novembre 2010
- 9 oct. 2010 à 17:14
Bonjour à tous,
Comment savoir si une fenêtre est créée / affichées, je m'explique:
Quand je crée une fenêtre avec
      form1 := tform1.create(self) - self étant une fenêtre parent, je crée ma fenêtre bien
si dans mon code je teste assigned(form1) , j'aurai True, bien.
si dans l'évenement OnClose de Form1 il y a Action : = cafree pour détruire la fenêtre, celle-ci sera détruite, mais  la valeur du pointeur Form1 ne sera pas mise à nil, et dans ce cas, si je teste assigned(Form1) j'aurai True alors que la fenetre n'existe plus. En fait la procedure free détruit l'objet et libère l'expace mais ne met pas le pointeur à nil.

En fait, je veux enabler/disabler des actions (boutons, menus, ...)  dans une forme si d'autres forms sont présentes (Action1.enabled := True/False), mais comment être sûr que les fenetres sont présentes assigned(xxx) peut me retourner une valeur fausse.
Une solution serait de renseigner une variabl dans form1.create : form1_aff = true et dans form1.destroy : form1_aff=false, et je pourrais faire action1.enabled := not form1_aff, ... et ainsi de suite pour les autres forms, mais ce n'est pas très élégant.
L'autre solution serait de boucler sur toutes les forms de l'application, ça ne me plait pas non-plus.
Avez-vous une idée ?
Bonne journée à tous.
Afficher la suite 

14 réponses

Meilleure réponse
Messages postés
17
Date d'inscription
lundi 16 juin 2003
Statut
Membre
Dernière intervention
12 novembre 2010
1
1
Merci
Solilog nous disait le dimanche 12 juillet 2009 à 18:17:37
Bonjour,
Je dois être pinailleur,désolé.
Oui ça marche parce que tu forces Form2:= nil dans TForm2.FormClose ce que je veux éviter car "en théorie" c'est interdit de mettre un pointeur de classe à nil avant la fin des traitements (le close doit ensuite appeler free, destroy pour libérer la mem) et ça risque de ne pas ou de mal libérer la mem. Peut-être que je pinaille.


Bonjour,

désolé de remonter un vieux topic, mais comme je suis en apprentissage de l'organisation des fenêtres dans Delphi et que j'ai résolu mon problème justement en forçant Form2 à nil, j'en parle ici. Mon appli n'utilise que des fenêtres non modales, chaque form ne pouvant avoir qu'une seule instance et ne pouvant pas survivre à son parent.
Dans le livre "Mastering Delphi 7" de Marco Cantu, voici ce qu'il indique pour gérer des fenêtres non modales à instance unique où utilise justement cette technique, Mastering Delphi 7 > Part I: Foundations > Chapter 7: Working with Forms > Dialog Boxes and Other Secondary Forms, paragraphe "Creating Single-Instance Secondary Forms" :

The situation is a little more complex when you want to display only one copy of a modeless form. You have to create the form, if it is not already available, and then show it:

if not Assigned (Form2) then
Form2 : = TForm2.Create (Application);
Form2.Show;

With this code, the form is created the first time it is required and then is kept in memory, visible on the screen or hidden from view. To avoid using up memory and system resources unnecessarily, you'll want to destroy the secondary form when it is closed. You can do that by writing a handler for the OnClose event:

procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
// important: set pointer to nil!
Form2 := nil;
end;

Notice that after you destroy the form, the global Form2 variable is set to nil, which contradicts the rule set earlier for forms with multiple instances, but as this is a single-instance we are in the exact opposite case. Without this code, closing the form would destroy its object, but the Form2 variable would still refer to the original memory location.

Dire « Merci » 1

Quelques mots de remerciements seront grandement appréciés. Ajouter un commentaire

Codes Sources 198 internautes nous ont dit merci ce mois-ci

Commenter la réponse de thierrybo
Messages postés
3809
Date d'inscription
vendredi 23 juillet 2004
Statut
Modérateur
Dernière intervention
1 septembre 2019
32
0
Merci
sinon  à la place de Composant.Free
tu peux utiliser FreeAndNil(Composant)

 
@+
Cirec

<hr siz="" />
Commenter la réponse de Cirec
Messages postés
4992
Date d'inscription
dimanche 26 février 2006
Statut
Modérateur
Dernière intervention
27 mars 2018
9
0
Merci
tu peux tester la visibilité de la forme après sa présence

if Assigned(Form1) then
 if Form1.visible then

nb : pas testé

cantador
Commenter la réponse de cs_cantador
Messages postés
273
Date d'inscription
samedi 13 juin 2009
Statut
Membre
Dernière intervention
18 avril 2015
8
0
Merci
Merci à tous les deux mais ça ne m'aide pas car:
  - Cirec - je ne veux pas utiliser xxx.Free ni xxx.FreeAndNil, je reste sur un close pour les forms et le close automatique pour les modals, (tu m'as quand même appris le freeandnill que je ne connaissait pas, merci)
  - cantador - je fais ton test et button1.enabled est false malgré que Form2 soit détruite. assigned(form2) retourne true et form2.visible aussi.

procedure TForm1.Button2Click(Sender: TObject);
begin
   form2:=tForm2.create(self);
   form2.show;
   // normalement le close est dans une autre proc
   // mais pour le test c'est pareil
   // je précise qu'il y a "Action:=caFree"
   // dans form2.onclose
   form2.close;
   if assigned(form2) then
      button1.enabled := not form2.visible;
end;
En plus il est possible que ça plante, car propriétés d'un objet détruit peuvent taper n'importe où en mem ...
 
Je vais mettre une variable dans chaque unit concernées genre Form1_vis : boolean, mise à true dans onCreate et false dans onclose, c'est moche mais au moins ça marche.
Si qq'1 a mieux à me proposer ...
Tcho à tous.
solilog
Commenter la réponse de solilog
Messages postés
4200
Date d'inscription
samedi 16 octobre 2004
Statut
Modérateur
Dernière intervention
2 janvier 2019
26
0
Merci
dans la fiche parent :

type
  TFormParent = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    fFormChild : TForm;
  public
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  end;

var
  FormParent: TFormParent;

implementation

procedure TFormParent.FormCreate(Sender: TObject);
begin
  fFormChild := TForm.Create(Self);
  fFormChild.FreeNotification(Self);
end;

procedure TFormParent.Notification(AComponent: TComponent; Operation: TOperation);
begin  if (AComponent fFormChild) and (Operation OpRemove) then
    fFormChild := nil
  else
    inherited;
end;

<hr width="100%" size="2" />
Commenter la réponse de f0xi
Messages postés
4200
Date d'inscription
samedi 16 octobre 2004
Statut
Modérateur
Dernière intervention
2 janvier 2019
26
0
Merci
ou encore :

type
  TFormParent = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    fFormChilds : TList;
  public
    function RegisterFormChild(AFormChild: TForm): integer;
    function UnregisterFormChild(AFormChild: TForm): integer;
  end;

var
  FormParent: TFormParent;

implementation

{$R *.dfm}

procedure TFormParent.FormCreate(Sender: TObject);
begin
  fFormChilds := TList.Create;
end;

procedure TFormParent.FormDestroy(Sender: TObject);
var N : integer;
begin
  for N := fFormChilds.Count-1  downto 0 do
    RemoveFreeNotification(TForm(fFormChilds.Items[N]));

  fFormChilds.Free;
end;

function TFormParent.RegisterFormChild(AFormChild: TForm): integer;
begin
  result := fFormChilds.IndexOf(pointer(AFormChild));

  if result = -1 then
  begin
    result := fFormChilds.Add(pointer(AFormChild));
    FreeNotification(AFormChild);
  end;
end;

function TFormParent.UnregisterFormChild(AFormChild: TForm): integer;
begin
  result := fFormChilds.IndexOf(pointer(AFormChild));

  if result <> -1 then
  begin
    RemoveFreeNotification(AFormChild);
    fFormChilds.Delete(result);
  end;
end;

<hr width="100%" size="2" />
Commenter la réponse de f0xi
Messages postés
4200
Date d'inscription
samedi 16 octobre 2004
Statut
Modérateur
Dernière intervention
2 janvier 2019
26
0
Merci
en gros :

creation de l'objet ->
  doit notifier de sa liberation (Objet.FreeNotification(parent))

liberation de l'objet ->
  appel de notification automatique du parent avec operation OpRemove

exemple de code pour notification :
  if (AComponent objetA) and (operation OpRemove) then

  begin
    ButtonObjetA.visible := false;


    RemoveFreeNotification(fObjetAInstance);

    fObjetAInstance := nil;

  end
  else

  if (AComponent objetB) and (operation OpRemove) then

  begin

    ButtonObjetB.visible := false;


    RemoveFreeNotification(fObjetBInstance);

    fObjetBInstance := nil;
  end

  else
    inherited;

 
<hr width="100%" size="2" />
Commenter la réponse de f0xi
Messages postés
4992
Date d'inscription
dimanche 26 février 2006
Statut
Modérateur
Dernière intervention
27 mars 2018
9
0
Merci
- cantador - je fais ton test et button1.enabled est false malgré que Form2 soit détruite. assigned(form2) retourne true et form2.visible aussi.
ce n'est pas possible...
si form2 est détruite (et son pointeur à nil) et que tu testes

button1.enabled := Assigned(form2);
 
ça doit marcher

cantador
Commenter la réponse de cs_cantador
Messages postés
273
Date d'inscription
samedi 13 juin 2009
Statut
Membre
Dernière intervention
18 avril 2015
8
0
Merci
Non cantador, c'est parce que button1créer.
La réponse de .enabled := Assigned(form2) retourne toujours True si Form2 a été une fois une fois créée.
La réponse de [../auteur/F0XI/360948.aspx f0xi] est la bonne, quoique lourde pour enabled sur des actions.
Mais je ne vois rien d'autre.
Problème clos, mous.
solilog
Commenter la réponse de solilog
Messages postés
273
Date d'inscription
samedi 13 juin 2009
Statut
Membre
Dernière intervention
18 avril 2015
8
0
Merci
Non cantador, c'est parce que button .enabled := Assigned(form2) retourne toujours True si Form2 a été une fois une fois créée.

La réponse de [../auteur/F0XI/360948.aspx f0xi] est bonne, quoique lourde pour enabler des actions.
Mais je ne vois rien d'autre.
Problème clos, Tcho
solilog
Commenter la réponse de solilog
Messages postés
273
Date d'inscription
samedi 13 juin 2009
Statut
Membre
Dernière intervention
18 avril 2015
8
0
Merci
Bonjour,
Je dois être pinailleur,désolé.
Oui ça marche parce que tu forces Form2:=nil dans TForm2.FormClose ce que je veux éviter car "en théorie" c'est interdit de mettre un pointeur de classe à nil avant la fin des traitements (le close doit ensuite appeler free, destroy pour libérer la mem) et ça risque de ne pas ou de mal libérer la mem. Peut-être que je pinaille.
Il eut été plus logique que Delphi mette à nil un pointezr libéré. Y a sans doute une raison.
C'est bon, j'ai utilisé des variables que je mets à true / false dans les create/close. des Forn2. Y aussi f0xi qui m'a aussi appris un truc pas mal (quoique un peu lourd pour des bouutons).
Au problème suivant.
solilog
Commenter la réponse de solilog
Messages postés
4992
Date d'inscription
dimanche 26 février 2006
Statut
Modérateur
Dernière intervention
27 mars 2018
9
0
Merci
"en théorie" c'est interdit de mettre un pointeur de classe à nil avant la fin des traitements (le close doit ensuite appeler free, destroy pour libérer la mem) et ça risque de ne pas ou de mal libérer la mem. Peut-être que je pinaille.


Non je ne pense pas que cela pose des soucis,
mais effectivement, la mémoire est-elle libérée dans ce cas ?

f0xi peut-il nous répondre sur ce sujet ?

cantador
Commenter la réponse de cs_cantador
Messages postés
4992
Date d'inscription
dimanche 26 février 2006
Statut
Modérateur
Dernière intervention
27 mars 2018
9
0
Merci
pour répondre à Cantador non il n'y a pas de fuites ... du moins pas détectées






Normal maintenant que tu m'as collé les phobies des fuites...
J'en vois partout...

cantador
Commenter la réponse de cs_cantador
Messages postés
273
Date d'inscription
samedi 13 juin 2009
Statut
Membre
Dernière intervention
18 avril 2015
8
0
Merci
Merci Cirec,
C'est le bon endroit pour mettre Form3:=nil dans la proc notification. T'es uns star.
Tcho.
Ps: C'est quoi l'histoire des fuites ? Si c'est une vanne, laissez tomber.
Commenter la réponse de solilog