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)
|