TObjectList, TObjet, record

Résolu
jderf Messages postés 189 Date d'inscription mercredi 29 décembre 2004 Statut Membre Dernière intervention 2 octobre 2014 - 20 déc. 2011 à 15:08
jderf Messages postés 189 Date d'inscription mercredi 29 décembre 2004 Statut Membre Dernière intervention 2 octobre 2014 - 28 déc. 2011 à 15:34
Bonjour,

J'ai voulu faire propre pour une fois, pas de record et de tableau de record !!
J'ai donc créé un class dérivé de TObject et la liste gérée par TObjectList.

Seulement j'avais pas fait attention que la méthode TObjectList.Add passe par référence l'oject !
En fait, TObjectList dérive de Tlist et dans la doc c'est claire
Tlist : function Add(Item: Pointer): Integer;


Pour simplifier j'ai écris un exemple, identique sur le principe à ma class.

unit MonUnite;

TMaClassObject = class(TObject)
  private
    FValue : integer;
  protected
    //
  public
    constructor Create;
    destructor Destroy; override;
    property Value : Integer read FValue write FValue;
  end;

-----------------------  
   
uses MonUnite;

var ListeObject : TObjectList;
  
.../...  
procedure TForm.Init;
var Obj : TMaClassObject;
begin
  // Création de la liste vide
  ListeObject := TObjectList.Create;
  ListeObject.Clear; // 

  // Création de l'object temporaire  
  Obj := TMaClassObject.Create;

  // Ajout dans la liste
  Obj.Value := 10;
  ListeObject.Add(Imp);

  //  Ajout dans la liste
  Obj.Value := 30;
  ListeObject.Add(Imp);

  // ICI la liste contient 2 fois la référnce du même Object qui à maitenant Value=30 !!
  Obj.Destroy;
  // ICI la liste contient 2 fois la réference d'un object qui n'existe plus !
  
  .../...
  
end;



Y'a t-il une autre solution que de transformer ma class TMaClassObject en record et de déclarer un tabelau dynamique comme ceci :
ListeObject : array of TMaClassObject;
Et d'écrire les procedures d'insertion et de suppression dans le tableau ?


Merci pour vos réponses.
Jean

7 réponses

cs_MAURICIO Messages postés 2106 Date d'inscription mardi 10 décembre 2002 Statut Modérateur Dernière intervention 15 décembre 2014 5
22 déc. 2011 à 10:37
Salut,

le problème est qu' effectivement, tu rajoutes le même objet ce qui n' est pas correct!
En modifiant sa valeur, tu modifies autant de fois que tu as ajouté l' objet.

Le truc consiste donc à créer un objet à chaque fois que tu veux insérer un nouvel élément.
Je te propose donc de créer un procedure pour cet effet et n' oublie pas que tu dois supprimer ces objets quand tu n' en a plus besoin.

procedeure AjouterObjet(Valeur: Integer);
var Obj : TMaClassObject;
begin
Obj := TMaClassObject.Create;

// Ajout dans la liste
Obj.Value := Valeur;
ListeObject.Add(Obj);
end;

procedure TForm.Init;
begin
AjouterObjet(10);
AjouterObjet(30);
end;

Pour ce qui est de ta question, je dirais que tu peux utiliser aussi une TStrings ...

A+

Composants Cindy pour Delphi
Faites une donation.
3
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
22 déc. 2011 à 18:12
Salut,

Mauricio a raison ... juste une petite précision sur un point.
[quote=Mauricio]... n' oublie pas que tu dois supprimer ces objets quand tu n' en a plus besoin. /quote
Oui et Non
TObjectList possède une propriété nommée "OwnsObjects" qui par défaut est à True.

