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

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 à 00:31
Bon, pour ceux qui cherchent encore :

J'ai cherché environ 6h avant de trouver la solution :

Pour utiliser le ownerdraw (et donc le double buffering) il faut forcément utiliser le OnPaint... Jusqu'ici tout va bien... ahhh... bah non, pas de OnPaint sur la ListBox....

Ahhh...

Bahhh...

C'est en fait OnPaintBackground

Petit exemple :


protected
override
void OnPaintBackground(PaintEventArgs pevent)
{
pevent.Graphics.Clear(
this.BackColor);

for(
int i = 0; i <
this.Items.Count; i++)
{

this.OnDrawItem(
new DrawItemEventArgs(pevent.Graphics,
this.Font,
this.GetItemRectangle(i), i, DrawItemState.Default));
}
}

Hop c'est tout beau ça flick plus du tout

Ika
3
cs_badrbadr Messages postés 475 Date d'inscription jeudi 19 juin 2003 Statut Membre Dernière intervention 3 novembre 2008 1
29 oct. 2005 à 00:52
j ai pas deja eu ce probleme, mais j ai une idée
ta classe hérite de ListBox et tu surcharges OnDrawItem pour dessiner ton custom-control
pkoi tu ne override pas le OnPaint à la place ?

@++
0
atomefougere Messages postés 32 Date d'inscription mercredi 1 septembre 2004 Statut Membre Dernière intervention 5 décembre 2005
29 oct. 2005 à 01:00
En fait, je veux surcharger le OnDrawItem pour gérer le dessin de mes items... Je ne vois pas trop comment le OnPaint peut remplacer le OnDrawItem... Je n'ai pas les bons rectangles de dessin, ni les index des items...
0
cs_badrbadr Messages postés 475 Date d'inscription jeudi 19 juin 2003 Statut Membre Dernière intervention 3 novembre 2008 1
29 oct. 2005 à 01:21
mmm, oui, scuse moi
t as raison maintenant que j'y pense
les seuls controles personalisés que j'ai fait, c'est des boutons et j'utilise OnPaint
http://www.csharpfr.com/code.aspx?ID=29856
c est pour ca que j'ai eu le reflexe de dire OnPaint

mais sinon, tu peux poster un peu plus de ton code en esperant que quelqu'un trouve le probleme

@++
0

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

Posez votre question
cs_coq Messages postés 6349 Date d'inscription samedi 1 juin 2002 Statut Membre Dernière intervention 2 août 2014 101
29 oct. 2005 à 10:09
Salut,

UserPaint est justement gzit pour gérer totalement soit même le dessin du contrôle.
Ce qui est étonnant c'est le clignotement, il est en continu ou juste au moment du dessin des items ?
Tu peux montrer le code de dessin en question ?

/*
coq
MVP Visual C#
*/
0
cs_coq Messages postés 6349 Date d'inscription samedi 1 juin 2002 Statut Membre Dernière intervention 2 août 2014 101
29 oct. 2005 à 10:10
gzit = fait

/*
coq
MVP Visual C#
*/
0
atomefougere Messages postés 32 Date d'inscription mercredi 1 septembre 2004 Statut Membre Dernière intervention 5 décembre 2005
29 oct. 2005 à 12:45
Salut,

Le clignotement intervient lorsque les items sont redessinés. A l'ajout, sur le redimensionnement de ma grille, sur le mouseDown etc.

Voici ma fonction de dessin très simplifée (qui clignote quand même) :

protected
override void OnDrawItem(DrawItemEventArgs e)

{

if (DesignMode && this.Items.Count == 0)

{

base.OnDrawItem(e);

}

else

{

if (e.Index != -1)
{

if (GetSelected(e.Index))

{

e.Graphics.FillRectangle(new SolidBrush(Color.Beige), e.Bounds);

}

e.Graphics.DrawString(this.Items[e.Index].ToString(),
this.Font,
new SolidBrush(Color.Red),
e.Bounds);

}

}

}

Et mon constructeur :



public SmailGrid()

