IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)


Création d'un composant C++ Builder

Par CGi

Le 30 octobre 2003


8 - Composant pouvant interagir avec ses semblables :

Nous allons voir un composant pouvant interagir avec ses frères, l'exemple le plus significatif étant le RadioBoutton qui décoche ses semblables ce trouvant dans le même groupe que lui, quand on le coche.

Le RadioBouton étant le meilleur exemple, nous allons nous aussi construire un RadioBouton. Pour ne pas le faire identique, nous le ferons en forme de losange. Nous le nommerons donc TRadioLosBtn.



Dans cet exemple nous ne commenterons que le code de la méthode SetChecked, le reste du code étant identique au composant TCaseACocher du chapitre 6, mis à part le dessin dans la méthode Paint.

Fichier "RadioLosBtn.h" :

#ifndef RadioLosBtnH
#define RadioLosBtnH
//---------------------------------------------------------------------------
#include <SysUtils.hpp>
#include <Classes.hpp>
#include <Controls.hpp>
//---------------------------------------------------------------------------
class PACKAGE TRadioLosBtn : public TCustomControl
{
private:
        bool FChecked;
        TColor FCouleur;
        bool ALeFocus;
protected:
        void __fastcall Paint();
        DYNAMIC void __fastcall KeyPress(char &Key);
        DYNAMIC void __fastcall DoEnter();
        DYNAMIC void __fastcall DoExit();
        DYNAMIC void __fastcall Click();
        DYNAMIC void __fastcall MouseDown(TMouseButton Button,
                                     Classes::TShiftState Shift, int X, int Y);
        virtual void __fastcall SetChecked (bool Value);
        virtual void __fastcall SetCouleur(TColor Value);
        virtual void __fastcall TextChanged(TMessage &Msg);
BEGIN_MESSAGE_MAP
  MESSAGE_HANDLER(CM_TEXTCHANGED, TMessage, TextChanged)
END_MESSAGE_MAP(TCustomControl)
public:
        __fastcall TRadioLosBtn(TComponent* Owner);
__published:
        __property Caption;
        __property OnClick;
        __property OnEnter;
        __property OnExit;
        __property OnKeyUp;
        __property OnKeyPress;
        __property OnKeyDown;
        __property TabOrder;
        __property TabStop;
   // nouvelles propriétés :
        __property bool Checked = {read=FChecked, write=SetChecked};
        __property TColor Couleur = {read=FCouleur, write=SetCouleur};
};
//---------------------------------------------------------------------------
#endif




Fichier "RadioLosBtn.cpp"

