Utilisation Tcollection et TCollectionItem

Signaler
Messages postés
3
Date d'inscription
mercredi 18 octobre 2006
Statut
Membre
Dernière intervention
4 avril 2007
-
cs_clola
Messages postés
3
Date d'inscription
mercredi 18 octobre 2006
Statut
Membre
Dernière intervention
4 avril 2007
-
Bonjour,

Je débute dans la programmation Objet. J'ai quelques notions théoriques mais je n'arrives pas à appliquer la notion de collection avec Delphi. Je cherche un peu d'aide tel que un petit code montrant la déclaration d'une classe style TPersonne(prop :nom,prenom, datenaiss methode : Age...) et d'une collection de TPersonne avec une petite utilisation.
Merci de toute l'aide que vous pourrez m'apporter.

7 réponses

Messages postés
120
Date d'inscription
mardi 3 avril 2007
Statut
Membre
Dernière intervention
15 novembre 2007
1
Tcollection est utile si tu comptes créer un compo visuel qui nécessite un éditeur de propriété  objet.
Sinon, TObjectList est plus souple et permet le tri de la liste, ce que TCollection n'autorise pas.

Je prépare un bout de code de demo que je posterai ici dès son achèvement.
Messages postés
3
Date d'inscription
mercredi 18 octobre 2006
Statut
Membre
Dernière intervention
4 avril 2007

Merci pour cette reponse rapide.
J'avais effectivement vu ton source sur TErrorManager mais je dois dire que ça me depasse un peu. Avec ton autre sujet je comprends maintenant mieux la definition des classes. Maintenant, au niveau de l'utilisation de ces objets c'est autre chose...
Je suis vraiment débutante...
Messages postés
4200
Date d'inscription
samedi 16 octobre 2004
Statut
Modérateur
Dernière intervention
2 janvier 2019
27
MMM...

ce que dis jelume n'est pas faux. mais en programmation une solution n'est pas forcement mauvaise et il y a toujours plusieurs methode pour resoudre un probleme.
Le tout etant de prendre la solutions qui correspond le plus aux besoins.

TObjectList est en effet plus simple a utiliser que TCollection et TCollectionItem, mais TObjectList s'utiliseras plutot en dynamique plutot qu'en statique.
Bien que la, on peu egalement utiliser un TCollection en dynamique... a vrai dire, la notion composant visuel et composant non-visuel n'exclus aucunes des deux façons de faire. D'ailleur on peu trés bien faire un composant visuel avec un TObjectList et un composant dynamique avec un TCollection...
bref.

pour ce qui est du tris, TCollection possede aussi les fonctions de base qui permettent de trier. bien sur, il faudrat implementer d'autre fonctions pour les tris speciaux (par nom, par prenom, par date etc). sur un TObjectList ce seras la meme chose, il faudrat implementer de toute façon des methode de tris car il ne sais pas d'emblé comment trier les données qu'il contient, surtout quand il s'agit un enregistrement (record) ou d'un objet TPersistent ou TObject, a tout les deux il faudrat leurs indiquer comment trier les elements.

TObjectList n'est pas forcement plus souple qu'un TCollection, plus simple certe, mais pas plus souple. A l'origine, tout les objets sont trés souple, car le systeme de classe de Delphi permet cette souplesse.
De toute façon, TObjectList ou TCollection, les deux sont trés bien a voir pour apprendre. mais niveau performance, souplesse, charge memoire, c'est kif kif, puisque un element de 60 octets par exemple dans un TObjectList prendras autant de place dans un TCollection.
On pourras juste dire, que TCollection implemente deja ce qu'il faut pour l'utilisation en design-time et qu'il ne serat pas necessaire de developper un editeur de propriété, contrairement a TObjectList qui est exempt  de ces methodes DT.

enfin, de toute façon, comme je l'ai dis plus haut, TObject, TList, TObjectList, TPersistent, TCollection et TCollectionItem sont de bonnes classes qui permettent d'apprendre la POO et donc la manipulation des classes en Delphi.
Ignorer ces classes serait, ma fois, relativement idiot et dommage, car elle ouvrent les portent a la comprehension de classe plus complexe comme TWinControl, TGraphicControl, TStream, TPropertyEditor etc.

Messages postés
120
Date d'inscription
mardi 3 avril 2007
Statut
Membre
Dernière intervention
15 novembre 2007
1
Bonsoir fOxi,

Tu dis:

"pour ce qui est du tris, TCollection possede aussi les fonctions de base qui permettent de trier .."