{
InitializeComponent();
this.DrawMode
=
DrawMode.OwnerDrawVariable;

SetStyle(ControlStyles.AllPaintingInWmPaint,
true);

SetStyle(ControlStyles.UserPaint,
true);

SetStyle(ControlStyles.DoubleBuffer,
true);

SetStyle(ControlStyles.ResizeRedraw,
true);

}
0
atomefougere Messages postés 32 Date d'inscription mercredi 1 septembre 2004 Statut Membre Dernière intervention 5 décembre 2005
29 oct. 2005 à 12:48
J'ai oublié de préciser que si je garde le constructeur tel quel, rien ne se dessine. Si j'enlève les SetStyle, ça se dessine mais ça clignote...
0
sebmafate Messages postés 4936 Date d'inscription lundi 17 février 2003 Statut Membre Dernière intervention 14 février 2014 37
29 oct. 2005 à 13:47
il faut aussi faire une surcharge de OnMeasureItem...

petit conseil aussi, remplace :
if (DesignMode && this.Items.Count == 0)

par
if (DesignMode || this.Items.Count == 0)

ensuite, je te déconseille l'utilisation du style ControlStyles.ResizeRedraw
intercepte plutôt l'évènement Resize du controle et appelle la méthode Invalidate().

Sébastien FERRAND
[MVP C#]
0
atomefougere Messages postés 32 Date d'inscription mercredi 1 septembre 2004 Statut Membre Dernière intervention 5 décembre 2005
29 oct. 2005 à 13:53
Salut Sébastien,

En fait, je surcharge déjà le OnMeasureItem. Et comme le ControlStyles.ResizeRedraw ne fonctionne pas, je fais appel a Invalidate() dans le OnSizeChanged...

Sinon tu as raison pour le test, je fais d'ailleurs le bon dans le OnMeasureItem.

Ca ne fonctionne toujours pas...
0
sebmafate Messages postés 4936 Date d'inscription lundi 17 février 2003 Statut Membre Dernière intervention 14 février 2014 37
29 oct. 2005 à 14:00
as-tu regardé sur CodeProject ?
http://www.codeproject.com/cs/combobox/

j'ai pas beaucoup de temps là, je m'en vais pour l'après midi...

Sébastien FERRAND
[MVP C#]
0
atomefougere Messages postés 32 Date d'inscription mercredi 1 septembre 2004 Statut Membre Dernière intervention 5 décembre 2005
29 oct. 2005 à 14:03
Oui j'ai fouillé un peu partout... Soit les listBox clignotent comme la mienne, soit elles n'imposent pas le redessin lors du resize, soit les composant héritent de Panel et non de ListBox, et tout est géré à la main...

Donc je sèche un peu. Je vais essayer de faire un mini projet de test pour que vous puissiez y jeter un coup d'oeil.

Bon après-midi à toi et merci pour ton aide.
0
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
29 oct. 2005 à 15:14
Nan nan ça se dit "je gizt", "tu gizts" ..

Vi laisses un mini projet si tu veux, sinon juste un détail comme ça, ControlStyles c'est un flags.
0
atomefougere Messages postés 32 Date d'inscription mercredi 1 septembre 2004 Statut Membre Dernière intervention 5 décembre 2005
29 oct. 2005 à 15:16
Je sais qu'il s'agit d'un flag. Si je sépare les SetStyle, c'est pour pouvoir les commenter plus facilement de façon indépendante...

Le problème, c'est que je travaille avec la beta de vs2005, et je ne crois pas que vous puissiez ouvrir la solution si vous avez vs2003...

J'vais voir.
0
cs_coq Messages postés 6349 Date d'inscription samedi 1 juin 2002 Statut Membre Dernière intervention 2 août 2014 101
29 oct. 2005 à 19:15
Ne t'inquiete pas pour la version de VS, la finale est dispo depuis qq jours et les betas des versions express sont assez répandues je pense.

/*
coq
MVP Visual C#
*/
0
sebmafate Messages postés 4936 Date d'inscription lundi 17 février 2003 Statut Membre Dernière intervention 14 février 2014 37
29 oct. 2005 à 19:16
envoie ton projet vs2005 à l'adresse suivante : sebmafate@hotmail.com

je vais voir...

Sébastien FERRAND
[MVP C#]
0
atomefougere Messages postés 32 Date d'inscription mercredi 1 septembre 2004 Statut Membre Dernière intervention 5 décembre 2005
29 oct. 2005 à 19:23
Merci beaucoup,

Je vais refaire une mini solution d'exemple, juste pour illustrer mon pb et je te l'envoie.
0
LUDINSKI Messages postés 441 Date d'inscription mardi 2 décembre 2003 Statut Membre Dernière intervention 22 mai 2012 8
31 oct. 2005 à 04:42
Salut AtomeFougere ^^

Je pense que tu utilises mal la méthode SetStyle !!
Au lieu d'écrire ça :

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

Il faudrait écrire ça, autrement tu auras affecté uniquement le style ResizeRedraw :

SetStyle( ControlStyles.AllPaintingInWmPaint |ControlStyles.UserPaint | ControlStyles.DoubleBuffer | ControlStyles.ResizeRedraw, true );

Ou comme tu aimerais pouvoir commenter sans trop de soucis :

ControlStyles controlStyles = ControlStyles.AllPaintingInWmPaint;
controlStyles |= ControlStyles.UserPaint;
controlStyles |= ControlStyles.DoubleBuffer;
controlStyles |= ControlStyles.ResizeRedraw;

SetStyle( controlStyles, true );

Sinon, j'ai refais le contrôle...
J'ai eu un problème lorsque j'ajoutais le style UserPaint, donc je l'ai supprimé
J'ai également appelé Invalidate( true ) lorsque la souris est enfoncée au-dessus du contrôle
parce qu'il ne redessinais pas les items lorsque la sélection était modifiée !


public
class NewListBox : ListBox
{

public NewListBox()
{

this.DrawMode = DrawMode.OwnerDrawVariable;

ControlStyles controlStyles = ControlStyles.AllPaintingInWmPaint;
controlStyles |= ControlStyles.DoubleBuffer;
controlStyles |= ControlStyles.ResizeRedraw;
SetStyle( controlStyles,
true );
}

protected
override
void OnDrawItem( DrawItemEventArgs e )
{

if( DesignMode &&
this.Items.Count == 0 )
{

base.OnDrawItem( e );
}

else
{

if( e.Index != -1 )
{

if( GetSelected( e.Index ) )
{
e.Graphics.FillRectangle(
new SolidBrush( Color.Beige ), e.Bounds );
}

e.Graphics.DrawString
(

this.Items[ e.Index ].ToString(),
e.Font,

new SolidBrush( Color.Red ),
e.Bounds
);
}
}
}

protected
override
void OnMouseDown( MouseEventArgs e )
{

base.OnMouseDown( e );
Invalidate(
true );
}
}

Voilà, en espérant avoir pu t'aider....
0
cs_coq Messages postés 6349 Date d'inscription samedi 1 juin 2002 Statut Membre Dernière intervention 2 août 2014 101
31 oct. 2005 à 10:58
Non, son utilisation de SetStyle est tout à fait bonne.
En interne la méthode ajoute ou retire le flag spécifié à la valeur existante, suivant l'état du booléen.

/*
coq
MVP Visual C#
*/
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 à 12:25
Salut Ludinski,

Merci d'avoir pris le temps de te pencher sur ton problème, c'est appréciable. Toutefois, je ne suis pas vraiment avancé... Comme le précise coq, il est possible d'appeller la méthode SetStyle plusieurs fois de suite, et elle change la valeur du flag en ne modifiant que la propriété ciblée, celle que l'on passe en paramètre.

Et sinon, dans ton source, tu fais bien une ListBox perso, mais le double buffering n'est pas actif, et le controle scintille donc sur les redimensionnement, or c'est justement le problème que je cherche à résoudre.

Je l'avais indiqué plusieurs fois : Sans le

SetStyle(ControlStyles.UserPaint,
true);

Le dessin fonctionne bien, mais le double buffering n'est pas actif. Si je la rajoute, alors le dessin ne se fait plus.

Une précision :

J'ai réussi à faire fonctionner le double buffering en utilisant le OnPaint. Seulement, ça ne me convient pas vraiment, puisqu'il me faut gérer le dessin de tous les items à cet endroit, et cela devient compliqué lorsque la liste est scrollable.

Peut-être que mon problème n'a pas de solution : la listBox de base scintille beaucoup... Mais je ne désespère pas...

Merci, et si vous avez d'autres idées, j'suis preneur.
0
Rejoignez-nous