Partie III : Créer un composant graphique


précédentsommairesuivant

VIII. Propriétés héritées

Le fait que nous ayons hérité d'une classe abstraite fait que toutes les propriétés classiques des contrôles ne sont pas présentes.

Heureusement, nous n'avons pas besoin de les implémenter : elles existent, mais cachée (protégées ou publiques selon les cas).

La classe TControl propose des dizaines de propriétés protégées et publiques, qu'il ne tient qu'à vous de rendre publiées.

Il est facile de rendre les propriétés protégées et publiques publiées. Il suffit de les redéclarer, avec juste le mot-clef property et le nom de la propriété, sans son type ni ses accès.

Vous pouvez choisir les propriétés que vous voulez rendre publiées. Dans notre exemple, nous utiliserons les propriétés suivantes. Vous remarquerez qu'il est possible de modifier les propriétés par défaut ou les spécifications de stockage. Nous utiliserons cette technique pour les propriétés Color (rappelez-vous que nous avons mis clNone dans le constructeur), ParentColor (puisque le fait de modifier la propriété Color entraîne la mise à False de ParentColor) et AutoSize (dont nous n'avons pas encore parlé).

 
Sélectionnez

published
  property AutoSize default True;
  property Color default clNone;
  property DragKind;
  property DragCursor;
  property DragMode;
  property ParentBiDiMode;
  property ParentColor default False;
  property ParentShowHint;
  property PopupMenu;
  property Align;
  property Anchors;
  property BiDiMode;
  property Constraints;
  property DockOrientation;
  property ShowHint;
  property Visible;

  property OnClick;
  property OnConstrainedResize;
  property OnContextPopup;
  property OnDblClick;
  property OnDragDrop;
  property OnDragOver;
  property OnEndDock;
  property OnEndDrag;
  property OnMouseActivate;
  property OnMouseDown;
  property OnMouseMove;
  property OnMouseUp;
  property OnMouseWheel;
  property OnMouseWheelDown;
  property OnMouseWheelUp;
  property OnResize;
  property OnStartDock;
  property OnStartDrag;
			

Nous allons tout de suite modifier le constructeur pour positionner AutoSize à True.

 
Sélectionnez

constructor TCircleChart.Create(AOwner : TComponent);
begin
  inherited;
  FClickedQuarter := -1;
  AutoSize := True;
  Color := clNone;
  FSpoke := 100;
  FBrush := TBrush.Create;
  FBrush.OnChange := GraphicsChange;
  FPen := TPen.Create;
  FPen.OnChange := GraphicsChange;
  FQuarters := TChartQuarters.Create(Self);
  FBaseAngle := 90;
end;
			

IX. Effet de la propriété AutoSize

Il est temps de nous intéresser à la façon dont AutoSize fait effet. Comment savoir en effet comment redimensionner le contrôle, ni même quand le faire ?

Dans TControl, il existe une méthode AdjustSize virtuelle qui doit redimensionner le contrôle en fonction des diverses propriétés. Voilà la réponse à notre première question.

Pour ce qui est de la deuxième, c'est simple : lorsque AutoSize est positionnée à True, la méthode AdjustSize est appelée (cela se fait automatiquement). De plus, dans les setter des propriétés influant sur la taille, il vous suffit d'appeler vous aussi AdjustSize.

Notre taille sera contrôlée par la propriété Spoke : la largeur et la hauteur n'ont aucune raison d'être différentes du double de cette propriété.

Nous allons donc modifier la méthode SetSpoke pour ajouter un appel à AdjustSize :

 
Sélectionnez

procedure TCircleChart.SetSpoke(New : integer);
begin
  if New <= 0 then exit;
  FSpoke := New;
  if AutoSize then AdjustSize;
  Invalidate;
end;
			

Nous allons également surcharger la méthode AdjustSize pour faire correspondre la taille avec le rayon du disque.

 
Sélectionnez

protected
  procedure AdjustSize; override;
			

Son implémentation est plus que simple. Mais il ne faut pas oublier à veiller que l'on est pas en train de charger le composant à partir d'un flux, au risque d'interférer avec les valeurs enregistrées.

 
Sélectionnez

procedure TCircleChart.AdjustSize;
begin
  if not (csLoading in ComponentState) then
  begin
    Width  := Spoke*2;
    Height := Spoke*2;
  end;
end;
			

X. Améliorer le système de menu pop-up

Le simple fait d'avoir rendu publiée la propriété PopupMenu a fait que l'on peut lui assigner un menu pop-up qui surgira automatiquement en cas de clic droit.

Toutefois, il est impossible, pour l'instant, à l'application de savoir sur quel quartier on a enfoncé le bouton droit, ce qui pourrait toutefois être très utile.

Nous allons donc surcharger la méthode DoContextPopup déclarée elle aussi dans TControl. Cette méthode appelle le gestionnaire d'événement OnContextPopup, mais permet aussi d'effectuer des actions avant que le menu soit affiché.

 
Sélectionnez

protected
  procedure DoContextPopup(MousePos : TPoint; var Handled : boolean); override;
			

Dans cette méthode, nous allons renseigner une variable privée FPopupQuarter de type TChartQuarter avec le quartier se trouvant à la position MousePos. Nous ajouterons une propriété publique en lecture seule pour que l'application puisse accéder à cette information.

 
Sélectionnez

