Double buffering sur composant perso [Résolu]

atomefougere 32 Messages postés mercredi 1 septembre 2004Date d'inscription 5 décembre 2005 Dernière intervention - 29 oct. 2005 à 00:33 - Dernière réponse : ikaemos 9 Messages postés lundi 6 septembre 2004Date d'inscription 4 décembre 2005 Dernière intervention
- 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.
Afficher la suite 

Votre réponse

28 réponses

Meilleure réponse
ikaemos 9 Messages postés lundi 6 septembre 2004Date d'inscription 4 décembre 2005 Dernière intervention - 5 déc. 2005 à 00:31
3
Merci
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

Merci ikaemos 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 97 internautes ce mois-ci

Commenter la réponse de ikaemos
cs_badrbadr 475 Messages postés jeudi 19 juin 2003Date d'inscription 3 novembre 2008 Dernière intervention - 29 oct. 2005 à 00:52
0
Merci
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 ?

@++
Commenter la réponse de cs_badrbadr
atomefougere 32 Messages postés mercredi 1 septembre 2004Date d'inscription 5 décembre 2005 Dernière intervention - 29 oct. 2005 à 01:00
0
Merci
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...
Commenter la réponse de atomefougere
cs_badrbadr 475 Messages postés jeudi 19 juin 2003Date d'inscription 3 novembre 2008 Dernière intervention - 29 oct. 2005 à 01:21
0
Merci
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

@++
Commenter la réponse de cs_badrbadr
cs_coq 6366 Messages postés samedi 1 juin 2002Date d'inscription 2 août 2014 Dernière intervention - 29 oct. 2005 à 10:09
0
Merci
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#
*/
Commenter la réponse de cs_coq
cs_coq 6366 Messages postés samedi 1 juin 2002Date d'inscription 2 août 2014 Dernière intervention - 29 oct. 2005 à 10:10
0
Merci
gzit = fait

/*
coq
MVP Visual C#
*/
Commenter la réponse de cs_coq
atomefougere 32 Messages postés mercredi 1 septembre 2004Date d'inscription 5 décembre 2005 Dernière intervention - 29 oct. 2005 à 12:45
0
Merci
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);

}
Commenter la réponse de atomefougere
atomefougere 32 Messages postés mercredi 1 septembre 2004Date d'inscription 5 décembre 2005 Dernière intervention - 29 oct. 2005 à 12:48
0
Merci
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...
Commenter la réponse de atomefougere
sebmafate 4947 Messages postés lundi 17 février 2003Date d'inscription 14 février 2014 Dernière intervention - 29 oct. 2005 à 13:47
0
Merci
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#]
Commenter la réponse de sebmafate
atomefougere 32 Messages postés mercredi 1 septembre 2004Date d'inscription 5 décembre 2005 Dernière intervention - 29 oct. 2005 à 13:53
0
Merci
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...
Commenter la réponse de atomefougere
sebmafate 4947 Messages postés lundi 17 février 2003Date d'inscription 14 février 2014 Dernière intervention - 29 oct. 2005 à 14:00
0
Merci
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#]
Commenter la réponse de sebmafate
atomefougere 32 Messages postés mercredi 1 septembre 2004Date d'inscription 5 décembre 2005 Dernière intervention - 29 oct. 2005 à 14:03
0
Merci
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.
Commenter la réponse de atomefougere
Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention - 29 oct. 2005 à 15:14
0
Merci
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.
Commenter la réponse de Lutinore
atomefougere 32 Messages postés mercredi 1 septembre 2004Date d'inscription 5 décembre 2005 Dernière intervention - 29 oct. 2005 à 15:16
0
Merci
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.
Commenter la réponse de atomefougere
cs_coq 6366 Messages postés samedi 1 juin 2002Date d'inscription 2 août 2014 Dernière intervention - 29 oct. 2005 à 19:15
0
Merci
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#
*/
Commenter la réponse de cs_coq
sebmafate 4947 Messages postés lundi 17 février 2003Date d'inscription 14 février 2014 Dernière intervention - 29 oct. 2005 à 19:16
0
Merci
envoie ton projet vs2005 à l'adresse suivante : sebmafate@hotmail.com

je vais voir...

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

Je vais refaire une mini solution d'exemple, juste pour illustrer mon pb et je te l'envoie.
Commenter la réponse de atomefougere
LUDINSKI 441 Messages postés mardi 2 décembre 2003Date d'inscription 22 mai 2012 Dernière intervention - 31 oct. 2005 à 04:42
0
Merci
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....
Commenter la réponse de LUDINSKI
cs_coq 6366 Messages postés samedi 1 juin 2002Date d'inscription 2 août 2014 Dernière intervention - 31 oct. 2005 à 10:58
0
Merci
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#
*/
Commenter la réponse de cs_coq
atomefougere 32 Messages postés mercredi 1 septembre 2004Date d'inscription 5 décembre 2005 Dernière intervention - 31 oct. 2005 à 12:25
0
Merci
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.
Commenter la réponse de atomefougere

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.