Question sur fonction assigned() [Résolu]

solilog 273 Messages postés samedi 13 juin 2009Date d'inscription 18 avril 2015 Dernière intervention - 11 juil. 2009 à 08:47 - Dernière réponse : thierrybo 17 Messages postés lundi 16 juin 2003Date d'inscription 12 novembre 2010 Dernière intervention
- 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 

Votre réponse

16 réponses

Cirec 4221 Messages postés vendredi 23 juillet 2004Date d'inscription 11 mai 2018 Dernière intervention - 13 juil. 2009 à 14:31
+3
Utile
non non non !!!

il n'est pas utile d'appeler "FreeNotification" Delphi le fait tout seul sauf cas exceptionnel:

tiré de l'aide de Delphi:
"
<link rel= "stylesheet" type="text/css" href="../common/bdshelp.css" /><link rel="stylesheet" href="ms-help://Hx/HxRuntime/HxLink.css" /><link rel="stylesheet" href="../common/DTUE.css" /><xml></xml><mshelp:toctitle title="FreeNotification Méthode"></mshelp:toctitle><mshelp:rltitle title="TComponent.FreeNotification Méthode"></mshelp:rltitle><mshelp:keyword index="A" term="Classes.TComponent.FreeNotification_Win32_Delphi"></mshelp:keyword><mshelp:keyword index="K" term="Classes.TComponent.FreeNotification Méthode"></mshelp:keyword><mshelp:keyword index="F" term="Classes.TComponent.FreeNotification"></mshelp:keyword><mshelp:keyword index="A" term="Classes.TComponent.FreeNotification"></mshelp:keyword><mshelp:keyword index="K" term="TComponent.FreeNotification Méthode"></mshelp:keyword><mshelp:keyword index="F" term="TComponent.FreeNotification"></mshelp:keyword><mshelp:keyword index="A" term="TComponent.FreeNotification"></mshelp:keyword><mshelp:keyword index="K" term="FreeNotification Méthode"></mshelp:keyword><mshelp:keyword index="F" term="FreeNotification"></mshelp:keyword><mshelp:keyword index="A" term="FreeNotification"></mshelp:keyword><mshelp:attr name="TopicType" value="kbRef"></mshelp:attr><mshelp:attr name="Product" value="bdsDelphi"></mshelp:attr><mshelp:attr name="ProductVers" value="D10"></mshelp:attr><mshelp:attr name="Locale" value="kbFrench"></mshelp:attr><mshelp:attr name="DevLang" value="Delphi"></mshelp:attr><mshelp:attr name="DevLangVers" value="Delphi"></mshelp:attr><mshelp:attr name="DocSet" value="bds"></mshelp:attr><mshelp:attr name="DocSet" value="bds_Win32"></mshelp:attr>Description
<descrlong id="descrLong" xmlns="">Utilisez
FreeNotification pour recenser AComponent comme un composant qui doit
être notifié quand le composant est sur le point d'être détruit. Il est
seulement nécessaire de recenser les composants de cette manière quand
ils résident dans une fiche différente ou ont un propriétaire
différent. Par exemple, si AComponent se trouve dans une autre fiche et
utilise le composant pour implémenter une propriété, il doit appeler
FreeNotification afin d'appeler sa méthode Notification à la
destruction du composant.Pour les composants
de même propriétaire, la méthode Notification est automatiquement
appelée quand une application libère explicitement le composant. Cette
notification n'est pas envoyée quand les composants sont libérés
implicitement, suite à la libération préalable du propriétaire.</descrlong>"

<hr siz="" />La preuve par l'exemple:

<hr siz="" />

