un bloc de mémoire non initialisé, qui peut contenir n'importe quoi, les restes d'une allocation précédente bref un truc pas propre
un bloc de mémoire non initialisé, qui peut contenir n'importe quoi, les restes d'une allocation précédente bref un truc pas propre
Je pensais que contrairement au C++ (quoiqu'en Qt ce n'est pas mal géré déjà), Delphi faisait le ménage après... mais aussi avant.
C'est pour cela que lors de la compilation, les avertissements de non initialisation apparaissent. A force de les voir... je n'y porte pas d'attention.
OK. Merci pour tous ces renseignements. J'espère résolu maintenant.
Dernière modification par Invité ; 01/12/2014 à 17h12.
Le problème étant réglé (pour l'instant), j'abuse un brin, je sais...
Frédéric,
avec un TList pour gérer les instances des Forms cela donne quoi comme déclarations/créations des Forms (et du TList) ? Cela me semble à priori largement aussi compliqué que de gérer les trous du tableau ? Non ?
Et avec une TObjectList pas besoin de gérer la destruction
Je me permet de répondre, tu peux avoir une variable:
et ensuite ajouté tes différentes form dedans:
Code : Sélectionner tout - Visualiser dans une fenêtre à part FListForm : TObjectList<TForm>
et tu peux utiliser comme tu veux :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 MaForm := TForm2.Create(nil); FListForm.Add(MaForm);
Pour tout détruire il suffit d'un simple
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 FListForm[i].Show etc ..
Pour tes variable je n'es pas lu tout ton code mais je te conseil d'utiliser les property
Code : Sélectionner tout - Visualiser dans une fenêtre à part FListForm.Clear;
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82 unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, system.Generics.Collections, Unit2; type TForm1 = class(TForm) Button1: TButton; Edit1: TEdit; Button2: TButton; ListBox1: TListBox; procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure Button2Click(Sender: TObject); private { Déclarations privées } FString : string; ListeForm2 : TList<Tform2>; public { Déclarations publiques } Property prString : string read FString write FString ; end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); var Form2 : TForm2; begin Form2 := TForm2.Create(Application); ListeForm2.Add(Form2); with Form2 do begin prString := Edit1.Text; ListeForm2 := self.ListeForm2; // Je passe une référence de la liste à Form2 comme ca Form2 n'a pas besoin de Form1 pour s'enlever de la liste à sa libération. Show; end; // oubien version courte sans utiliser de "var form2 : TForm2" : // with ListeForm2[ListeForm2.Add(TForm2.Create(Application))] do // begin // prString := Edit1.Text; // ListeForm2 := self.ListeForm2; // Je passe une référence de la liste à Form2 comme ca Form2 n'a pas besoin de Form1 pour s'enlever de la liste à sa libération. // Show; // end; end; procedure TForm1.Button2Click(Sender: TObject); var Form2 : TForm2; begin // affiche la liste des captions de fenetre + la propriété prString ListBox1.Clear; for Form2 in ListeForm2 do ListBox1.Items.Add('Caption :' + Form2.Caption + ' parametre : ' + Form2.prString); end; procedure TForm1.FormCreate(Sender: TObject); begin ListeForm2 := TList<TForm2>.create(); end; procedure TForm1.FormDestroy(Sender: TObject); var Form2 : TForm2; begin for Form2 in ListeForm2 do Form2.ListeForm2 := nil; // les deux lignes dessus sont inutiles si Form1 est la form principale de ton application. ListeForm2.Free; end; end.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 unit Unit2; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, system.Generics.Collections; type TForm2 = class(TForm) procedure FormShow(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure FormCreate(Sender: TObject); private { Déclarations privées } FString : string; public { Déclarations publiques } ListeForm2 : TList<Tform2>; Property prString : string read FString write FString ; end; // J'ai supprimé le var form2 : TForm2 ! comme ca je suis certain de ne pas utiliser Form2 ! implementation {$R *.dfm} procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction); begin Action := cafree; // libère la mémoire if assigned(ListeForm2) then with ListeForm2 do begin Delete(IndexOf(self)); end; end; procedure TForm2.FormCreate(Sender: TObject); begin ListeForm2 := nil; end; procedure TForm2.FormShow(Sender: TObject); begin self.Caption := 'Fenêtre Form2, appelée avec parametre : ' + prString; end;
Uniquement pour les variables d'instance. A la création de l'objet, la mémoire est mise à zéro.
Les variables globales sont dans un état indéterminé mais depuis quelques versions de Delphi déjà, il est possible de les initialiser:
Les variables locales (propres à une procédure/méthode) doivent l'être obligatoirement par code.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 var MaVar :integer = 0;
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 procedure Proc; var MaVar :integer; begin MaVar := 0; end;
Bon alors j'essaie de suivre.
Robin,
comme je n'utilise pas les TObjectList, j'ai testé (sous FireMonkey)
- Déclaration
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls, System.Generics.Collections, unit2; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); private { Déclarations privées } public { Déclarations publiques } FListForm : TObjectList<TForm>; //-> uses System.Generics.Collections; end; var Form1: TForm1; implementation {$R *.fmx} procedure TForm1.FormCreate(Sender: TObject); begin FListForm := TObjectList<TForm>.Create(True); end; procedure TForm1.FormDestroy(Sender: TObject); //-> Nécessaire ? Je pense que non. FListForm est détruit automatiquement avec Form1 begin //FListForm.Clear; FreeAndNil(FListForm); end;
- Instanciation
Je m'y prends peut-être mal mais je me pose déjà quelques questions :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 procedure TForm1.Button1Click(Sender: TObject); var wForm2 : TForm2; begin wForm2 := TForm2.Create(nil); FListForm.Add(wForm2); //FreeAndNil(wForm2); //-> Pourquoi un plantage... FListForm ne dispose pas d'une instanciation autonome de wForm2 ? FListForm[FListForm.Count -1].Show; //-> est-ce bien wForm2 que je viens de créer ? end;
Trois questions :
- Suis-je sûr que la wForm2 nouvellement créée est la dernière du TObjectList ? Je suppose que oui. Y a-t-il des exceptions à ce fonctionnement. Intervertir 2 Forms pourrait être catastrophique.
- Comment marque-t-on une fiche wForm2 particulière qui, par exemple, servirait de référence ? Avec le tableau, c'est facile, son numéro restera fixe. Le problème étant que si la liste se maintient à jour toute seule, les N° se décalent automatiquement. Exemple, j'ouvre 3 bulletins. Je marque le 2ème ouvert comme référence, Je ferme le premier ouvert... Que devient la référence ? Il faut intégrer une variable supplémentaire à TForm2. Avec un Array, la 2ème fiche ouverte, restera toujours la deuxième que l'on enlève d'autres ou pas après avoir désigné cette Form comme référence.
- FreeAndNil(wForm2); ??
Merci.
Dernière modification par Invité ; 01/12/2014 à 18h27.
AndNotOr,
j'avais remarqué qu'on ne pouvait pas initialiser les variables locales autrement que par code...
Commentaire : c'est vraiment peu pratique. J'avais pris de "mauvaises" habitudes en C++. Enfin "mauvaises"
Frédéric,
En attente... Il faut que j'étudie cela de plus près... En regardant rapidement le code, je comprends mal la présence des TList dans les 2 units... et je pensais (naïvement certainement) que la destruction d'une wForm2 mettrait automatiquement à jour la TList... je commence à saturer un peu... Donc je reverrai cela jeudi PM maintenant.
Merci à tous pour votre aide.
Dernière modification par Invité ; 01/12/2014 à 18h39.
1-
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 var wForm2 : TForm2; IndexForm : integer; begin wForm2 := TForm2.Create(nil); IndexForm := FListForm.Add(wForm2); FListForm[IndexForm].Show; end
2- Je ne comprend pas la question
3- Ce n'est pas le freeandNil qui plante c'est que vous essayez d'utiliser form2.show juste après l'avoir détruit.
J'ai encore mal compris le mécanisme ? Mais comme je l'ai écrit, je ne connais pas les TObjectList.
J'ai pensé que le cast générait une propre instance autonome de TForm2 (par "copie" de la Form locale wForm2, traduction et interprétaion personnelles assez fantaisistes et approximatives du TObjectList.add) et que donc une fois affectée au TObjectList la wForm2 local pouvait être détruite... Visiblement, ce n'est pas le cas... Mais pourtant cela doit l'être quelque part... car la wForm2 n'est pas permanente car "régénérée" à chaque clic sur le TButton. C'est une variable locale.
Pour le point 2, j'ai probablement mal interprété les propos lus :
Si le TObjectList est capable de gérer automatiquement les suppressions des Forms (gestion des trous), je peux supposer que l'IndexForm que vous employez est variable dans le temps pour une Form donnée. Sinon l'IndexForm dépasserait à un moment donné le count. C'est inenvisageable.
Pour le point 2, cela m'inquiète. Si vous ne comprenez pas, c'est que ma modélisation est loin de la réalité de ce que je pense être le fonctionnement . Il n'est pas facile d'imaginer avec précision les mécanismes sous-jacents pour comprendre le fonctionnement des objets que l'on ne connait pas. Et partiellement par paresse -mais pas seulement car l'offre documentaire y est pour quelque chose et crée une lassitude certaine-, on imagine, et on tâtonne. Bref en situation, je crée 3 Forms d'index (automatique à la création dans le TObjectList) : 0, 1, 2. Je retiens la N° 2 en référence (idRef := 2) Par exemple, un champ de cette Form sera transféré automatiquement dans les 2 autres. Je me ravise et détruis la fiche 1. Les index deviennent non pas 0, 2 mais 0, 1 si le TlObjectList gère automatiquement la destruction de l'ex Form1. Et si j'ai bien compris, comment vais-je indiquer que la Form d'index automatique (2) est devenue l'index 1 de mon TObjectList ? Mais ce n'est pas une certitude. Il faut que je me documente sur cet Objet. Ce que j'écris est peut-être absurde. Dans tous les cas, c'est une digression chronophage par rapport au projet initial... mais cela peut éventuellement me permettre de découvrir de nouveaux horizons même si je peux supposer qu'un array de TForms me permettra de réaliser ce que je veux obtenir. J'ai l'habitude des tableaux d'une part, et à priori seules l'assignation et la désassignation des TForms me posaient problème pour gérer proprement l'approche envisagée. Et dans ce domaine, grâce au forum, il me semble avoir progressé et être capable de modéliser une approche cohérente.
Je réétudierai cela plus tard à tête reposée...
Dernière modification par Invité ; 01/12/2014 à 19h57.
L'avantage du TObjectList créé avec OwnsObjects à True est de libérer les objets qu'il référence au Clear ou lors de sa propre libération.
Comme un tableau, une liste peut avoir des "trous" en remplaçant par affectation la référence voulue par nil => pas de décalage d'index.
Par contre, TobjectList ne se met pas à jour lors de la destruction d'un des objets dont on lui a passé une référence. On peut concevoir facilement des objets dont le Destroy mettra à nil la référence qu'une liste conserve sur eux, en leur passant une référence à cette liste, mais je ne vois pas bien si cela peut être utile dans votre cadre, que je n'ai pas saisi...
Au final, utiliser un tableau ou une liste est équivalent si on retire pas d'objet de l'un ni de l'autre et se contente de modifier les références obsolètes.
Delphi 5 Pro - Delphi 10.4 Rio Community Edition - CodeTyphon 6.90 sous Windows 10 ; CT 6.40 sous Ubuntu 18.04 (VM)
. Ignorer la FAQ Delphi et les Cours et Tutoriels Delphi nuit gravement à notre code !
Là, j'abandonne. Je n'arriverai pas à le formuler correctement.
Je vais me faire l'avocat du diable. Mais compte tenu des méthodes d'affectations (le passage par une TForm locale m'indispose), l'inconvénient du TObjectList<TForm>, c'est que ses "Items" ne sont pas des TForms autonomes alors que dans un tableau de TForms, elles peuvent être gérées directement comme telles. Enfin, c'est ce que je perçois actuellement, mais ma documentation n'est pas assez complète pour que je cerne vraiment efficacement l'approche TObjectList sur des TForms. Parce que les 2 sont liés. En réalité le tableau ou le TObjectList sont des Objets de gestion, de classement, d'organisation des TForms créés ou détruites... Le reste, tout le reste, c'est-à-dire l'essentiel, c'est la TForm qui le fait... Donc déjà, la création d'une TForm déclarée localement et son affectation au TObjectList sont une incompréhension pour moi.. Je ne comprends pas ce qui se passe exactement. Par quel mécanisme, un objet local créé dans un bouton dans un bouton qui peut être multi-cliqué, peut-il perdurer sans être répliqué ? Et si c'est tel n'est pas le cas, pourquoi la destruction de la Form locale après "affectation", plante-telle le programme ?
Mais tout cela je l'ai déjà exprimé.
Bon j'arrête là. A... jeudi.
Dernière modification par Invité ; 01/12/2014 à 20h16.
Essayez mon projet à base de TList (c'est comme le TObjectList sauf que je gère moi même la libération de la mémoire).
C'est là votre erreur, wForm2 n'est pas votre objet c'est juste un pointeur vers votre objet.
Apres le wForm2 := TForm2.create(application); vous pouvez faire wForm2 := nil; cela ne va pas libérer ou fermer votre instance de form2. Simplement wForm2 ne pointe plus vers cette instance.
Pour ce qui est des TList et TlistObject ce ne sont que des liste de pointeurs avec les même contraintes que pour un tableau de pointeur.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 var wForm2,wForm2bis,wForm2ter : TForm2; // Je crée 3 pointeurs vers des instances de type TForm2 begin wForm2 := TForm2.create(application); // je crée une instance de TForm2 et wForm2 pointe vers cette instance d'objet wForm2bis := TForm2.create(application);// je crée une seconde instance de TForm2 et wForm2bis pointe vers cette instance d'objet wForm2ter := wForm2; // wForm2ter pointe vers la même instance que wForm2 (on n'a pas créé de nouvelle instance) FreeAndNil(wForm2); // Je libère l'instance pointée par wForm2 et affecte nil ) wform2. if Assigned(wForm2ter) then wForm2ter.show; // erreur !!! wform2ter n'est pas égal à nil et pointe toujours vers la même adresse mémoire. Seulement l'instance qui était à cette adresse n'existe plus. L'instance a été libéré par le FreeAndNil(wForm2). end; // les pointeurs wForm2, wForm2bis, wForm2ter sont libérés (mais ca ne ferme pas l'instance que wForm2bis pointait)
Vous ne pouvez plus réfléchir avec les index, puisque c'est la TListxxx qui gère ceux-ci.
Vous parlez de form de référence ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13 Form2Reference : Tform2; ListeForm2 : TList<Tform2>; // liste les références aux instances des autres Form2 (autre que la référence) ... ... ... //Copie de la propriete MaPropriete de la form de référence vers les autres form : procedure PropagerMaPropriete(); var Form2 : TForm2; begin for Form2 in ListeForm2 do Form2.MaPropriete := Form2Reference.MaPropriete; end;
Bonjour à tous.
De toute façon, moi je supprime les variables globales créer par Delphi (genre var frmEditor : TfrmEditor) comme ça je suis obliger soit d'utiliser une variable local quand je veux faire une instanciation.
Andry
On progresse .....
salut
le plus simple serait d'utiliser un objet global a ton application ce qui permettrais par exemple
d'acceder a partir de tes diffferentes formes
je mexplique
dans le dpr tu auras un truc du genre
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 Unit UGlobal; interface TDataGlobal = class(TDataModule) ... end var DataGlobal: TDataGlobal; implementation ... end.
dans tes formes tu pourra donc a tous moment retrouver des information passé a TDataGlobal
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 //////////////////////////////////////////////////////////////////////////////// begin SysUtils.ThousandSeparator := ' '; SysUtils.DecimalSeparator := '.'; SysUtils.ShortDateFormat := 'dd/mm/yy'; SysUtils.TwoDigitYearCenturyWindow := 50; // pivot de changement de siècle // initialise l'application Application.Initialize; Application.UpdateFormatSettings := False; Application.Title := 'Mon appli a mois'; Application.CreateForm(TDataGlobal, DataGlobal); Application.CreateForm(Tform1, form1); // fenêtre principale de l'appli Application.Run; end.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 Procedure TForm1.jaibesoindinfogeneral ; begin MonInfo := DataGlobal.MonInfoQueJaiBesoin end;
J'ai pris un datamodule car celui-ci est pratique pour posser des composants et autres joyeuseté
@mes deux cents
Blaise PascalNous souhaitons la vérité et nous trouvons qu'incertitude. [...]
Nous sommes incapables de ne pas souhaiter la vérité et le bonheur, et sommes incapables ni de certitude ni de bonheur.
PS : n'oubliez pas le tag
Bonjour,
Donc pour les TForms, j'ai étudié et pense avoir compris l'usage des pointeurs. Je resterai sur mon array, non pas que cette solution présente une quelconque supériorité ou infériorité. C'est simplement une question d'affect, d'habitude et de conception de ma pensée. L'un des systèmes ne présentant pas d'avantage par rapport à l'autre, je choisis celui qui me paraît le plus naturel, le plus lisible, le moins potentiellement faillible dans le code en ce qui me concerne parce que je suis toujours très réticent à l'utilisation de pointeurs surtout quand une autre solution existe. Je sais bien qu'il y en a partout, mais autant que possible je préfère un usage implicite (et automatique).
Pour les variables globales stockées dans une unit, cela fonctionne en effet. Cependant, si 2 instances "simultanées" d'une même Form modifient la même variable d'une autre unité servant de stockage, la dernière modification écrase la première. Donc tout dépend du mode d'appel des fenêtres.
Je place un "résolu". Merci pour vos aides.
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager