Double buffering sur composant perso [Résolu]

Signaler
Messages postés
32
Date d'inscription
mercredi 1 septembre 2004
Statut
Membre
Dernière intervention
5 décembre 2005
-
Messages postés
9
Date d'inscription
lundi 6 septembre 2004
Statut
Membre
Dernière intervention
4 décembre 2005
-
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

Messages postés
9
Date d'inscription
lundi 6 septembre 2004
Statut
Membre
Dernière intervention
4 décembre 2005

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
Messages postés
475
Date d'inscription
jeudi 19 juin 2003
Statut
Membre
Dernière intervention
3 novembre 2008

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 ?

@++
Messages postés
32
Date d'inscription
mercredi 1 septembre 2004
Statut
Membre
Dernière intervention
5 décembre 2005

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...
Messages postés
475
Date d'inscription
jeudi 19 juin 2003
Statut
Membre
Dernière intervention
3 novembre 2008

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

@++
Messages postés
6351
Date d'inscription
samedi 1 juin 2002
Statut
Modérateur
Dernière intervention
2 août 2014
92
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#
*/
Messages postés
6351
Date d'inscription
samedi 1 juin 2002
Statut
Modérateur
Dernière intervention
2 août 2014
92
gzit = fait

/*
coq
MVP Visual C#
*/
Messages postés
32
Date d'inscription
mercredi 1 septembre 2004
Statut
Membre
Dernière intervention
5 décembre 2005

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);

}
Messages postés
32
Date d'inscription
mercredi 1 septembre 2004
Statut
Membre
Dernière intervention
5 décembre 2005

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...
Messages postés
4936
Date d'inscription
lundi 17 février 2003
Statut
Modérateur
Dernière intervention
14 février 2014
36
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#]
Messages postés
32
Date d'inscription
mercredi 1 septembre 2004
Statut
Membre
Dernière intervention
5 décembre 2005

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...
Messages postés
4936
Date d'inscription
lundi 17 février 2003
Statut
Modérateur
Dernière intervention
14 février 2014
36
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#]
Messages postés
32
Date d'inscription
mercredi 1 septembre 2004
Statut
Membre
Dernière intervention
5 décembre 2005

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.
Messages postés
3246
Date d'inscription
lundi 25 avril 2005
Statut
Modérateur
Dernière intervention
27 octobre 2012
38
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.
Messages postés
32
Date d'inscription
mercredi 1 septembre 2004
Statut
Membre
Dernière intervention
5 décembre 2005

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.
Messages postés
6351
Date d'inscription
samedi 1 juin 2002
Statut
Modérateur
Dernière intervention
2 août 2014
92
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#
*/
Messages postés
4936
Date d'inscription
lundi 17 février 2003
Statut
Modérateur
Dernière intervention
14 février 2014
36
envoie ton projet vs2005 à l'adresse suivante : sebmafate@hotmail.com

je vais voir...

Sébastien FERRAND
[MVP C#]
Messages postés
32
Date d'inscription
mercredi 1 septembre 2004
Statut
Membre
Dernière intervention
5 décembre 2005

Merci beaucoup,

Je vais refaire une mini solution d'exemple, juste pour illustrer mon pb et je te l'envoie.
Messages postés
441
Date d'inscription
mardi 2 décembre 2003
Statut
Membre
Dernière intervention
22 mai 2012
7
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....
Messages postés
6351
Date d'inscription
samedi 1 juin 2002
Statut
Modérateur
Dernière intervention
2 août 2014
92
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#
*/
Messages postés
32
Date d'inscription
mercredi 1 septembre 2004
Statut
Membre
Dernière intervention
5 décembre 2005

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.