Developpez.com - C
X

Choisissez d'abord la catégorieensuite la rubrique :



Création d'un composant C++ Builder

Par CGi

Le 8 juin 2003


2 - Création d'un composant graphique.


Dans cet exemple nous allons créer un composant horloge de type analogique.

La procédure de création est la même que dans la première partie, nous ne reviendrons donc pas dessus. La seule différence est que notre composant descend de TGraphicControl. TGraphicControl est l'ancêtre de nombreux contrôles graphiques légers, n'ayant pas besoin des entrées clavier ou de contenir d'autre contôles. Il possède une propriété Canvas pour dessiner et une méthode virtuelle Paint pour l'actualisation les dessins. TLabel est un descendant de TGraphicControl.


Code :

Fichier "horloge.h"

#ifndef HorlogeH
#define HorlogeH
//---------------------------------------------------------------------------
#include <SysUtils.hpp>
#include <Controls.hpp>
#include <Classes.hpp>
//---------------------------------------------------------------------------
class PACKAGE THorloge : public TGraphicControl
{
private:
        TTimer *Timer1;
        Graphics::TBitmap *Image1;
        bool FSec;
        bool __fastcall CanResize(int &NewWidth, int &NewHeight);
protected:
        void __fastcall Tempo(TObject* Owner);
        void __fastcall Paint();
public:
        __fastcall THorloge(TComponent* Owner);
        virtual __fastcall ~THorloge();
__published:
        __property Anchors;
        __property ParentShowHint;
        __property ShowHint;
        __property Visible;

        __property bool Seconde = {read=FSec, write=FSec, default=true};
};
//---------------------------------------------------------------------------
#endif

Dans le fichier en-tête "horloge.h" partie private nous déclarons un pointeur Timer1 sur un TTimer qui donnera le tempo de rafraîchissement du dessin, un pointeur sur un TBitmap qui nous servira de support pour dessiner, une donnée membre booléenne FSec qui mémorisera la propriété Seconde pour l'affichage de l'aiguille des secondes, une méthode Tempo pour actualiser le dessin des aiguilles, puis les méthodes CanResize et Paint en vue de les redéfinir. Dans la partie public nous déclarons le destructeur de notre composant. Dans la partie __published nous déclarons les propriétés que l'on veut rendre visible et la nouvelle propriété Seconde qui nous permettra d'afficher ou ne pas afficher l'aiguille des secondes.


Fichier "horloge.cpp"

#include <vcl.h>
#include <math.h>  //rajouté manuellement pour sin, cos.
#pragma hdrstop
#include "Horloge.h"
#pragma package(smart_init)
//---------------------------------------------------------------------------
// ValidCtrCheck est utilisé pour vérifier que les composants créés n'ont
// aucune fonction virtuelle pure
//

static inline void ValidCtrCheck(THorloge *)
{
        new THorloge(NULL);
}
//---------------------------------------------------------------------------

