2010-11-11 4 views
1

J'ai un panneau dans lequel je fais un dessin personnalisé. Pour vous assurer que l'échelle graphique est proportionnelle lorsque le panneau est redimensionné, j'utilise la propriété Transform de mon Graphics.Mise à l'échelle brutale des graphiques lors du redimensionnement du panneau

private void panelGraph_Paint(object sender, PaintEventArgs e) 
{ 
    var gfx = e.Graphics; 
    gfx.Transform = BuildTransform(e.ClipRectangle); 
    var width = 1.0f/gfx.Transform.Elements[0]; 
    var white = new Pen(Color.White, width); 
    gfx.DrawLine(white, new PointF(-1.0f, -1.0f), new PointF(1.0f, -1.0f)); 
    gfx.DrawLine(white, new PointF(-1.0f, -1.0f), new PointF(-1.0f, 1.0f)); 
} 

La matrice de BuildTransform mappe une zone avec une largeur et une hauteur [-2, 2] vers la zone de e.ClipRectangle.

Le code fonctionne, en quelque sorte. Le problème est que lorsque je redimensionne le panneau, la mise à l'échelle de mes graphiques n'est pas fluide mais s'effectue par étapes discrètes. Si j'ajoute la ligne suivante dans ma peinture fonction:

Console.WriteLine("Paint {0} {1}", e.ClipRectangle.Width, e.ClipRectangle.Height); 

Je reçois la sortie comme ça quand je redimensionne lentement la fenêtre:

Paint 1 815 
Paint 1 815 
Paint 1 815 
Paint 751 815 
Paint 1 815 
Paint 753 815 
Paint 1 813 
Paint 754 811 

Qu'est-ce qui provoque cela et comment puis-je résoudre ce problème?

EDIT: Le problème n'est pas déterministe mais semble dépendre de la rapidité avec laquelle je redimensionne la fenêtre (!). Si je redimensionne lentement et lentement la fenêtre, je peux l'obtenir presque arbitrairement sans que la taille de mes graphiques ne change.

Répondre

2

Lorsque vous redimensionnez votre fenêtre, le contrôle invalidera uniquement la zone qui doit être invalidée. Par conséquent, si vous le faites plus grand, il supposera que le rectangle existant est correct et invalidera la nouvelle zone que l'agrandissement rendra visible. Puisque vous devez évidemment invalider votre contrôle entier lorsque vous le redimensionnez, ajoutez un eventhandler resize et invalidez votre contrôle là. Cela devrait résoudre votre problème.

+0

Aha, je pense que je comprends ma sortie maintenant.Le rectangle du clip est la zone qui a besoin d'être repeinte, alors quand je viens d'ajuster la taille verticale de la fenêtre d'un pixel, j'obtiens une taille de clip de quelque chose comme '654, 1'. Dès que je le redimensionne horizontalement, toute la région devra être redessinée. –

+0

Ouais! WinForms essaie d'optimiser la repeindre pour vous. Windows récupère normalement les zones et utilise le plus petit rectangle les contenant toutes pour le processus d'invalidation. Assez souvent, vous devez remplacer ce comportement si vous voulez avoir des graphismes fluides, c'est-à-dire dans l'interaction de l'utilisateur. Vous pouvez également jeter un oeil à ce lien: http://stackoverflow.com/questions/957573/winforms-how-to-speed-up-invalidate – Pedery

3

AFAIK, ClipRectangle n'est pas ce dont vous avez besoin, utilisez plutôt Bounds. Le message de peinture est toujours accompagné d'une zone de découpage à REPAINT. Il est inférieur ou égal à la zone de contrôle entière, selon la quantité de contrôle masquée et qui a été révélée et doit être repeinte.

+0

J'ai expérimentalement calculé ma transformation à partir de la taille fournie dans l'événement de repeinte mais j'ai toujours la même étrangeté. –

+0

Utilisez les commandes de contrôle, comme dit, s'il vous plaît essayez avec elle. La taille fournie dans l'événement repaint est quelque chose que vous ne voulez pas utiliser ici. Si ça marche, je vais essayer d'expliquer pourquoi. –

+0

J'ai ajouté l'explication qui devrait vous rassurer en quelque sorte :) –

1

Définissez la propriété Form.DoubleBuffer sur true.

+0

Cela supprime seulement le scintillement (ce qui est bien sûr bien sûr), le problème d'échelle réelle reste. –

1

est ici un composite d'autres réponses des personnes:

  • Vous devriez remplacer/gérer l'événement de redimensionnement et d'annuler toute la fenêtre
  • Vous devez utiliser ClientRectangle et non e.ClipRectangle lors du calcul de la mise à l'échelle pour la fenêtre.
Questions connexes