Pourrais-tu me dire comment étant donné que la méthode sort n'existe pas dans TCollection ?
Si j'ai modifié plusieurs codes sources à base de TCollection pour les passer en TObjectList, c'est justement à cause de ce problème.
Je serais très intéressé de savoir comment faire ...

En attendant ta solution que je pourrai utiliser moi-même dans mes dev futurs, je prépare le petit exemple à base de TObjectList.

Merci d'avance

Jean-Luc !
Messages postés
120
Date d'inscription
mardi 3 avril 2007
Statut
Membre
Dernière intervention
15 novembre 2007
1
Voilà le code promis !
J'aurais bien mis le projet complet ici mais je ne sais pas comment envoyer un fichier.

unit Unit1;

interface

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

type

  TPersonnes = class;

  TPersonne = class(TObject)
  private

    FAge: Integer;
    FNom: String;

    procedure SetAge(const Value: Integer);
    procedure SetNom(const Value: String);

  public

    Parent: TPersonnes;

    function Next : TPersonne;
    function Index: Integer;

    property Nom: String read FNom write SetNom;
    property Age: Integer read FAge write SetAge;

  end;

  TPersonnes = class(TObjectList)
  private

    function GetPersonne(Index: Integer): TPersonne;

    procedure SetPersonne(Index: Integer; const Value: TPersonne);

  public

    function NouvellePersonne: TPersonne;

    procedure AjouterPersonne(const vNom: String; const vAge: Integer);

    property Personne[Index: Integer]: TPersonne read GetPersonne write SetPersonne;

  end;

  TForm1 = class(TForm)
    memoPersonnes: TMemo;
    btnAfficher: TButton;
    btnCreerListe: TButton;
    procedure btnCreerListeClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure btnAfficherClick(Sender: TObject);
  private

    Personnes: TPersonnes;

  public
    { Déclarations publiques }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TPersonne }

function TPersonne.Index: Integer;
begin
  Result := Parent.IndexOf(Self);
end;

function TPersonne.Next: TPersonne;
begin
  if Index < Pred(Parent.Count) then
    Result := Parent.Personne[Succ(Index)]
  else
    Result := nil;
end;

procedure TPersonne.SetAge(const Value: Integer);
begin
  FAge := Value;
end;

procedure TPersonne.SetNom(const Value: String);
begin
  FNom := Value;
end;

{ TPersonnes }

procedure TPersonnes.AjouterPersonne(const vNom: String; const vAge: Integer);
begin
  with NouvellePersonne do
  begin
    Nom := vNom;
    Age := vAge;
  end;
end;

function TPersonnes.GetPersonne(Index: Integer): TPersonne;
begin
  if (Count > 0) and (Index < Count) then
    Result := Items[Index] as TPersonne
  else
    Result := nil;
end;

function TPersonnes.NouvellePersonne: TPersonne;
begin
  Result := Personne[Add(TPersonne.Create)];
  Result.Parent := Self;
end;

procedure TPersonnes.SetPersonne(Index: Integer; const Value: TPersonne);
begin
  if (Count > 0) and (Index < Count) then
    Items[Index] := Value
  else
    Raise Exception.Create('Aucun élément à cet index');
end;

//
// Code de la feuille montrant l'utilisation de la liste
//

procedure TForm1.btnCreerListeClick(Sender: TObject);
begin
  Personnes.AjouterPersonne('Jacques', 77);
  Personnes.AjouterPersonne('Nicolas', 51);
  Personnes.AjouterPersonne('Ségolène', 53);
  Personnes.AjouterPersonne('François', 48);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Personnes := TPersonnes.Create;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Personnes.Free;
end;

procedure TForm1.btnAfficherClick(Sender: TObject);
var
  Personne: TPersonne;
begin
  Personne := Personnes.Personne[0];
  while Assigned(Personne) do
  begin    memoPersonnes.Lines.Add(format('Nom %s ; Age %d', [Personne.Nom, Personne.Age]));
    Personne := Personne.Next;
  end;
end;

end.
Messages postés
4200
Date d'inscription
samedi 16 octobre 2004
Statut
Modérateur
Dernière intervention
2 janvier 2019
27
vus que jelume vas te faire l'exemple avec TObjectList, je t'ai fais l'exemple avec Tcollection :

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    ListBox1: TListBox;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Déclarations privées }
  public
    { Déclarations publiques }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ Interface des classes TMonItem et TMaCollection }

// utilisé par TMonItem
uses DateUtils;

