Meetup Delphi à Lyon

Meetup de Lyon le 9 Novembre 2017

Première synchronisation des meetup ! Trois rencontres seront proposées ce soir, Bordeaux, Paris et Lyon.

Pour ce deuxième meetup au Webup Space de Lyon je vais faire une présentation Delphi (FMX et VCL).

 

Pour commencer nous allons voir les collections génériques, comment filtrer les données de ces listes et puis un exemple concret pour gérer une navigation et les données dans une application.  Ensuite passage à Firemonkey avec une présentation des effets et animations qui vont servir à créer un menu pour Android. Pour finir le déploiement d’une base de données sur un périphérique mobile et comment télécharger des données.

Les collections génériques

Les types génériques Delphi permettent d’utiliser des classes pour lesquelles un ou plusieurs types ne sont pas spécifiés à la définition du type, mais seulement au moment de leurs utilisations.

Les collections se trouvent dans l’unité System.Generics.Collections.

On retrouve les TObject(…)<T> et TList<T>.

Les listes TObject sont des TList avec la capacité de libérer les items quand ils sont supprimé de la liste. Pour cela à la création de la liste le constructeur contient le paramètre AOwnsObject, par défaut à True. Il peut être modifié plus tard avec la propriété OwnsObjects.

Commençons par créer une classe TPersonne.

type
   TPersonne = class
   strict private
      FName: string;
      FAge : integer;
   public
      constructor Create(aName: string; aAge: integer);
      destructor Destroy; override;
   end;
 
{ TTest }
 
constructor TPersonne.Create(aName: string; aAge: integer);
begin
   Writeln(Format('Création de %s', [aName]));
   FName := aName;
   FAge  := aAge;
end;
 
destructor TPersonne.Destroy;
begin
   Writeln(Format('Destruction de %s', [FName]));
   inherited;
end;

TObjectList<t>

Il s’agit d’une liste sur laquelle nous pouvons ajouter des items et les détruire à l’aide de la méthode Clear.

var
   List: TObjectList&lt;TPersonne&gt;;
begin
   try
      try
         List := TObjectList&lt;TPersonne&gt;.Create(True);
 
         List.Add(TPersonne.Create('Arnaud', 10));
         List.Add(TPersonne.Create('Pierre', 20));
         List.Add(TPersonne.Create('David',  50));
 
         List.Clear;
      finally
         FreeAndNil(List);
      end;
 
      Readln;
   except
      on E: Exception do
         Writeln(E.ClassName, ': ', E.Message);
   end;
end.

TObjectStack<t>

Cette liste est de type Last In First Out (LIFO), la méthode Peek retourne le dernier item, la méthode Pop le supprime. Avec l’exemple si dessous les items sont supprimés dans l’ordre inverse de la TObjectList.

var
   List: TObjectStack&lt;TPersonne&gt;;
begin
   try
      try
         List := TObjectStack&lt;TPersonne&gt;.Create;
 
         List.Push(TPersonne.Create('Arnaud', 10));
         List.Push(TPersonne.Create('Pierre', 20));
         List.Push(TPersonne.Create('David',  50));
 
         // retourne le dernier item (c)
         List.Peek;
         // supprime le dernier item de la liste (c)
         List.Pop;
 
         List.Clear;
      finally
         FreeAndNil(List);
      end;
 
      Readln;
   except
      on E: Exception do
         Writeln(E.ClassName, ': ', E.Message);
   end;
end.

TObjectQueue

A l’inverse de la TObjectStack la TObjectQueue est une liste de type First In First Out (FIFO). Les méthodes Queue et Dequeue permettent de manipuler les objets de la liste.

var
   List: TObjectQueue&lt;TPersonne&gt;;
begin
   try
      try
         List := TObjectQueue&lt;TPersonne&gt;.Create;
 
         List.Enqueue(TPersonne.Create('Arnaud', 10));
         List.Enqueue(TPersonne.Create('Pierre', 20));
         List.Enqueue(TPersonne.Create('David',  50));
 
         //  supprime le 1er item de la liste (a)
         List.Dequeue;
      finally
         FreeAndNil(List);
      end;
 
      Readln;
   except
      on E: Exception do
         Writeln(E.ClassName, ': ', E.Message);
   end;
end.

Filtrer des données

Utiliser des listes c’est bien, pouvoir filtrer dedans simplement c’est mieux 🙂
Pour cela nous allons commencer par voir les méthodes anonymes.

