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

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 n'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és 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 records de la même taille que TMessage, mais avec des valeurs de types 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

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 ni 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.