Accéder au contenu principal

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.

Commentaires

Posts les plus consultés de ce blog

Toshiba AC100 et Android 4

Toshiba AC100 est un smartbook. Toshiba est la seule grosse entreprise qui a commercialisé un smartbook, malgré que plusieurs autres en aient présenté. Un smartbook est similaire à un netbook (taille) en plus d'avoir des caractéristiques souvent proche à un mobile (GPS, 3g, processeur ARM, autonomie). Le Toshiba AC100 utilisait le système d'exploitation Android en version 2.1. Toshiba a effectué une mise à jour Android 2.2. Il a arrêté la commercialisation et le support de cette machine. L'appareil ayant un bon rapport qualité/prix, la communauté le prit en charge. Il est possible d'installer une version beaucoup plus récente d'Android telle que la 4.1. La rom alternative Cyanogen a été utilisée pour ce portage. Les procédures citées ont été faites sous Linux.  Sous Windows, il faut télécharger une version de nvflash pour ce système. Préparation Télécharger les fichiers: cm_ac100-ota-eng.cm10-beta2.zombah.zip recovery.ac100-cm10_beta2.img via ce...

Spring data jpa et Hibernate’s Warning “firstResult/maxResults specified with collection fetch”

Nous verrons dans cet article comment corrigé le problème  Hibernate’s Warning “firstResult/maxResults specified with collection fetch” qui peut survenir lorsqu'il y a un fetch d'effectuer et qu'il y a du paging. Nous utiliserons spring data jpa. Détail structure Imaginons une relation 1 à plusieurs Lorsqu'on obtient un parent, on désire obtenir aussi sa liste d'enfants. En sql, il y aurait une jointure à effectuer. Il est question d'une recherche avancé où on pourrait recherche par plusieurs critères. Spécification Création d'une spécification pour construire une requête dynamique @Component public class ParentSpecification {     public Specification<Parent> recherche(RechercheParent recherche) {         return (root, cq, cb) -> {             Join<Parent, enfant> enfantJoin;              List<Predicate> rootPredicates = new ArrayList<>();       ...

Migration d’une application Spring Boot 2.2 vers Spring Boot 4.0 : retour d’expérience concret

 En 2019, nous avons développé une application métier basée sur : Java 8 Spring Boot 2.2.7 Gradle 6.6.1 Thymeleaf Bootstrap 4.3.1 Environ 40 000 lignes de code Java Fin 2025, voici un retour d’expérience concret sur la migration vers : Java 25 Spring Boot 4.0.1 Gradle 9.2.1 La partie thymeleaf, n'a pas été touché, il y a quelques warning concernant l'obsolescence de certain commande tel que th:include. Une migration plus rapide que prévu Un point important : en moins de 30 minutes, l’application démarrait sur la nouvelle stack. Évidemment, "ça démarre" ne veut pas dire "tout fonctionne", mais ce premier jalon est très révélateur : la base Spring Boot reste solide les outils de migration sont matures la dette technique était maîtrisée Les changements majeurs rencontrés De javax.* à jakarta.* C’est probablement le changement le plus visible. Tous les imports javax.* doivent être migrés ve...