Drawing Glitches When Using Creategraphics Rather Than Paint Event Handler for Custom Drawing

Paint Event e.Graphics.DrawImage doesn't seem to follow double buffering

As already mentioned in the comments - to enable Double Buffering of the panel you need to SetStyle() within the panel constructor, not in the form load event. To do so, you have to create your own panel. Bellow the sample code of custom panel class.

public partial class CustomPanel : UserControl
{
public CustomPanel()
{
InitializeComponent();

// Add Double Buffering
SetStyle(ControlStyles.UserPaint | ControlStyles.ResizeRedraw | ControlStyles.DoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
}
}

Problem with CreateGraphics and drawing strings

It is the CreateGraphics() call that is getting you in trouble, indirectly. The problem is anti-aliasing of the text. A normal painting cycle erases the background before drawing something on top. That doesn't happen in your case, your draw text on top of existing text. The side effect is that the pixels uses to create the aliasing get darker each time your draw. The end result is bold looking, and noticeably jagged text outlines.

The fix is easy: start with a clean slate before you draw:

    using (Graphics g = CreateGraphics()) {
g.Clear(this.BackColor); <=== added
g.SetClip(ClientRectangle);
// etc..
}

You'll now also get to encounter a problem in drawing known as "flicker". It might not yet be that noticeable yet, but it will when you do more drawing. Flicker is suppressed with double-buffering. A feature supported by Windows Forms, but only if you use standard drawing techniques. In other words: no CreateGraphics().

Problem when drawing on a Panel in Winform

this code will go in your form load event

Panel pHText = new Panel();
pHText.Name = "ctrId"; //specify control name, to access it in other parts of your code
pHText.Location = new Point(10, 10);
pHText.Size = new Size(200, 200);
pHText.BackColor = Color.White;
pHText.Paint += paintingUrCtr;//adding onpaint event
Controls.Add(pHText)

add paint event named paintingUrCtr.

private void paintingUrCtr(object sender, PaintEventArgs e)
{
Font myFont = new Font("Arial", 14);
e.Graphics.DrawLine(new Pen(Color.Black), 0, 0, 10, 10);
e.Graphics.DrawString("text", myFont, Brushes.Blue, 10, 10);
}

GDI+ drawing becomes corrupted when ClientSize changes

Painting for container controls like Form was optimized, they only redraw the part of the window that was revealed by the resize. In other words, if the user drags the right or bottom edge then there's no repaint at all when the window is made smaller. A small repaint if it is made bigger, only the part of the window to became visible.

This is normally very appropriate since they don't have much reason to completely repaint themselves, they only draw their background. This matters in particular when the user resizes the window by dragging a corner, that can generate a storm of repaint requests. And if repainting is slow then that gets to be very visible, moving the mouse makes the motion "stutter", flicker can be noticeable as well.

But you care, you need to completely redraw the ellipse since you use the ClientSize property in your paint event handler.

Whether or not this optimization is turned on is determined by a style flag for the control, as Sriram pointed out. Turning this off is so common that Winforms exposed the style flag through a simple property to make it easier to change it:

    public Form1() {
InitializeComponent();
this.ResizeRedraw = true;
this.DoubleBuffered = true;
}

Note the DoubleBuffered property, another example of a convenience property that actually changed ControlStyles. You want this turned on to suppress the flicker your window exhibits. Caused by first drawing the background, which erases your ellipse, then repainting the ellipse.

There's another pretty serious problem in your code, SolidBrush is a disposable class. Disposing objects is optional, but skipping this for System.Drawing objects is quite unwise. If you resize your window frequently enough, 10000 times, then your program will crash. That sounds like a lot, but it is not when you set ResizeRedraw to true since that generates a lot of repaints. Only the garbage collector can keep you out of trouble, it won't in a simple program like this. Fix:

    protected override void OnPaint(PaintEventArgs e) {
using (var brush = new SolidBrush(this.ForeColor)) {
e.Graphics.FillEllipse(brush, 0, 0, this.ClientSize.Width, this.ClientSize.Height);
}
base.OnPaint(e);
}

Btw, do not optimize this by keeping the brush around as recommended in another post. Creating a brush is very cheap, takes about a microsecond. But is far too expensive to keep around, it is allocated on a heap that's shared by all programs that run on the desktop. A limited resource, that heap is small and programs start failing badly when the that heap is out of storage.

Problem when drawing on a Panel in Winform

this code will go in your form load event

Panel pHText = new Panel();
pHText.Name = "ctrId"; //specify control name, to access it in other parts of your code
pHText.Location = new Point(10, 10);
pHText.Size = new Size(200, 200);
pHText.BackColor = Color.White;
pHText.Paint += paintingUrCtr;//adding onpaint event
Controls.Add(pHText)

add paint event named paintingUrCtr.

private void paintingUrCtr(object sender, PaintEventArgs e)
{
Font myFont = new Font("Arial", 14);
e.Graphics.DrawLine(new Pen(Color.Black), 0, 0, 10, 10);
e.Graphics.DrawString("text", myFont, Brushes.Blue, 10, 10);
}

Drawing graphics when creating a new object

When you call Draw() method in constructor, the control has not yet been added to the parent, is just an object in memory, so the call has no effect.

If you make the call as you say in the OnPaint() method, then is drawed since this method is called whenever render the control is needed.



Related Topics



Leave a reply



Submit