#include <vcl.h>
#pragma hdrstop
#include "RadioLosBtn.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(TRadioLosBtn *)
{
        new TRadioLosBtn(NULL);
}
//---------------------------------------------------------------------------
__fastcall TRadioLosBtn::TRadioLosBtn(TComponent* Owner)
        : TCustomControl(Owner)
{
        Width = 100;
        Height = 21;
        TabStop = true;
        FChecked = false;
        FCouleur = clBlack;
        ALeFocus = false;
}
//---------------------------------------------------------------------------
void __fastcall TRadioLosBtn::Paint()
{
        TPoint points[4];

        points[0] = Point(10,0);
        points[1] = Point(20,10);
        points[2] = Point(10,20);
        points[3] = Point(0,10);
        Canvas->Brush->Color = clWindow;
        Canvas->Pen->Color = clWhite;
        Canvas->Polygon(points, 3);
        Canvas->Pen->Color = clGray;
        Canvas->MoveTo(9,1);
        Canvas->LineTo(0,10);
        Canvas->LineTo(10,20);
        Canvas->Pen->Color = clBlack;
        Canvas->MoveTo(9,2);
        Canvas->LineTo(1,10);
        Canvas->LineTo(10,19);
        Canvas->Pen->Color = clSilver;
        Canvas->MoveTo(10,1);
        Canvas->LineTo(19,10);
        Canvas->LineTo(9,20);

        Canvas->Brush->Color = Color;
        Canvas->TextOut(25,2,Caption);

        if (Checked)
         {
            points[0] = Point(10,5);
            points[1] = Point(15,10);
            points[2] = Point(10,15);
            points[3] = Point(5,10);
            Canvas->Brush->Color = FCouleur;
            Canvas->Pen->Color = FCouleur;
            Canvas->Polygon(points, 3);
         }
        if (ALeFocus)
         {
            Canvas->Brush->Color = Color;
            TRect FocRect;
            FocRect.Top = 1;
            FocRect.Left = 22;
            FocRect.Right = Width - 2;
            FocRect.Bottom = Height - 2;
            Canvas->DrawFocusRect(FocRect);
         }
}
//---------------------------------------------------------------------------
void __fastcall TRadioLosBtn::KeyPress(char &Key)
{
    if (Key == 32) Checked = !Checked;
    TCustomControl::KeyPress(Key);
}
//---------------------------------------------------------------------------
void __fastcall TRadioLosBtn::Click()
{
     TCustomControl::Click();
     Checked = !Checked;
}
//---------------------------------------------------------------------------  
void __fastcall TRadioLosBtn::MouseDown(TMouseButton Button,
                                    Classes::TShiftState Shift, int X, int Y)
{
     SetFocus();
     ALeFocus = true;
     Invalidate();
}  
//---------------------------------------------------------------------------
void __fastcall TRadioLosBtn::DoEnter()
{
     TCustomControl::DoEnter();
     ALeFocus = true;
     Invalidate(); // Pour afficher le rectangle de focus.
}
//---------------------------------------------------------------------------
void __fastcall TRadioLosBtn::DoExit()
{
     TCustomControl::DoExit();
     ALeFocus = false;
     Invalidate(); // Pour éffacer le rectangle de focus.
}
//---------------------------------------------------------------------------
void __fastcall TRadioLosBtn::TextChanged(TMessage &Msg)
{  
     Invalidate(); // Pour afficher la modification du texte.
}
//---------------------------------------------------------------------------
void __fastcall TRadioLosBtn::SetChecked(bool Value)
{
   if (!Focused() || !Checked)
     {
      FChecked = Value;
      if ( Value )
      {
        TRadioLosBtn *Frere;
        for (int x=0 ; x < Parent->ControlCount ; x++)
         {
          if ((AnsiString)Parent->Controls[x]->ClassName() == this->ClassName())
             {
               Frere = (TRadioLosBtn *)Parent->Controls[x];
               if(Frere != this) Frere->Checked = false;
             }
         }
     }
     Invalidate();
     }
}
//---------------------------------------------------------------------------
void __fastcall TRadioLosBtn::SetCouleur(TColor Value)
{
     FCouleur = Value;
     Invalidate();
}
//---------------------------------------------------------------------------
namespace Radiolosbtn
{
        void __fastcall PACKAGE Register()
        {
                 TComponentClass classes[1] = {__classid(TRadioLosBtn)};
                 RegisterComponents("MesCompo", classes, 0);
        }
}

Comme nous l'avons dis plus haut, dans ce document, ce qui nous intéresse se passe dans la méthode SetChecked. Ce que nous voulons obtenir est tout d'abord de le cocher s'il ne l'est pas, ensuite décocher les objets du même type que lui se trouvant dans le même groupe, c'est-à-dire ayant le même parent. Pour les décocher, nous allons énumérer tous les composants contenus dans son Parent, tester s'ils sont du même type que lui et les mettre à false si c'est le cas ; sauf, bien entendu, s'il s'agit de lui même, testé par la condition "if(Frere != this)". Ses frères ne doivent pas exécuter cette boucle, (sinon on aurait des appels de SetChecked jusqu'au débordement de pile) ceci est testé par la condition "if ( Value )", c'est le seul qui à une demande de mise à true. Par contre, s'il est déjà coché, il ne se passe rien, test "if (!Focused() || !Checked)" cette condition n'est pas exécutée si le contrôle détient le focus et est coché.



A bientôt pour la suite,
CGi

Avec la contribution d'Alacazam pour la relecture.

Télécharger les sources.
(Est inclus le fichier "Radiolosbtn.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-2020 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.