[quote=Au sujet de "OwnsObjects" l'aide de Delphi]Permet à TObjectList de libérer les objets lorsqu'ils sont supprimés de la liste ou si la liste est détruite.

Description
OwnsObjects permet à TObjectList de contrôler la mémoire de ses objets. Si OwnsObjects est à true (par défaut),

Appeler Delete ou Remove libère l'objet supprimé en plus de les supprimer de la liste.

Appeler Clear libère tous les objets de la liste en plus de vider la liste.

Appeler le destructeur libère tous les objets de la liste en plus de détruire l'objet TObjectList lui-même.

Affecter une nouvelle valeur à un indice de Items libère l'objet qui occupait précédemment cette position dans la liste.

Même si OwnsObjects est à true, la méthode Extract peut être utilisée pour supprimer les objets de la liste sans les libérer.

/quote

@jderf:
[quote=jderf]
  // ICI la liste contient 2 fois la référnce du même Object qui à maitenant Value=30 !!
  Obj.Destroy;
  // ICI la liste contient 2 fois la réference d'un object qui n'existe plus !
  
  .../...
/quote

Il ne faut jamais appeler la méthode "Destroy" directement dans le code. Il faut toujours utiliser "Free" à la place qui fait appel à "Destroy" en interne !!!!

Quand l'aide dit:
Appeler le destructeur libère tous les objets de la liste en plus de détruire l'objet TObjectList lui-même.

c'est pareil ... d'ailleurs elle le précise:
N'appelez pas directement Destroy. Appelez plutôt Free. Free vérifie que la référence objet n'a pas la valeur nil avant d'appeler Destroy.



Sinon j'ajouterai que TObjectList se comporte exactement comme on attend qu'une list d'objets se comporte.
Si il faisait, à chaque "Add", une copie de l'objet ça serait vite le bordel !!!

[hr]@+Cirec
[hr]
0
jderf Messages postés 189 Date d'inscription mercredi 29 décembre 2004 Statut Membre Dernière intervention 2 octobre 2014 1
26 déc. 2011 à 15:22
Merci Mauricio, merci Cirec pour ces compléments.

Je voulais lire, à partir d'un fichier INI ou XML, la position, couleur, et d'autres caractéristiques d'élément composant une impression (logo, adresse, bas page etc..).
Mais je crois que l'idée n'est pas une bonne idée au niveau conception.

Les objects (TImpImage, TImpAdresse, TImpCadreText, TImpLigneText, ...) étaient créés et remplis à la lecture, et mémorisés dans la liste. Une fois la lecture du fichier terminé, les object étaient détruits. Il me restait alors une liste avec tous les éléments à mettre dans mon impression. Je passait à la procedure d'impression uniquement la liste.

Je vais laissé murir un peu, je suis pas bien pressé.

Merci encore et bonne fêtes.
Jean
0
Utilisateur anonyme
27 déc. 2011 à 01:04
Salut,

Tu peux aussi utiliser les classes TCollection et TCollectionItem : ca pourrait etre une bonne alternative à la classe TObjectList.

Sinon pour revenir à l'essentiel : ton objectif. J'avoue ne pas avoir tout saisi à ce que tu souhaites faire(il manque un peu d'informations pour comprendre là ou tu veux en venir ).

Pourrais tu exposer clairement ce que tu veux faire : on pourrait peut etre te donner une piste
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
jderf Messages postés 189 Date d'inscription mercredi 29 décembre 2004 Statut Membre Dernière intervention 2 octobre 2014 1
27 déc. 2011 à 11:08
Bjr Francky,

Je vais essayé de faire plus clair !

Dans mon appli, j'ai une dizaine de types d'impression différente. Pour chaque document, une partie des données est interne à l'appli et générée par l'application. Une autre partie, correspondant aux logo, à l'adresse de la société, au bas de page avec le n° siret etc .. est externe à l'appli. Je souhaite que ces éléments variables puissent être facilement modifiés en dehors de l'appli.
Pour cela, je pensais mettre les infos dans un fichier ini ou xml comme ci-dessous :

<?xml version="1.0" encoding="ISO-8859-1"?>

  <haut_page>
  </haut_page>
  
  <rich_text>
none
clBlue
16
<top>100</top>
<left>100</left>
500
<right>500</right>
<chemin>..\modele_impression\modele.rtf</chemin>
  </rich_text>
  
  
<top>100</top>
<left>100</left>
500
<right>500</right>
<chemin>..\modele_impression\images\logo.jpg</chemin>
  
  
  <ligne>
  	none
clBlue
16
<top>100</top>
<left>100</left>
500
<right>500</right>  
<Xposition>pcenter</Xposition>
<Yposition>pcenter</Yposition>
<text>text sur une ligne, centré en X et Y</text>
  </ligne>
  
  
  



Donc le process :
- une impression est demandée
- je lis le fichier xml correspondant
- je stock les infos de mise en page dans une liste
- je lance la création de la page (données + elément de la liste)
- je lance l'impression du document

Donc pour cela en fonction des éléments trouvés dans le xml, je créé les objets correspondants et je les stcoke dans la liste. Une fois la lecture fini,je sors de ma procedure et les objets sont détruits et il me reste que la liste (global à l'unite d'impression) avec toutes les infos. Enfin c'est ce que je croyais !!

Voilà en espérant être un peu plus clair. Merci.

Jean.
0
Utilisateur anonyme
27 déc. 2011 à 18:26
Salut,

Hummmm pas facile ton truc : Perso je m'y prendrais pas du tout ainsi.

1)Je ferais différents types (TLine,TImage,TText ...) avec pour chacun les propriétés dont j'ai besoin. Par exemple :[width,Height,Top,Left,Picture,Color,font].

2)Ensuite je ferais un composant visuel, utilisant les deux classes TCollection et TCollectionItem afin de créer en runtime ou designtime une liste de TLine,TImage,TText et cela suivant mes besoins afin de créer mon modèle de page en fonction de mon envie (En jouant sur le caractère private, public,published il est possible de bloquer l'accessibilité des propriétés comme on le souhaite et donc d'aboutir à un truc du type wysiwyg ce qui est l'idéal je pense pour toi).

3)Ensuite pour enregistrer et lire mon modèle sur un fichier c'est facile j'utiliserais les fonctions WriteComponent et ReadComponent. Cela se fait en une ligne de code.