private
  FPopupQuarter : TChartQuarter;
public
  property PopupQuarter : TChartQuarter read FPopupQuarter;
			

Nous initialiserons cette variable à nil dans le constructeur :

 
Sélectionnez

constructor TCircleChart.Create(AOwner : TComponent);
begin
  inherited;
  FClickedQuarter := -1;
  FPopupQuarter := nil;
  Color := clNone;
  FSpoke := 100;
  FBrush := TBrush.Create;
  FBrush.OnChange := GraphicsChange;
  FPen := TPen.Create;
  FPen.OnChange := GraphicsChange;
  FQuarters := TChartQuarters.Create(Self);
  FBaseAngle := 90;
  AutoSize := True;
end;
			

Voici l'implémentation de DoContextPopup :

 
Sélectionnez

procedure TCircleChart.DoContextPopup(MousePos : TPoint; var Handled : boolean);
begin
  FPopupQuarter := PointToQuarter(MousePos);
  inherited;
end;
			

XI. Afficher un hint selon le quartier pointé

Il reste une dernière chose à faire : nous n'avons pas encore utilisé la propriété Hint de TChartQuarter.

Le but que nous poursuivons est que dans le cas où la souris stationne au-dessus d'un quartier, ce soit le hint de ce quartier qui soit affiché en lieu et place du hint du TCircleChart.

Tous les cas que nous avons rencontré jusqu'à présent ont pu être réglés grâce à la VCL. Malheureusement, ce n'est pas le cas de ce nouveau problème !

Nous devrons donc nous débrouiller autrement. Dans ce genre de cas, une étude des sources de la VCL pourra souvent se révéler très instructive sur la manière de procéder.

Après une étude intensive de ces sources, j'ai remarqué qu'il était possible d'implémenter cette fonctionnalité en interceptant le message CM_HINTSHOW.

Pour intercepter un message Windows (envoyé via SendMessage ou PostMessage), il faut écrire une méthode qui possède la directive message. Ce type de méthode doit accepter un unique paramètre variable (var) mais son type peut être quelconque ; en pratique, il se nomme Message et de type TMessage ou TWMXXX ou TCMXXX. Ces TWMXXX et TCMXXX sont des record de la même taille que TMessage mais avec des valeurs de type différents, permettant de récupérer plus facilement la signification des paramètres L et R du message. Ces méthodes sont très souvent privées.

Le message qu'intercepte la méthode est déterminé par une constante d'identificateur de message placée après la directive message. Par exemple : message WM_LBUTTONDOWN;

Nous déclarerons donc une méthode CMHintShow privée comme suit :

 
Sélectionnez

private
  procedure CMHintShow(var Message : TCMHintShow); message CM_HINTSHOW;
			

Cette méthode sera appelée automatiquement lorsque notre contrôle interceptera un message de type CM_HINTSHOW.

Dans le code d'implémentation de telles méthodes, on peut utiliser l'instruction inherited, bien qu'elles ne soient pas des méthodes surchargées, pour appeler la méthode correspondante (qui ne porte pas forcément le même nom ni n'accepte le même paramètre, mais qui intercepte le même message) dans la plus proche classe parente qui en possède une.

Notre méthode CMHintShow devra, si la position de la souris (récupérée grâce à Message.HintInfo.CursorPos) se trouve sur un quartier qui possède un hint, modifier le champ Message.HintInfo.HintStr pour refléter cette valeur.

 
Sélectionnez

procedure TCircleChart.CMHintShow(var Message : TCMHintShow);
var Quarter : TChartQuarter;
begin
  inherited;
  if Message.Result <> 0 then exit;
  Quarter := PointToQuarter(Message.HintInfo.CursorPos);
  if Assigned(Quarter) and (Quarter.Hint <> '') then
    Message.HintInfo.HintStr := Quarter.Hint;
end;
			

précédentsommairesuivant

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

Tutoriels
Les génériques avec Delphi 2009 Win32 (English version) - également disponible en espagnol et en russe
Réaliser un plug-in comportant un composant
Construire une procédure pointant sur une méthode
Création de composants - en 4 parties
Refactoring avec Delphi 2007
Prise en main de Delphi 2005
Analyseurs syntaxiques - Leur fonctionnement par l'exemple
Créer un fichier d'aide HLP
Pourquoi un paramètre const change-t-il mystérieusement de valeur ?
Sources
SJRDUnits - Routines et classes diverses
SJRDComps - Quelques composants
Projet Sepi
Présentation
FAQ Sepi
Programmes
FunLabyrinthe - Jeu de labyrinthe très spécial et très fun
TrickTakingGame - Jeux de cartes à plis en ligne
MultiAgenda - Agenda multi-répertoires
DecodeFormulaires - Décode les formulaires
Excel --> HTML - Convertisseur de tableaux Excel en HTML
AddressLinks - Lie les adresses Internet et e-mail d'un document HTML
Vipion - Tic Tac Toe sur 4x4 cases avec jeu de l'ordinateur
BigCalc - Calculatrice de haut niveau
Espace paroissial Astérion de Watermael-Boitsfort
  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2005 Sébastien Doeraene. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.