samedi 30 juin 2001

Création d'un composant

CRÉATION D'UN COMPOSANT

Beaucoup de composants visuel et non visuel existent pour Delphi. Il peut arriver que ces composants ne nous conviennent pas pour diverses raisons. On peut alors utiliser le composant existant et lui ajouter des fonctionnalités. Nous allons créer un composant qui défilera du texte à l'écran, un peu à la manière d'un générique au cinéma. Le composant fonctionnera sous Windows et Linux grâce à la CLX.

Nous allons utiliser l'expert Delphi pour créer le squelette du composant. Il faut cliquer dans le menu «component», ensuite cliquez sur «New component...». L'expert Delphi apparait, on doit sélectionner l'ancêtre de notre composant, c'est à dire son parent. Notre composant héritera de ses fonction et méthode. L'ancêtre de notre composant est le TCustomPanel et le nom de la classe choisie est TUnitTextSequence.


Squelette du composant

Lorsqu'on valide, Delphi nous génère le code.



La procédure Register permettra à notre composant d'être inséré dans la liste des composants disponible sous delphi. Le composant se trouvera dans l'onglet Sample. Vous pouvez modifier cette valeur pour le mettre dans un autre onglet.

Champs

Afin de rendre le composant un peu plus intéressant, quelques champs sont ajoutés au composant. Une image de fond, la vitesse de défilement du texte ainsi que le texte sont des éléments de la classe. Ces champs sont privés afin de ne pas être utilisé directement par une autre classe externe à l'unité.

private
     FAlignment:TAlignment;           //alignement du texte
     FFond:TPicture;                  //image de fond pour le composant
     FTexte:TStringList;              //ligne pour l'animation
     FSpeedMove:Integer;              //Vitesse que le texte bougera
     FTimer:TTimer;                   //Le timer pour l'animation
     FMinMove:Integer;                //Point le plus haut où l'animation peut aller
     FMaxMove:Integer;                //Point le plus bas où l'animation peut se rendre
     FMove:Integer;                   //Le déroulement courant au millième de pixel près

Procédure

Ces champs doivent pouvoir être modifié. Leur valeur doit être changée. Nous allons créer quelques procédures qui permettront de modifier la valeur de certains champs.