Une méthode anonyme est une procédure ou une fonction n’ayant pas de nom. Une méthode anonyme traite un bloc de code comme une entité qui peut être assigné à une variable ou utilisée comme paramètre d’une méthode.

Voici un exemple avec une méthode anonyme avec deux paramètres qui retourne un entier.

type
   TDeuxChiffres = reference to function (X, Y: integer): integer;
 
var
   Func: TDeuxChiffres;
begin
   try
      Func := function(X, Y: integer): integer
              begin
                 Result := X + Y;
              end;
 
      Writeln(Func(1, 2).ToString);
 
      Readln;
 
      Func := function(X, Y: integer): integer
              begin
                 Result := X * Y;
              end;
 
      Writeln(Func(1, 2).ToString);
 
      Readln;
 
      Func := function(X, Y: integer): integer
              begin
                 Result := X - Y;
              end;
 
      Writeln(Func(1, 2).ToString);
 
      Readln;
   except
      on E: Exception do
         Writeln(E.ClassName, ': ', E.Message);
   end;
end.

TPredicate

Le TPredicate n’est ni plus ni moins qu’une méthode anonyme qui retourne un booléen.

TPredicate&lt;T&gt; = reference to function (Arg1: T): Boolean;

A l’aide de notre classe de base (TPersonne) nous allons récupérer les personnes respectant certains critères. Pour cela nous allons créer un nouveau type, le TListPersonne qui est une TObjectList<TPersonne>.

type
   TTypePersonne = (tpMajeur, tpMineur);
 
   TPersonne = class
   strict private
      FName: string;
      FAge : integer;
   public
      constructor Create(aName: string; aAge: integer);
      destructor Destroy; override;
 
      property Name : string  read FName;
      property Age  : integer read FAge;
   end;
 
   TListPersonne = class(TObjectList&lt;TPersonne&gt;)
   strict private
      function GetPersonne(aPredicate: TPredicate&lt;TPersonne&gt;): TList&lt;TPersonne&gt;; overload;
   public
      function GetPersonne(aTypePersonne: TTypePersonne): TList&lt;TPersonne&gt;; overload;
   end;
 
{ TTest }
 
constructor TPersonne.Create(aName: string; aAge: integer);
begin
   Writeln(Format('Création de %s', [aName]));
   FName := aName;
   FAge  := aAge;
end;
 
destructor TPersonne.Destroy;
begin
   Writeln(Format('Destruction de %s', [FName]));
   inherited;
end;
 
var
   List: TListPersonne;
{ TListPersonne }
 
function TListPersonne.GetPersonne(
  aPredicate: TPredicate&lt;TPersonne&gt;): TList&lt;TPersonne&gt;;
var
   ListPersonne: TList&lt;TPersonne&gt;;
   Personne    : TPersonne;
begin
   ListPersonne := TList&lt;TPersonne&gt;.Create;
 
   for Personne in Self do
   begin
      if aPredicate(Personne) then
      begin
         ListPersonne.Add(Personne);
      end;
   end;
 
   Result := ListPersonne;
end;
 
function TListPersonne.GetPersonne(
  aTypePersonne: TTypePersonne): TList&lt;TPersonne&gt;;
var
   Critere : TPredicate&lt;TPersonne&gt;;
begin
   Result := nil;
 
   if aTypePersonne = tpMajeur then
   begin
      Critere := function (Personne : TPersonne) : boolean
                 begin
                    Result := Personne.Age &gt;= 18;
                 end;
   end
   else
   begin
      if aTypePersonne = tpMineur then
      begin
         Critere := function (Personne : TPersonne) : boolean
                    begin
                       Result := Personne.Age &lt; 18;
                    end;
      end;
   end;
 
   if Assigned(Critere) then
      Result := GetPersonne(Critere);
end;
 
var
   ListFiltre: TList&lt;TPersonne&gt;;
   i: integer;
begin
   try
      try
         List := TListPersonne.Create(True);
 
         List.Add(TPersonne.Create('Arnaud', 10));
         List.Add(TPersonne.Create('Pierre', 20));
         List.Add(TPersonne.Create('David',  50));
 
         Readln;
 
         ListFiltre := List.GetPersonne(tpMajeur);
 
         Writeln('Récupération des personnes majeures');
         for i := 0 to ListFiltre.Count - 1 do
         begin
            Writeln(Format('%s est majeur', [ListFiltre[i].Name]));
         end;
 
         Readln;
      finally
         FreeAndNil(ListFiltre);
         FreeAndNil(List);
      end;
 
      Readln;
   except
      on E: Exception do
         Writeln(E.ClassName, ': ', E.Message);
   end;