{-------------------------------------------------------------------------}
{ Last modified                                                           }
{    Date : 13/07/2009 13:50:15                                           }
{  Author : Cirec http://www.delphifr.com/auteur/CIREC/311214.aspx        }
{-------------------------------------------------------------------------}
unit  Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1  = class(TForm)
    Button2: TButton;
    procedure Button2Click(Sender: TObject);
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  private

  public

  end;

var
  Form1: TForm1;

implementation

uses Unit3;

{$R *.dfm}

procedure TForm1.Button2Click(Sender: TObject);
begin
 if assigned(Form3) then
   Exit;
  Form3 :=  TForm3.create(Self);
   with  Form3 do
  try
    showModal;
  finally
  end;
end;

procedure TForm1.Notification(AComponent: TComponent;

  Operation: TOperation);

begin

  if (aComponent  = Form3) and (Operation =  opRemove) then

  begin

    ShowMessage('j''avais raison');

    Form3 :=  nil ;

  end;

  inherited;

end;


end.

<hr siz ="" />La Fenêtre de teste:

<hr siz= "" />
unit  Unit3;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

  TForm3  = class(TForm)
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
     { Déclarations privées }
  public
    { Déclarations publiques }
  end;

var
  Form3: TForm3;

implementation

{$R *.dfm}

procedure TForm3.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action : =  caFree;
end ;

end.

<hr siz = "" />Et pour finir le DPR:

<hr siz= "" />
program  Project1;

uses
  Forms,
  Unit1 in 'Unit1.pas'  {Form1} ;

{$R *.res}

begin
  //ReportMemoryLeaksOnShutDown : = True;
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

<hr siz="" />Fin:

<hr siz="" />
pour répondre à Cantador non il n'y a pas de fuites ... du moins pas détectées

mais en procédant comme montré dans l'exemple il n'y en a pas et tout fonctionne très bien sans bidouille

 
@+
Cirec

<hr siz="" />
Cette réponse vous a-t-elle aidé ?  
Commenter la réponse de Cirec
thierrybo 17 Messages postés lundi 16 juin 2003Date d'inscription 12 novembre 2010 Dernière intervention - 9 oct. 2010 à 17:14
+1
Utile
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.
Commenter la réponse de thierrybo
Cirec 4221 Messages postés vendredi 23 juillet 2004Date d'inscription 11 mai 2018 Dernière intervention - 11 juil. 2009 à 12:10
0
Utile
sinon  à la place de Composant.Free
tu peux utiliser FreeAndNil(Composant)

 
@+
Cirec

<hr siz="" />
Commenter la réponse de Cirec
cs_cantador 4996 Messages postés dimanche 26 février 2006Date d'inscription 27 mars 2018 Dernière intervention - 11 juil. 2009 à 13:25
0
Utile
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
solilog 273 Messages postés samedi 13 juin 2009Date d'inscription 18 avril 2015 Dernière intervention - 11 juil. 2009 à 15:13
0
Utile
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
f0xi 4304 Messages postés samedi 16 octobre 2004Date d'inscription 9 mars 2018 Dernière intervention - 11 juil. 2009 à 15:18
0
Utile
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
f0xi 4304 Messages postés samedi 16 octobre 2004Date d'inscription 9 mars 2018 Dernière intervention - 11 juil. 2009 à 15:45
0
Utile
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
f0xi 4304 Messages postés samedi 16 octobre 2004Date d'inscription 9 mars 2018 Dernière intervention - 11 juil. 2009 à 15:54
0
Utile
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
cs_cantador 4996 Messages postés dimanche 26 février 2006Date d'inscription 27 mars 2018 Dernière intervention - 11 juil. 2009 à 18:04
0
Utile
- 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
solilog 273 Messages postés samedi 13 juin 2009Date d'inscription 18 avril 2015 Dernière intervention - 11 juil. 2009 à 19:53
0
Utile
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
solilog 273 Messages postés samedi 13 juin 2009Date d'inscription 18 avril 2015 Dernière intervention - 11 juil. 2009 à 19:59
0
Utile
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
cs_cantador 4996 Messages postés dimanche 26 février 2006Date d'inscription 27 mars 2018 Dernière intervention - 12 juil. 2009 à 12:01
0
Utile
Mais si solilog ça marche avec la form2 non créée au démarrage :

test ce code :

unit Unit1;


interface


uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;


type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Déclarations privées }
  public
    { Déclarations publiques }
    procedure AffichageBouton;
  end;


var
  Form1: TForm1;


implementation


{$R *.dfm}
uses unit2;


procedure TForm1.AffichageBouton;
begin
  Button1.Enabled := Assigned(form2);
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
  AffichageBouton;
end;


procedure TForm1.Button2Click(Sender: TObject);
begin
  if not Assigned(Form2) then
    Application.CreateForm(TForm2, Form2);
  Form2.Show;
  AffichageBouton;
end;


end.






unit Unit2;



interface


uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;


type
  TForm2 = class(TForm)
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Déclarations privées }
  public
    { Déclarations publiques }
  end;


var
  Form2: TForm2;


implementation


uses Unit1;


{$R *.dfm}


procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Form2 := nil;
  Form1.AffichageBouton;
end;


end.

clique maintenant sur le bouton2 de la form1 et ferme ensuite la form2

cantador
Commenter la réponse de cs_cantador
solilog 273 Messages postés samedi 13 juin 2009Date d'inscription 18 avril 2015 Dernière intervention - 12 juil. 2009 à 18:17
0
Utile
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
cs_cantador 4996 Messages postés dimanche 26 février 2006Date d'inscription 27 mars 2018 Dernière intervention - 13 juil. 2009 à 12:05
0
Utile
"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
cs_cantador 4996 Messages postés dimanche 26 février 2006Date d'inscription 27 mars 2018 Dernière intervention - 13 juil. 2009 à 15:40
0
Utile
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
solilog 273 Messages postés samedi 13 juin 2009Date d'inscription 18 avril 2015 Dernière intervention - 13 juil. 2009 à 17:10
0
Utile
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

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.