Double buffering sur composant perso

Résolu
atomefougere Messages postés 32 Date d'inscription mercredi 1 septembre 2004 Statut Membre Dernière intervention 5 décembre 2005 - 29 oct. 2005 à 00:33
ikaemos Messages postés 9 Date d'inscription lundi 6 septembre 2004 Statut Membre Dernière intervention 4 décembre 2005 - 5 déc. 2005 à 21:31
Salut tout le monde.

Je vous explique mon problème :

J'ai codé un composant qui hérite de la ListBox. Je gère le redimensionnement de ses items en fonction du texte qui doit y être affiché. J'ai notamment surchargé la méthode OnDrawItem pour dessiner mes items.

J'ai un clignotement assez désagréable, que j'ai essayé de supprimer en utilisant le double buffering sur mon composant. Dans le constructeur, j'ajoute donc les instructions :

SetStyle(System.Windows.Forms.ControlStyles.DoubleBuffer, true);
SetStyle(System.Windows.Forms.ControlStyles.AllPaintingInWmPaint, true);
SetStyle(System.Windows.Forms.ControlStyles.ResizeRedraw, true);
SetStyle(System.Windows.Forms.ControlStyles.UserPaint, true);

Mon controle est en OwnerDrawVariable
.

Le problème est le suivant :

- Lorsque je n'apelle pas les SetStyle, mes items se dessinent bien, mais ça clignote
- Lorsque j'apelle les SetStyle, mes items ne se dessinent plus. Il semblerait que ce soit le :
SetStyle(System.Windows.Forms.ControlStyles.UserPaint, true);

qui empêche le dessin. Si je le commente, le dessin de fait bien, mais ça clignote toujours.

Est-ce que quelqu'un a déjà eu le problème ?

Merci.

28 réponses

sebmafate Messages postés 4936 Date d'inscription lundi 17 février 2003 Statut Membre Dernière intervention 14 février 2014 37
31 oct. 2005 à 12:34
après moultes recherches... je suis arrivé à la conclusion qu'étant donné que le contrôle standard à le même conmportement (clignotement lors du redimensionnement), à moins de refaire ton propre controle... je crains que tu n'arriveras pas à tes fins

Sébastien FERRAND
[MVP C#]
0
cs_badrbadr Messages postés 475 Date d'inscription jeudi 19 juin 2003 Statut Membre Dernière intervention 3 novembre 2008 1
31 oct. 2005 à 16:12
ca tourne au drame avec ce mechant ListBox ici
Je vais donc dire ce que je connais du double buffering en espérant que ça donne des idées
le fait d'activer le double buffering avec SetStyle(ControlStyles.DoubleBuffer, true) ne résout que la moitié du problème.

Windows dessines un contrôle ou une fenetre en trois étapes. D'abord il efface la région en dessinant avec une couleur à lui. Deuxièmement, il envoie l'événement PaintBackground à la fenêtre ou au contrôle pour dessiner l'arrière plan (chose que la classe d'orginie fait generalement pour nous en utilisant BackColor ou BackgroundImage) et la troisième phase est le dessin final avec Paint.

le Double Buffering fusionne l'étape deux et l'étape trois. pour corriger l'étape un, il faut utiliser le falg AllPaintingInWmPaint

Bon jusqu'à date, vous savez ca...
mais qu'est ce que vous pensez d'override la methode OnPaintBackground()
ca sera interressant d'essayer ca:

protected override void OnPaintBackground(PaintEventArgs e)
{
//ne pas utiliser la méthode de la classe base
//base.OnPaintBackground(e)
e.Graphics.FillRectangle(Brushes.Black, this.ClientRectangle);
}

voila.....
j'espère que ca va aider, j'aime pas ca avancer des théories sans les expérimenter mais c'est que j'ai pas le temps

Ah oui, j'ai eu l'air intelligent dans ce poste là, fe que il importe que je donne mes source
Windows Forms Programming in C# by Chris Sells page 210

salut

@++
0
atomefougere Messages postés 32 Date d'inscription mercredi 1 septembre 2004 Statut Membre Dernière intervention 5 décembre 2005
31 oct. 2005 à 16:26
Merci pour l'intérêt que vous portez tous à la question, vraiment.

Cependant badrbadr, je ne pense pas que le fait de surcharger le PainBackground change quelque chose... J'ai bien compris le principe du double buffering, mais le problème ici, c'est qu'on ne peut l'activer que si on dessine le composant dans le OnPaint.