end.

Créer un menu pour android

Tout d’abord nous allons créer un TLayout (LytMenu) et ajouter un TFloatAnimation (faMenu) dessus. Notre layout contient un rectangle et une listbox pour afficher les options du menu.

Ensuite un TRectangle (RecMenuHelper) est ajouté directement sur la TForm.

Lors du clic sur le bouton pour afficher le menu, celui-ci glisse de la gauche vers la droite, le helper vient se positionner sur la droite du menu pour intercepter la fermeture du menu si l’utilisateur ne clic pas sur une option.

Nous allons créer une propriété MenuVisible.

private
   FMenuVisible: boolean;
   procedure SetMenuVisible(const Value: boolean);
 
   property MenuVisible: boolean read FMenuVisible write SetMenuVisible;

Dans la FormCreate nous allons masquer le menu

procedure TForm1.FormCreate(Sender: TObject);
begin
   FMenuVisible          := False;
   LytMenu.Visible       := False;
   RecMenuHelper.Visible := False;
end;

Nous allons ajouter un événement OnClick sur le helper qui va masquer le menu.

procedure TForm1.RecMenuHelperClick(Sender: TObject);
begin
   MenuVisible := False;
end;

Le bouton pour afficher le menu est identique sauf que la valeur est True.

La méthode pour afficher ou masquer le menu est SetMenuVisible.

procedure TForm1.SetMenuVisible(const Value: boolean);
begin
   if FMenuVisible &lt;&gt; Value then
   begin
      // afficher menu
      if Value then
      begin
         LytMenu.Height := ClientHeight;
         LytMenu.Width  := ClientWidth div 4 * 3;
 
         LytMenu.Position.Y := 0;
         LytMenu.Position.X := -LytMenu.Width;
 
         LytMenu.Visible := True;
         LytMenu.BringToFront;
         faMenu.StartValue := LytMenu.Position.X;
         faMenu.StopValue  := 0;
         faMenu.Start;
      end
      // cacher menu
      else
      begin
         faMenu.StartValue := 0;
         faMenu.StopValue  := -LytMenu.Width;
         faMenu.Start;
         RecMenuHelper.Visible := False;
      end;
 
      FMenuVisible := Value;
   end;
end;

Pour finir, sur la méthode OnFinish du TFloatAnimation nous allons afficher le helper.

procedure TForm1.faMenuFinish(Sender: TObject);
begin
   if FMenuVisible then
   begin
      RecMenuHelper.Height := ClientHeight;
      RecMenuHelper.Width  := ClientWidth - LytMenu.Width;
 
      RecMenuHelper.Position.Y := 0;
      RecMenuHelper.Position.X := LytMenu.Width;
 
      RecMenuHelper.BringToFront;
      RecMenuHelper.Visible := True;
   end
   else
   begin
      LytMenu.Visible := False;
   end;
end;

Déployer une base de données

Pour déployer une base de données sur un périphérique Android vous pouvez vous rendre sur le précédent article ici.

Télécharger des images

Pour télécharger des images nous allons utiliser les composants Indy.

Créer initialement en 1993 Indy (Internet Direct) est un projet open source développé par des volontaires avec l’aide de sponsors. Il est porté sur Delphi en 1995. En 2001 Borland accorde des licences à Indy pour les intégrer dans Delphi 6 et en 2011 il est mis à jour pour prendre en charge le développement multiplateforme sous Firemonkey (XE2 iOS et OSX), en 2014 pour Android.

Ils offrent des composants utilisant les protocoles TCP, UDP, FTP, http, …

Le composant TIdHTTP permet de récupérer des données (GET) et de les sauvegarder dans un flux (Stream).

var
   IdHTTP: TIdHTTP;
   MS : TMemoryStream;
begin
   IdHTTP := TIdHTTP.Create(nil);
   MS     := TMemoryStream.Create;
   try
      IdHTTP.Get('http://rammsteintrade.free.fr/wk/img/thumb/10200.jpg', MS);
 
      Image1.Bitmap.LoadFromStream(MS);
   finally
      MS.Free;
      IdHTTP.Free
   end;
end;

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

*