4)Pour l'impression : Un chouilla plus compliqué. Je ferais une fonction/procedure Doc_Print en utilisant la classe TPrinter et un analyseur pour lancer l'impression.

L'avantage de cette technique c'est que tu pourras faire un document visuel ce qui est vachement pratique pour l'utilisation futur de tes modèles. Après c'est du boulot mais c'est pas si complexe et long qu'on pourrait le croire.

Par contre ta stratégie me semble pas bonne du tout (Surtout qu'un fichier Ini est limité à 64ko) et le résultat que tu vas obtenir va faire un peu sale (Utiliser un fichier XML ou ini pour faire un ca n'est pas ce qui convient le mieux ^^).

Pour la classe TObjectList tu risques d'etre obligé de faire du bricolage par moment. Bref c'est à mon gout pas du tout adapté à ce que tu veux faire et tu risques de coincer à certains moments avant de finaliser ton idée.

Un dernier conseil : prend une feuille de papier et pose bien par écrit ta problématique. Ca te permettra de mieux cerner là ou tu veux aller et de mieux cerner ce que tu dois faire.

Bon courage à toi
0
jderf Messages postés 189 Date d'inscription mercredi 29 décembre 2004 Statut Membre Dernière intervention 2 octobre 2014 1
28 déc. 2011 à 15:34
Merci Francky pour les conseils.

Pour l'impression et le rendu visuel, je vais utiliser PrintPreview. Par contre pour gérer, d'une manière souple, la mise en page (et si possible en dehors de l'appli), je vais effectivement prendre le temps de la reflexion. C'est la première fois que je me lance à faire des impressions de données avec une mise en page un peu sophistiquée.

A+
Jean
0
Rejoignez-nous