Effacer la dernière image dessinée [Résolu]

cs_Jean_Jean 639 Messages postés dimanche 13 août 2006Date d'inscription 5 mai 2016 Dernière intervention - 29 juil. 2010 à 11:26 - Dernière réponse : cs_MAURICIO 2233 Messages postés mardi 10 décembre 2002Date d'inscription 15 décembre 2014 Dernière intervention
- 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
Afficher la suite 

13 réponses

Répondre au sujet
Bacterius 3869 Messages postés samedi 22 décembre 2007Date d'inscription 3 juin 2016 Dernière intervention - 29 juil. 2010 à 13:03
+3
Utile
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 !
Cette réponse vous a-t-elle aidé ?  
Commenter la réponse de Bacterius
Cirec 4217 Messages postés vendredi 23 juillet 2004Date d'inscription 3 avril 2018 Dernière intervention - 29 juil. 2010 à 13:08
+3
Utile
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]
Cette réponse vous a-t-elle aidé ?  
Commenter la réponse de Cirec
Bacterius 3869 Messages postés samedi 22 décembre 2007Date d'inscription 3 juin 2016 Dernière intervention - 30 juil. 2010 à 10:49
+3
Utile
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 !
Cette réponse vous a-t-elle aidé ?  
Commenter la réponse de Bacterius
Cirec 4217 Messages postés vendredi 23 juillet 2004Date d'inscription 3 avril 2018 Dernière intervention - 30 juil. 2010 à 11:17
+3
Utile
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]
Cette réponse vous a-t-elle aidé ?  
Commenter la réponse de Cirec
cs_MAURICIO 2233 Messages postés mardi 10 décembre 2002Date d'inscription 15 décembre 2014 Dernière intervention - 30 juil. 2010 à 16:31
+3
Utile
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+
Cette réponse vous a-t-elle aidé ?  
Commenter la réponse de cs_MAURICIO
cs_MAURICIO 2233 Messages postés mardi 10 décembre 2002Date d'inscription 15 décembre 2014 Dernière intervention - 30 juil. 2010 à 17:45
+3
Utile
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+
Cette réponse vous a-t-elle aidé ?  
Commenter la réponse de cs_MAURICIO
Cirec 4217 Messages postés vendredi 23 juillet 2004Date d'inscription 3 avril 2018 Dernière intervention - 29 juil. 2010 à 13:11
0
Utile
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]
Commenter la réponse de Cirec
cs_Jean_Jean 639 Messages postés dimanche 13 août 2006Date d'inscription 5 mai 2016 Dernière intervention - 29 juil. 2010 à 14:01
0
Utile
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
Commenter la réponse de cs_Jean_Jean
cs_Jean_Jean 639 Messages postés dimanche 13 août 2006Date d'inscription 5 mai 2016 Dernière intervention - 30 juil. 2010 à 10:03
0
Utile
@ 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
Commenter la réponse de cs_Jean_Jean
cs_Jean_Jean 639 Messages postés dimanche 13 août 2006Date d'inscription 5 mai 2016 Dernière intervention - 30 juil. 2010 à 11:22
0
Utile
Ah, je me sens mieux!
Bien à vous
Jean_Jean
Commenter la réponse de cs_Jean_Jean
cs_Jean_Jean 639 Messages postés dimanche 13 août 2006Date d'inscription 5 mai 2016 Dernière intervention - 30 juil. 2010 à 17:13
0
Utile
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
Commenter la réponse de cs_Jean_Jean
cs_Jean_Jean 639 Messages postés dimanche 13 août 2006Date d'inscription 5 mai 2016 Dernière intervention - 30 juil. 2010 à 18:02
0
Utile
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
Commenter la réponse de cs_Jean_Jean
cs_MAURICIO 2233 Messages postés mardi 10 décembre 2002Date d'inscription 15 décembre 2014 Dernière intervention - 30 juil. 2010 à 18:07
0
Utile
Aucun problème ... Je suis heureux d' avoir pu t' aider.
A+
Commenter la réponse de cs_MAURICIO

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.