__fastcall THorloge::THorloge(TComponent* Owner)
        : TGraphicControl(Owner)
{
       ControlStyle << csOpaque;
       Image1 = new Graphics::TBitmap();
       Timer1 = new TTimer(NULL);
       Timer1->OnTimer = Tempo;
       FSec=true;
       Width = 120;
       Height = 120;
       Image1->Width = Width;
       Image1->Height = Height;
}
//---------------------------------------------------------------------------
__fastcall THorloge::~THorloge()
{
      delete Image1;
      delete Timer1;
}
//---------------------------------------------------------------------------
// Pour ne pas changer les dimensions du composant.
bool __fastcall THorloge::CanResize(int &NewWidth, int &NewHeight)
{
       NewWidth = 120;
       NewHeight = 120;
       return true;
}
//---------------------------------------------------------------------------
// Rafraichissement du dessin selon le tempo.
void __fastcall THorloge::Tempo(TObject* Sender)
{
       Invalidate();
}
//---------------------------------------------------------------------------
//Dessin du composant
void __fastcall THorloge::Paint()
{
      float n,z,u,x0,y0,x1,y1,x2,y2,x3,y3;
      TDateTime heure;
      TPoint points[4];
      Word wHour, wMinute, wSeconde;

      heure = Now();
      DecodeTime(heure, wHour, wMinute, wSeconde, NULL);

      // Couleur de fond.
      Image1->Canvas->Brush->Color = Color;
      Image1->Canvas->Pen->Color = Color;
      Image1->Canvas->Rectangle(0,0,Image1->Width,Image1->Height);

      // Dessin du cercle.
      Image1->Canvas->Pen->Color = clBlack;
      Image1->Canvas->Pen->Width = 2;
      Image1->Canvas->Ellipse(2,2,118,118);

      // Dessin du texte.
      Image1->Canvas->Font->Name = "Arial";
      Image1->Canvas->Font->Color = clBlack;
      Image1->Canvas->Font->Size = 8;
      Image1->Canvas->TextOut( 50,80,"CGi");

      Image1->Canvas->TextOut( 55,6,"12");
      Image1->Canvas->TextOut( 58,101,"6");
      Image1->Canvas->TextOut( 8,53,"9");
      Image1->Canvas->TextOut( 105,53,"3");

      Image1->Canvas->TextOut( 81,13,"1");
      Image1->Canvas->TextOut( 97,30,"2");

      Image1->Canvas->TextOut( 98,76,"4");
      Image1->Canvas->TextOut( 81,94,"5");

      Image1->Canvas->TextOut( 33,94,"7");
      Image1->Canvas->TextOut( 15,76,"8");

      Image1->Canvas->TextOut( 14,30,"10");
      Image1->Canvas->TextOut( 32,13,"11");

      Image1->Canvas->Pen->Width = 1;

      // Dessin aiguille des secondes si FSec à true.
      if (FSec)
       {
        n = wSeconde*200/60;
        z = n/100*3.14159;
        u = (n+50)/100*3.14159;

        x0 = sin(z)*50;
        y0 = -cos(z)*50;

        x1 = -sin(z)*10;
        y1 = cos(z)*10;

        x2 = sin(u)*2;
        y2 = -cos(u)*2;

        x3 = -sin(u)*2;
        y3 = cos(u)*2;

        points[0] = Point(x1+60,y1+60);
        points[1] = Point(x2+60,y2+60);
        points[2] = Point(x0+60,y0+60);
        points[3] = Point(x3+60,y3+60);

        Image1->Canvas->Brush->Color = clRed;
        Image1->Canvas->Polygon(points, 3);
       }

      // Dessin aiguille des minutes.
      n = wMinute*200/60 + wSeconde*200/60/60;
      z = n/100*3.14159;
      u = (n+50)/100*3.14159;

      x0 = sin(z)*50;
      y0 = -cos(z)*50;

      x1 = -sin(z)*10;
      y1 = cos(z)*10;

      x2 = sin(u)*4;
      y2 = -cos(u)*4;

      x3 = -sin(u)*4;
      y3 = cos(u)*4;

      points[0] = Point(x1+60,y1+60);
      points[1] = Point(x2+60,y2+60);
      points[2] = Point(x0+60,y0+60);
      points[3] = Point(x3+60,y3+60);

      Image1->Canvas->Brush->Color = clAqua;
      Image1->Canvas->Polygon(points, 3);

      // Dessin aiguille des heures.
      n = wHour*200/12 + wMinute*200/60/12;
      z = n/100*3.14159;
      u = (n+50)/100*3.14159;

      x0 = sin(z)*35;
      y0 = -cos(z)*35;

      x1 = -sin(z)*10;
      y1 = cos(z)*10;

      x2 = sin(u)*4;
      y2 = -cos(u)*4;

      x3 = -sin(u)*4;
      y3 = cos(u)*4;

      points[0] = Point(x1+60,y1+60);
      points[1] = Point(x2+60,y2+60);
      points[2] = Point(x0+60,y0+60);
      points[3] = Point(x3+60,y3+60);

      Image1->Canvas->Brush->Color = clYellow;
      Image1->Canvas->Polygon(points, 3);

      Canvas->Draw(0,0,Image1);
}
//---------------------------------------------------------------------------
namespace Horloge
{
        void __fastcall PACKAGE Register()
        {
                 TComponentClass classes[1] = {__classid(THorloge)};
                 RegisterComponents("MesCompo", classes, 0);
        }
}


Passons maintenant en revue l'implémentation de notre composant, fichier horloge.cpp:

Dans le constructeur: Nous ajoutons à la propriété ControlStyle de notre composant l'attribut csOpaque, cela évite de petits scintillements résiduels. Nous créons le Bitmap (Image1). Nous créons le Timer Timer1 et nous assignons la méthode Tempo à l'événement OnTimer de Timer1, la propriété Interval du Timer étant à une seconde par défaut nous ne la changeons pas, cela correspond à l'intervalle de rafraîchissement de notre horloge. La donnée membre FSec est initialisée à true, l'aiguille des secondes étant visible par défaut. Puis nous définissons les dimensions du composant et du Bitmap.