Or il est plus intuitif et plus pertinent à mon avis de gérer le dessin d'une listBox item par item, en surchargeant le OnDrawItem. Seulement, le fait de travailler avec le OnDrawItem n'est pas compatible avec le OnPaint... Le OnPaint de la classe de base est censé dessiner les items et déclancher les évenements OnDrawItem, mais pour une raison inconnue, à partir du moment ou on surcharge le OnDrawItem dans la classe fille, le contrôle ne supporte plus le double buffering. Lorsque je dessine tout dans le OnPaint, le doubleBuffer est actif, mais ca devient ingérable avec le scrolling.

Enfin j'sais plus trop quoi penser, ça m'embête vraiment, et je suis déçu de constater ça alors que dans d'autres langages, utilisant aussi gdi, tout se passe bien...
0
ikaemos Messages postés 9 Date d'inscription lundi 6 septembre 2004 Statut Membre Dernière intervention 4 décembre 2005
4 déc. 2005 à 00:26
Salut,

Je viens d'expérimenter un truc qui pourrait t'aider :

Dans le contructeur :

this.SetStyle(ControlStyles.Opaque | ControlStyles.ResizeRedraw,
true);

(enfin tout dépend si tu as besoin de resizeRedraw, mais le Opaque permet d'éviter de tracer le fond, et donc évite de substituer le OnPaintBackground pour le court circuiter)

ensuite il suffit de substituer OnMouseMove et OnMouseLeave pour invalider que les lignes nécessaires (la précedente et celle en cours). On définira l'élément "myOverIndex" comme étant l'élément en mouseover de la listbox (très utile si on veut vraiment repeindre TOUTE la ligne sans utiliser le DrawBackground) :


/// <summary>
/// Index de l'élément en mode "Over".
/// </summary>
private
int myOverIndex = -1;


protected
override
void OnMouseMove(MouseEventArgs e)
{

int item =
this.IndexFromPoint(e.X, e.Y);


if(item !=
this.myOverIndex)
{

int myOldOver =
this.myOverIndex;

this.myOverIndex = item;


if((myOldOver >= 0)&&(myOldOver <
this.Items.Count))
{

this.Invalidate(
this.GetItemRectangle(myOldOver));
}


if((item >= 0)&&(item <
this.Items.Count))
{

this.Invalidate(
this.GetItemRectangle(
this.myOverIndex));
}

base.OnMouseMove (e);

}


protected
override
void OnMouseLeave(EventArgs e)
{

int myOldOver =
this.myOverIndex;

this.myOverIndex = -1;


if((myOldOver >= 0)&&(myOldOver <
this.Items.Count))
{

this.Invalidate(
this.GetItemRectangle(myOldOver));
}


base.OnMouseLeave (e);
}



Tout ça évite de redessiner si il n'y a pas besoin, et d'invalider l'intégralité du contrôle. Ca n'enlève pas l'effet de scintillement mais le rend quasiement imperceptible ;)

Voili, j'espère que ça correspond à tes attentes :)
0

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

Posez votre question
ikaemos Messages postés 9 Date d'inscription lundi 6 septembre 2004 Statut Membre Dernière intervention 4 décembre 2005
4 déc. 2005 à 00:31
Ah vi juste une chose : il faut éviter d'utiliser un SmoothingMode spécial pour tracer les contours d'une ligne, sinon ça colle des cocheneries sur les bords des lignes (à cause du mode opaque qui empeche le tracé du fond). L'idéal si tu veux utiliser un SmoothingMode spécial est de ne l'utiliser que pour tracer des éléments et de le remettre en mode par défaut ensuite.
0
cs_badrbadr Messages postés 475 Date d'inscription jeudi 19 juin 2003 Statut Membre Dernière intervention 3 novembre 2008 1
5 déc. 2005 à 00:53
bravo ikaemos pour ta
perseverance

@++
0
atomefougere Messages postés 32 Date d'inscription mercredi 1 septembre 2004 Statut Membre Dernière intervention 5 décembre 2005
5 déc. 2005 à 21:17
Ca a l'air de fonctionner, je te remercie sincèrement :)
0
ikaemos Messages postés 9 Date d'inscription lundi 6 septembre 2004 Statut Membre Dernière intervention 4 décembre 2005
5 déc. 2005 à 21:31
Content que ça puisse te servir ;)
0
Rejoignez-nous