Effacer la dernière image dessinée

Résolu
cs_Jean_Jean Messages postés 615 Date d'inscription dimanche 13 août 2006 Statut Membre Dernière intervention 13 décembre 2018 - 29 juil. 2010 à 11:26
cs_MAURICIO Messages postés 2106 Date d'inscription mardi 10 décembre 2002 Statut Modérateur Dernière intervention 15 décembre 2014 - 30 juil. 2010 à 18:07
Bonjour à tous,
Non je ne programme pas sur la plage mais au milieu de mes cartons! Mais si comme je le pense vous avez emmené votre pc sur la plage, vous pourrez peut-être éclaircir un point.

Je suis en train de définir un composant graphique de B-arbre. Le choix des étiquettes des n'uds peut être de différentes formes avec différentes couleurs etc.
Voici l'une des procédures de dessin d'une étiquette de forme circulaire:
{-----------------------------------------
procedure TTreeShape.DrawShadowEtiqCircle;
 var rl,rt,rw,rh: Integer;
begin
  if Shadow then
  begin
    { Calcul dimensions width et height de l'ombre}
    ...
    Canvas.Ellipse(rl,rt,rl+rw,rt+rh);
  end;
end;
procedure TTreeShape.DrawEtiqCircle;
 var rl,rt,rw,rh: Integer;
begin
  { Calcul dimensions width et height de l'étiquette}
  ...
  Canvas.Ellipse(rl,rt,rl+rw,rt+rh);
end;

J'ai donc écrit différentes fonctions, mais je ne sais pas trop ou je dois écrire la fonction d'effacement de l'ancienne forme des étiquettes en cas de changement de forme. La fonction de dessin ci-dessus est appelée par :

procedure TTreeShape.PaintTree;
begin
 With Canvas do
 begin
   Canvas.Brush.Color := FBrush.Color;
   Canvas.Pen.Color   := FPen.Color;
   Case FEtiquette of
     teCircle     : DrawEtiqCircle;
     teEllipse    : DrawEtiqEllipse;
     ?
   end;
 end;
end;

J'ai défini également les procédures:
procedure TTreeShape.ChangeRedraw(Sender: TObject);
begin
  Invalidate;
end;

procedure TTreeShape.SetEtiquette(value: TTypeEtiquet);
begin
  if value <> FEtiquette then
  begin
    FEtiquette := value;
    Paint;
  end;
end;



Je ne sais plus par quel bout réfléchir.

1. A votre avis que dois-je faire pour effacer l'ancienne image? Dans qu'elle procédure dois-je écrire le code?

2. L'image de l'arbre (liens, étiquettes, données) seront dessinés dans un bitmap.

Merci pour vos suggestions.

Jean_Jean

13 réponses

Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 10
29 juil. 2010 à 13:03
Salut,
moi j'aurai fait un :
BitBlt(Canvas.Handle, // coordonnées x, // coordonnées y,
                      // largeur étiquette, // hauteur étiquette,
                      0, 0, 0, WHITENESS);

Ca aurait rempli le rectangle de l'étiquette de blanc, te laissant libre de dessiner une forme quelconque par-dessus sans imperfections. On peut obtenir le même résultat avec une couleur de fond différent et jouant avec Canvas.Rectangle et Pen. J'aurai mis ça avant tous les Appels à Ellipse. Peux-tu préciser ton problème un peu plus ?

Cordialement, Bacterius !
3
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
29 juil. 2010 à 13:08
Salut,

1°) il serait intéressant de nous dire de quel composant tu dérive ton "TTreeShape" ?
puisqu'en fonction du composant ancêtre choisi tu peux surcharger la méthode "Paint" qui est prévue pour ça.

donc dans ce cas l'effacement interviendrait au début de cette méthode et suivrait le code de "PaintTree" ce qui ressemblerait un peu à ça:
 with inherited Canvas do
 begin
   Brush.Color := FBrush.Color;
   Pen.Color   := FPen.Color;
   // <--- ICI on efface 
   FillRect(ClipRect);
   case FEtiquette of
     teCircle     : DrawEtiqCircle;
     teEllipse    : DrawEtiqEllipse;
   end;
 end;


et tpour finir tu peux alors "Invalidate" partout à la place de "Paint" comme dans "SetEtiquette"

"Invalidate" est plus performant que "Paint"


[hr]@+Cirec
[hr]
3
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 10
30 juil. 2010 à 10:49
Invalidate dit à Windows que la totalité de la représentation graphique du composant a été changée, et qu'il faut mettre à jour le plus tôt possible. Windows envoie alors un message WM_PAINT au composant qui le traite et appelle Paint en conséquence. En appellant Paint, tu forces un peu la main

Cordialement, Bacterius !
3
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
30 juil. 2010 à 11:17
ouai c'est presque ça

[quote=Aide Delphi]Description
Utilisez Invalidate quand la totalité du contrôle doit être dessinée. Si plusieurs zones d'un contrôle doivent être redessinées, Invalidate provoque le réaffichage de toute la fenêtre en une seule passe, pour éviter les instabilités provoquées par les redessins redondants. Les performances ne sont pas dégradées par plusieurs appels d'Invalidate avant que le contrôle ne soit effectivement redessiné.

/quote


[hr]@+Cirec
[hr]
3

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
cs_MAURICIO Messages postés 2106 Date d'inscription mardi 10 décembre 2002 Statut Modérateur Dernière intervention 15 décembre 2014 5
30 juil. 2010 à 16:31
Salut à tous!

Arg, j' arrive trop tard sur ce topic !!!

Pour résumer, Invalidate donne l' ordre de redessinner (ne sera executé que lorsque cela sera possible) et Paint execute l' ordre.

Donc, si tu faits :
Invalidate;
x := x + 1;
Invalidate;
Ça va repeindre une seule fois ton compo.

Et, si tu faits :
Paint;
x := x + 1;
Paint;
Ça va repeindre deux fois ton compo.

et pour finir, si tu faits :
Invalidate;
Application.ProcessMessages;
x := x + 1;
Invalidate;
Ça va repeindre deux fois ton compo.

Mais bon, tu avais déjà compris ...

A+
A+
3
cs_MAURICIO Messages postés 2106 Date d'inscription mardi 10 décembre 2002 Statut Modérateur Dernière intervention 15 décembre 2014 5
30 juil. 2010 à 17:45
Resalut Jean-Jean,

il me semble que l' on peut "invalider" une partie d' un compo avec InvalidateRect.
Par exemple, le TDBGrid utilise cela pour éviter de repeindre toute la grille lorsque l' on passe par exemple d' un colonne à l' autre: on ne met à jour que les cellules concernnées (sauf si on provoque un scroll horizontal lors du changement de colonnes).

Pour ma part, j' ai opté pratiquement tout le temps pour le Invalidate dans mes compos, qui sont bien entendu plus simple que le TDBGrid (à l' exeption de mes DBGrids héritant du TDBGrid et possède donc cette fonctionnalité "héritée").

La seule exception, c' est mon TcyColorMatrix qui permet de mettre à jour (graphiqument donc ...) que partiellement un bitmap utilisé pour sauvegarder tout le graphique du compo. Dans le OnPaint, je fais juste canvas.DrawBitmap(monBitmap).
C' est à dire que lorsque je change une zone de mon compo, je mets à jour cette zone dans le Bitmap puis j' appelle Invalidate (qui va donc appeler l' événement Paint), on pourrait aussi peindre directement sur le canvas simplement la zone modifiée.

En fait, il y a 2 critères à prendre en compte:
- la lenteur à redessinner le compo: teste combien de TonCompo.Update tu arrives à faire par seconde pour voir s' il est necessaire d' optimiser ton compo (utilise la fonction GetTickCount).
- déterminer avec quelle fréquence le compo est susceptible de faire un paint: le cas de la DBGrid est un bon exemple: si j' appuis sur la toucha clavier "bas", je vais parcourir tous les enregistremnts jusqu' à la fin du fichier. Il faut donc que la mise à jour soit rapide pour une bonne fluidité du compo.

A+
3
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
29 juil. 2010 à 13:11
oup
une petite erreur c'est glissée dans l'avant dernière ligne ... il fallait lire :
et pour finir tu peux alors appeler "Invalidate" partout à la place de "Paint" dans "SetEtiquette" par exemple.



[hr]@+Cirec
[hr]
0
cs_Jean_Jean Messages postés 615 Date d'inscription dimanche 13 août 2006 Statut Membre Dernière intervention 13 décembre 2018 3
29 juil. 2010 à 14:01
Chers amis,

Merci pour vos réponses... Le soleil ne vous tape pas sur les neurones, quel bonheur!!!

Mon composant dérive de :
TTreeShape = class(TGraphicControl)
private
Rect : TRect;
MemDC : HDC;
Bitmap : HBitmap;
FBrush : TBrush;
FPen : TPen;
FShadow : Boolean;
FShadowOffset : Cardinal;
FShadowColor : TColor;
FEtiquette : TTypeEtiquet;
...
@Cirec, oui je pense à priori comme toi, j'ai surchargé paint pour définir la mémoire dont j'ai besoin et dessiner les différents éléments du graphique...D'ailleurs, c'est en construction car je vais devoir dessiner les étiquettes, les ombres, les liens et les données... => dessin dans un bitmap global, c'est plus logique.

  protected
    procedure Paint; override;
    procedure PaintShadow; virtual;
    procedure PaintTree; virtual;


voici ma méthode paint (non définitive et en test) :
procedure TTreeShape.Paint;
var
  rc: bool;
  oldBmp: HBitmap;
  oldThumb: TRect;
begin
  inherited Paint;
  with Canvas do
  begin
    Brush.Color := FBrush.Color;
  //    FillRect(Canvas.ClipRect);
//    Pen.Mode := pmblack;//pmxor;
    {Création mémoire pour lasauvegarde du bitmap}
    if MemDC = 0 then MemDC := CreateCompatibleDC(Canvas.Handle);
    {Create image arbre}
    if Bitmap = 0 then
       Bitmap := CreateCompatibleBitmap(Canvas.Handle, Width, Height);
    Rect.top    := 0;
    Rect.bottom := Height;
    Rect.left   := (Width - 10) div 2;
    Rect.Right  := Rect.Left + 10;

  SelectObject(MemDC, OldBmp);
  end;
  if Shadow then PaintShadow;
  PaintTree;
end;


@Bactérius
Oui, cette instruction BitBlt est utile, je l'avais oubliée. Mais je suis dans une réflexion plus large et méthodologique car j'ai les étiquettes, mais aussi le reste. Ce qui voudrait dire qu'il me faut peut-être tout redessiner ou presque et pas seulement les étiquettes...
La seule constante est la dimension de l'arbre. Si elle est modifiée, je redessine tout...
Mais peut-être qu'en voulant économiser de la complexité de programmation, je ne vais pas beaucoup gagner en temps d'exécution. Le mieux serait alors de tout redessiner!


Jean_Jean
0
cs_Jean_Jean Messages postés 615 Date d'inscription dimanche 13 août 2006 Statut Membre Dernière intervention 13 décembre 2018 3
30 juil. 2010 à 10:03
@ Cirec
C'est bon pour l'effacement.
Par contre je ne comprends pas ta phrase: "et pour finir tu peux appeler? alors "Invalidate" partout à la place de "Paint" comme dans "SetEtiquette"

"Invalidate" est plus performant que "Paint"

Invalidate? qu'est-ce que c'est en fait? Une méthode qui oblige à redessiner?
Cordialement

Jean_Jean
0
cs_Jean_Jean Messages postés 615 Date d'inscription dimanche 13 août 2006 Statut Membre Dernière intervention 13 décembre 2018 3
30 juil. 2010 à 11:22
Ah, je me sens mieux!
Bien à vous
Jean_Jean
0
cs_Jean_Jean Messages postés 615 Date d'inscription dimanche 13 août 2006 Statut Membre Dernière intervention 13 décembre 2018 3
30 juil. 2010 à 17:13
Merci Mauricio pour ces précisions!
Oui, les paint répétitifs, c'est un problème!
Invalidate = à retenir!

j'en profite pour vous redemander un conseil pour les dessins.
J'ai un graphique assez compliqué (B-arbre) à redessiner chaque fois qu'un paramètre change :
noeud, couleur, forme étiquette, forme des liens...
Bref des multitudes de détails.
a votre avis, est-il plus performant de tout redessiner ou de ne redessiner que la zone pixel à modifier en faisant des sortes de couches (bitmap) qu'il faut ensuite superposer?
Il me semble Mauricio que tu avais opté pour cette solution (dans un de tes codes) de sous-couches (calques) que l'on superpose!!!??

- Si je redessine tout, je dessine selon les options dans la méthode PaintTree :

procedure TTreeShape.PaintTree;
begin
 With Canvas do
 begin
   Canvas.Brush.Color := FBrush.Color;
   Canvas.Pen.Color   := FPen.Color;
   Case FEtiquette of
     teCircle     : DrawEtiqCircle;
     teEllipse    : DrawEtiqEllipse;
     ...
   end;
   Case FConnexion of
     tcSolid      : DrawConnectSolid;
     tcShortDodded: DrawConnectShortDodded;
     ...
   end;
   ...
 end;
end;


C'est dans les procédures Draw que je réalise les différents graphiques qui vont composer le Bitmap final.

Cordialement

Jean_Jean
0
cs_Jean_Jean Messages postés 615 Date d'inscription dimanche 13 août 2006 Statut Membre Dernière intervention 13 décembre 2018 3
30 juil. 2010 à 18:02
Merci beaucoup Mauricio pour ces bonnes précisions...
Je vais méditer sur tes réflexions et revoir ton compo TcyColorMatrix qui m'inspirera peut-être!
Bien à toi
Jean_Jean
0
cs_MAURICIO Messages postés 2106 Date d'inscription mardi 10 décembre 2002 Statut Modérateur Dernière intervention 15 décembre 2014 5
30 juil. 2010 à 18:07
Aucun problème ... Je suis heureux d' avoir pu t' aider.
A+
0
Rejoignez-nous