Dans la définition de la méthode Tempo nous allons appeler la méthode Invalidate ce qui va rafraîchir le dessin notre horloge toutes les secondes. Tempo est appelée par l'événement OnTimer de Timer1.

La méthode CanResize retourne par référence toujours les mêmes dimensions, car notre composant a des dimensions fixes que l'on ne pourra changer.

La partie dessin à proprement parler se trouve dans la méthode Paint. Cette méthode est appelée à chaque fois que notre composant doit être redessiné, soit parce qu'il a été caché par une autre fenêtre, soit toutes les secondes pour afficher la nouvelle position des aiguilles. Dans un composant graphique on dessine toujours sur la méthode Paint. Elle est appelée par un message (WM_PAINT) envoyé par Windows quand cela est nécessaire.

Pour éviter l'effet de scintillement nous dessinerons sur un bitmap (TBitmap) auquel nous avons accès par le pointeur Image1 et qui sera restitué à l'écran une fois le dessin terminé par la méthode Draw du canvas de notre composant. En ce qui concerne le dessin sur le Bitmap Image1 nous dessinons de façon classique à l'aide de son Canvas donc sans commentaire. Les aiguilles sont dessinées avec la méthode Polygon dont les coordonnées sont calculées à l'aide des fonctions trigonométriques sin et cos. La méthode Polygon a comme arguments un pointeur sur un tableau de TPoint qui contient les coordonnées de chaque point du polygone et un int qui contient l'indice du dernier élément du tableau de TPoint.

Dans le destructeur de notre composant nous détruirons les objets Image1 et Timer1.



Ce composant a été compilé et testé sur BCB4 et BCB6.

CGi

Avec la contribution d'Alacazam pour la relecture.

Télécharger les sources.
(Est inclus le fichier "horloge.dcr" contenant l'icône qui le représente sur la palette de composants)





Sommaire

1 - Création d'un composant pas à pas.
2 - Création d'un composant graphique.
3 - Propriété de type TStrings.
4 - Propriété de type TBitmap et contrôle du Owner.
5 - Propriété de type enum.
6 - Contrôle fenêtré.
7 - Evénement personnalisé et sous-propriétés.
8 - Composant pouvant interagir avec ses semblables.
9 - Ressources dans un composant.
10 - Boîte de dialogue dans un composant.
11 - Composant conteneur.
12 - Les éditeurs de composants. Nouveau



C/C++
  Les pointeurs du C/C++.   Les listes chaînées.             Liste simple.             Liste triée.             Liste double.   Les arbres.   Les tas.   Le C orienté objets ?

  1 - La fenêtre principale.   2 - Contrôles et messages.   3 - Les commandes.   4 - Dialogue std.   5 - Contexte de périph.   6 - Dessiner.   7 - Les ressources.   8 - Dialogue perso.   9 - Dialogue comm.   10 - Les accélérateurs.

Assembleur
  Assembleur sous Visual C++.

C++ BUILDER
  Trucs et astuces.   Composant.   TRichEdit.   TDrawGrid.   Application MDI.   TThread.   wxWidgets.   Style Win XP.

  Première application.   Construire un menu.   Dessiner.   Sisers, Timers...   Dialogues standards.   Dialogues perso.

DotNet
  Composant C# Builder.   Contrôle WinForm.   Application MDI.

Java
  Applet java.





Copyright 2002-2016 CGi - Tous droits réservés CGi. Toutes reproduction, utilisation ou diffusion de ce document par quelque moyen que ce soit autre que pour un usage personnel doit faire l'objet d'une autorisation écrite de la part de l'auteur, propriétaire des droits intellectuels.
Les codes sources de ce document sont fournis en l'état. L'utilisateur les utilise à ses risques et périls, sans garantie d'aucune sorte de la part de l'auteur. L'auteur n'est responsable d'aucun dommage subi par l'utilisateur pouvant résulter de l'utilisation ou de la distribution des codes sources de ce document.
De la même façon, l'auteur n'est en aucun cas responsable d'une quelconque perte de revenus ou de profits, ou de données, ou de tous dommages directs ou indirects, susceptibles de survenir du fait de l'utilisation des codes sources de ce document, quand bien même l'auteur aurait été averti de la possibilité de tels dommages. L'utilisation des codes sources de ce document vaut acceptation par l'utilisateur des termes de la licence ci-dessus.

Contacter le responsable de la rubrique C