protected
    { Déclarations protégées }
     procedure FondItemChange(ASender:TObject); {Quant FFond ou FItems sont modifiés}
     procedure SetAlignment(AAlignment:TAlignment);
     procedure SetFond(AFond:TPicture); virtual; {Losrqu'une affectation à Fond est fait: réf. property Fond}
     procedure SetTexte(ATexte:TStringList); virtual; {Lorsqu'une affecation à Items est effectuée: réf. property Items}
     procedure SetSpeedMove(ASpeedMove:integer); {Losrque l'utilisateur effectue un changement de vitesse de déroulement}
     procedure TimerTimer(Sender:TObject);virtual; {Quant FTimer a un événement selon l'intervalle de temps}

Propriété

Une propriété définie un attribut d'un objet. Elle permet d'associer une action à la lecture et modification de ses données Ces propriétés sont affichées dans l'inspecteur d'objet, car elles sont déclarées «published».

published
    { Déclarations publiées }
     property Alignment:TAlignment read FAlignment write SetAlignment;
     property Color;
     property Font;
     property Fond:TPicture read FFond write SetFond;
     property Texte:TStringList read FTexte write SetTexte;
     property SpeedMove:integer read FSpeedMove write SetSpeedMove;

Initiation du composant

Tel que vue dans le tutoriel sur la programmation orientée objet, un objet doit être initialisé avant d'être utilisé. Un constructeur doit être créé.

public
    { Déclarations publiques }
     constructor Create(AOwner:TComponent); override;
     destructor Destroy;override;
     procedure Paint; override; {la méthode responsable du redessinement}
     procedure SetBounds(ALeft,ATop,AWidth,AHeight:Integer); override; {Pour réactualiser la zone virtuelle de 
     déroulement sur un redimensionnement du composant}
     procedure SetRect1(var R: TRect; xLeft, yTop, xRight, yBottom: integer);

Dans la partie implémentation
constructor TTextSequence.Create(AOwner:TComponent);
begin
  inherited Create(AOwner); {Appele de méthode de son parent}
  FAlignment:=taCenter;
  Height:=150;
  Width:=100;
  FFond:=TPicture.Create;
  FTexte:=TStringList.Create;
  FTimer:=TTimer.Create(self);
  FFond.OnChange:=FondItemChange;  {Quand l'image de fond change, alors appelle de notre méthode FondItemChange}
  FTexte.OnChange:=FondItemChange; {Même chose pour les lignes d'animation}
  FMove:=0; {point de départ de l'animation au début}
  FTimer.OnTimer:=TimerTimer; {notre méthode TimerTimer sera appelée par FTimer}
  FTimer.Interval:=75; {1 = 1 ms environ}
  SpeedMove:=500; {vitesse de départ par défaut: peut-être autre chose si tu veux}
end;

Destuction du composant

Les éléments que nous avons créés dynamiquement doivent être libéré. Nous en avons créé 3 dans le constructeur.

destructor TTextSequence.Destroy;
begin
  FFond.Free;
  FTexte.Free;
  FTimer.Free;
  inherited Destroy;  {Appele le destructeur hérité}
end; 

Méthode

Le composant possède quelques méthodes, nous allons-nous attarder sur la méthode de dessinèrent. Cette méthode permet de rafraîchir le composant. Puisque le texte défile, le composant doit être constamment rafraichi.

procedure TTextSequence.Paint;
var
  DrawLine:integer;
  i:integer;
  Bitmap:TBitmap;
  Rectangle:TRect;
begin
  Bitmap:=TBitmap.Create;
  Bitmap.Width:=Width;     {largeur du bitmap}
  Bitmap.Height:=Height;   {Hauteur du bitmap}
  Bitmap.Canvas.Brush.Style:=bsSolid;
  Bitmap.Canvas.Brush.Color:=Color;
  SetRect1(Rectangle,0,0,ClientWidth,ClientHeight);
  Bitmap.Canvas.FillRect(Rectangle);
  if Assigned(FFond.Graphic) then
    if not FFond.Graphic.Empty then
      Bitmap.Canvas.StretchDraw(Rectangle,FFond.Graphic);
  Bitmap.Canvas.Brush.Style:=bsClear;
  Bitmap.Canvas.Font.Assign(Font);
  if FTexte.Count>0 then begin {si on a des lignes en animation}
    DrawLine:=FMove div 1000; {Nous conservons le déplacement au millième près}
    for i:=0 to Pred(FTexte.Count) do
    begin
      {calculs de l'affichage de la prochaine ligne d'animation}
      DrawLine:=DrawLine+Bitmap.Canvas.TextHeight(FTexte[i]);
      {si l'affichage est visible} 
      if (DrawLine>-Bitmap.Canvas.TextHeight(FTexte[i])) and (DrawLine<Height)  then
         case Alignment of
              TALeftJustify: Bitmap.Canvas.TextRect(Rectangle,Rectangle.Left+2,DrawLine,FTexte[i]);
              TARightJustify:Bitmap.Canvas.TextRect(Rectangle,
                Rectangle.Right-Bitmap.Canvas.TextWidth(FTexte[i])-2,DrawLine,FTexte[i]);
              TACenter:Bitmap.Canvas.TextRect(Rectangle,(Width div 2)-
                (Bitmap.Canvas.TextWidth(FTexte[i]) div 2),DrawLine,FTexte[i]);
         end;
    end;
  end;
  Canvas.Draw(0,0,Bitmap);{Dessine le bitmap en mémoire sur le canvas}
  Bitmap.Free;           {Libère l'objet de la mémoire}
end;

La méthode commence par créer un Bitmap, il servira à afficher le 
texte. On créer une zone de la dimension
du contrôle. On vérifie s'il a mouvement, on calcule la prochaine ligne 
et on ajuste l'alignement. Il est
possible d'augmenter la fluidité en diminuant la valeur du déplacement. 
Par défaut c'est 1000, une valeur plus faible
peut être mise. De plus, il est possible d'augmenter la valeur de 
l'intervalle du timer. Le composant se redessinera moins souvent
avec une valeur plus élevée.

Vous pouvez remarquer dans le code, que la méthode invalidate est utilisée. Cette méthode permet de redessiner le contrôle. La méthode paint à été définie comme override. Le composant n'appellera donc pas la méthode pain du parent du composant, mais cette qu'on a redéfini.

Au fur à mesure qu'on code un programme, on y décèle des problèmes. Afin de diminuer d'éventuel problème avec les composants existants, vous pouvez utiliser le composant tel qu'un objet. Il suffit de créer un programme, d'y ajouter l'unité de votre composant et de l'utiliser. Dans l'exemple ci-dessous, nous utilisons un trackbar pour diminuer ou augmenter la vitesse. La vitesse courante est affiché dans un label.



Lorsque vous pensez que votre composant être excent de problème, vous pouvez l'installer dans l'edi de Delphi. Il suffit de cliquer dans le menu Component ensuite sur Install component. Vous spécifiez le nom de l'unité. Le composant trouve alors dans l'onglet spécifié par la méthode register. Une fois que le composant est installé, vous n'avez qu'à le glisser sur la fiche pour l'utiliser.



Il est sage d'étudier les composants existants, les modifier afin dans créer de nouveau. Nous avons vue comment créer un composant visuel. D'autres fonctionnalités pourraient être ajoutées. Pratiquez-vous!

Un programme utilisant le composant est disponible ici

Je remercie Daniel Drouin de m'avoir initié à la programmation sous Delphi et de m'avoir initié à la programmation de composant à l'aide de cet exemple.