type
  { TMonItem }
  TMonItem = class(TCollectionItem)
  private
    fCollection  : TCollection;
    fOnChange    : TNotifyEvent;
    fUserName    : string; {prenom}
    fUserSurname : string; {nom}
    fUserDDN     : TDate;  {date de naissance}
    fUserAge     : integer; {age (lecture seule)}
    procedure SetStrProp(index : integer; val : string);
    procedure SetUserDDN(val : TDate);
  protected
    function GetDisplayName : string; override;
    procedure Change; virtual;
    procedure ComputeUserAge; virtual;
    property Collection : TCollection  read fCollection write fCollection;
    property OnChange   : TNotifyEvent read fOnChange   write fOnChange;
  published
    { propriétés publiées, visible dans l'editeur de propriétés }
    property UserName    : string index 0 read fUserName    write SetStrProp;
    property UserSurname : string index 1 read fUserSurname write SetStrProp;
    property UserDDN     : TDate   read fUserDDN  write SetUserDDN;
    property UserAge     : integer read fUserAge;
  public
    { propriétés et methodes publique }
    constructor Create(Collection : TCollection); override;
    procedure Assign(Source : TPersistent); override;
  end;

  { TMaCollection }
const
  // signature des fichiers UDBK (User Data Bank)
  USERDB_FILE_SIGN = cardinal($4B424455);

type
  TMaCollection = class(TCollection)
  private
    fOwner : TPersistent;
    function GetItem(Index: Integer): TMonItem;
    procedure SetItem(Index: Integer; Value: TMonItem);
  protected
    function GetOwner: TPersistent; override;
  published
    { propriétés publiées, visible dans l'editeur de propriétés }
  public
    constructor Create(AOwner : TPersistent);
    function Add : TMonItem; { ajoute un element }
    property Items[Index: Integer]: TMonitem read GetItem write SetItem; default;

    { chargement et sauvegarde d'un fichier UDBK }
    function LoadFromFile(const FileName : string) : boolean; virtual;
    function SaveToFile(const FileName : string) : boolean; virtual;

    { genere une liste lisible des elements de la collection }
    procedure ListItems(Strings : TStrings);

    { retourne l'utilisateur le plus agé }
    function IndexOfOlder : integer;
    { retourne l'utilisateur le plus jeune }
    function IndexOfYounger : integer;
  end;

{ implementation des classes TMonItem et TMaCollection }

{ TMonItem }

constructor TMonItem.Create(Collection: TCollection);
begin
  fCollection := (Collection as TMaCollection);
  inherited Create(Collection);
  fUserName    := '';
  fUserSurname := '';
  fUserDDN     := DateOf(Now);
  ComputeUserAge;
end;

procedure TMonItem.SetStrProp(index : integer; val : string);
begin
  case index of
    0 : if fUserName <> Val then
        begin
          fUserName := Val;
          Change;
        end;
    1 : if fUserSurname <> Val then
        begin
          fUserSurname := Val;
          Change;
        end;
  end;
end;

procedure TMonItem.SetUserDDN(Val : TDate);
begin
  if fUserDDN <> Val then
  begin
    fUserDDN := Val;
    ComputeUserAge;
    Change;
  end;
end;

function TMonItem.GetDisplayName: string;
begin
  result := '['+IntToStr(Self.Index)+'] '+fUserName+' '+fUserSurname;
end;

procedure TMonItem.Change;
begin
  Changed(false);
  if Assigned(fOnChange) then
     fOnchange(self);
end;

procedure TMonItem.ComputeUserAge;
begin
  fUserAge := DateUtils.YearsBetween(Now, fUserDDN);
end;

procedure TMonItem.Assign(Source : TPersistent);
begin
  if source is TMonItem then
  begin
     with (Source as TMonItem) do
     begin
        Self.fUserName    := fUserName;
        Self.fUserSurname := fUserSurname;
        Self.fUserDDN     := fUserDDN;
     end;
     ComputeUserAge;
     Change;
  end else
     inherited Assign(source);
end;

{ TMaCollection }

constructor TMaCollection.Create(AOwner : TPersistent);
begin
  fOwner := AOwner;
  inherited Create(TMonItem);
end;

function TMaCollection.GetItem(Index: Integer): TMonItem;
begin
  Result := TMonItem(inherited GetItem(Index));
end;

procedure TMaCollection.SetItem(Index: Integer; Value: TMonItem);
begin
  inherited SetItem(Index, Value);
end;

function TMaCollection.GetOwner: TPersistent;
begin
  Result := fOwner;
end;

function TMaCollection.Add : TMonItem;
begin
  Result := (inherited Add) as TMonItem;
end;

function TMaCollection.LoadFromFile(const FileName : string) : boolean;
var
  FSign : cardinal;
  N     : integer;
  CountBuf : integer;
  StrBuf   : string;
  StrBufLen: byte;
  DateBuf  : Array[0..2] of word;
begin
  result := false;
  with TFileStream.Create(FileName, fmOpenRead) do
  try
    ReadBuffer(FSign, 4);
    if FSign = USERDB_FILE_SIGN then
    begin
      ReadBuffer(CountBuf, 4);
      if CountBuf > 0 then
         for N := 0 to CountBuf-1 do
             with Self.Add do
             begin
               ReadBuffer(StrBufLen, 1);
               SetLength(StrBuf, StrBufLen);
               ReadBuffer(StrBuf[1], StrBufLen);
               UserName := StrBuf;

               StrBuf := '';

               ReadBuffer(StrBufLen, 1);
               SetLength(StrBuf, StrBufLen);
               ReadBuffer(StrBuf[1], StrBufLen);
               UserSurname := StrBuf;

               ReadBuffer(DateBuf, SizeOf(Datebuf));
               UserDDN := EncodeDate(DateBuf[2],DateBuf[1],DateBuf[0]);
             end;
      result := true;
    end;
  finally
    Free;
  end;
end;

function TMaCollection.SaveToFile(const FileName : string) : boolean;
var N : integer;
    FSign     : cardinal;
    CountBuf : integer;
    StrBuf    : string;
    StrBufLen : byte;
    DateBuf   : Array[0..2] of word;
begin
  result := false;
  with TFileStream.Create(FileName, fmCreate) do
  try
    FSign := USERDB_FILE_SIGN;
    WriteBuffer(FSign, 4);
    CountBuf := Count;
    WriteBuffer(CountBuf, 4);
    for N := 0 to CountBuf-1 do
        with Items[N] do
        begin
          StrBufLen := Length(UserName);
          WriteBuffer(StrBufLen, 1);
          StrBuf    := UserName;
          WriteBuffer(StrBuf[1], StrBufLen);

          StrBufLen := Length(UserSurname);
          WriteBuffer(StrBufLen, 1);
          StrBuf    := UserSurname;
          WriteBuffer(StrBuf[1], StrBufLen);

          DecodeDate(UserDDN, DateBuf[2], DateBuf[1], DateBuf[0]);
          WriteBuffer(DateBuf, SizeOf(DateBuf));
        end;
    result := true;
  finally
    Free;
  end;
end;

procedure TMaCollection.ListItems(Strings : TStrings);
var N : integer;
    DS: string;
begin
  Strings.BeginUpdate;
  Strings.Clear;
  for N := 0 to Count-1 do
      with Items[N] do
      begin
        DateTimeToString(DS, 'dd/mm/yyyy', UserDDN);
        Strings.Add( UserName+' '+UserSurname+' né(e) le '+DS+' à '+IntToStr(UserAge)+' ans.');
      end;
  Strings.EndUpdate;
end;

function TMaCollection.IndexOfOlder : integer;
var N,A : integer;
begin
  result := -1;
  A := 0;
  for N := 0 to Count-1 do
      with Items[N] do
      begin
        if A < UserAge then
        begin
           A := UserAge;
           result := Index;
        end;
      end;
end;

function TMaCollection.IndexOfYounger : integer;
var N,A : integer;
begin
  result := -1;
  A := 2000;
  for N := 0 to Count-1 do
      with Items[N] do
      begin
        if A > UserAge then
        begin
           A := UserAge;
           result := Index;
        end;
      end;
end;

{ Exemple d'utilisation de la collection }
var
  TMC : TMaCollection;

procedure TForm1.FormCreate(Sender: TObject);
begin
  { creation dynamique }

  TMC := TMaCollection.Create(Self);

  { ajout d'elements }
  with TMC.Add do
  begin
    UserName    := 'Paul';
    UserSurname := 'Dupont';
    UserDDN     := StrToDate('07/11/1977');
  end;

  with TMC.Add do
  begin
    UserName    := 'Marine';
    UserSurname := 'Dumoulin';
    UserDDN     := StrToDate('18/12/1976');
  end;

  with TMC.Add do
  begin
    UserName    := 'Pauline';
    UserSurname := 'Dumoulont';
    UserDDN     := StrToDate('11/01/2002');
  end;

  { affichage des elements dans une liste }
  TMC.ListItems(ListBox1.Items);

end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  { liberation de la collection }
  TMC.Free;
end;

end.

Messages postés
3
Date d'inscription
mercredi 18 octobre 2006
Statut
Membre
Dernière intervention
4 avril 2007

Merci pour vos reponses si precieuses.
J'ai egalement avancé de mon côté. Dès que j'ai fini, je donne egalement mon source.
Encore merci pour ces echanges fructueux.