C# paint program flickering

2019-03-29 20:24发布

I'm trying to make a simple paint program in C#, but it keeps flickering when I'm drawing, like I need some kind of double buffering, but I don't know how to do it.

I am drawing on a Panel and I'm using a Bitmap to store the graphics.

Here's my code:

public partial class Form1 : Form
{
    private Bitmap drawing;
    private bool leftDown = false;
    private int prevX;
    private int prevY;
    private int currentX;
    private int currentY;

    public Form1()
    {
        InitializeComponent();

        drawing = new Bitmap(panel1.Width, panel1.Height);
    }

    private void panel1_MouseDown(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            leftDown = true;

            prevX = e.X;
            prevY = e.Y;
        }
    }

    private void panel1_MouseMove(object sender, MouseEventArgs e)
    {
        if (leftDown)
        {
            Graphics g = Graphics.FromImage(drawing);

            currentX = e.X;
            currentY = e.Y;

            g.DrawLine(new Pen(Color.Black), new Point(currentX, currentY), new Point(prevX, prevY));
            panel1.Invalidate();

            prevX = currentX;
            prevY = currentY;

            g.Dispose();
        }
    }

    private void panel1_MouseUp(object sender, MouseEventArgs e)
    {
        leftDown = false;
    }

    private void panel1_MouseLeave(object sender, EventArgs e)
    {
        leftDown = false;
    }

    private void panel1_Paint(object sender, PaintEventArgs e)
    {
        e.Graphics.DrawImageUnscaled(drawing, 0, 0);
    }
}

4条回答
虎瘦雄心在
2楼-- · 2019-03-29 20:43

Normally, simply adding this.DoubleBuffered = true; in your code should do the trick.

If it does not, add this code to your form :

protected override CreateParams CreateParams
{
    get
    {
        CreateParams cp = base.CreateParams;
        cp.ExStyle |= 0x02000000;
        return cp;
    }
}

You can also change it using Reflection, but there is no advantage, neither readability or speed.

查看更多
欢心
3楼-- · 2019-03-29 20:53

You need to subclass Panel to do this, because you need to override certain things. A Panel like this should work:

class DoubleBufferedPanel : Panel {
    public DoubleBufferedPanel() : base() {
        this.SetStyle(ControlStyles.AllPaintingInWmPaint |
                      ControlStyles.DoubleBuffered |
                      ControlStyles.Opaque |
                      ControlStyles.OptimizedDoubleBuffer, true);
    }
    public override void OnPaint(PaintEventArgs e) {
        // Do your painting *here* instead, and don't call the base method.
    }

    // Override OnMouseMove, etc. here as well.
}

However, you don't need the functionality Panel adds to Control at all, that is for it to be functioning as a container. So, in fact, you should be inheriting from Control unless you need subcontrols.

Another improvement might be to only Invalidate with the Rectangle that changed. This will repaint one area and reduce drawing time. You can also pass a srcRect to Graphics.DrawImage, that srcRect being calculated from e.ClipRectangle, for even better performance if subclassing Panel doesn't work for you.

查看更多
Juvenile、少年°
4楼-- · 2019-03-29 20:54

When painting pixel maps in the Paint event, the flickering is often caused by Windows forms because it first draws the background and then the pixel map. So the flicker is the background that becomes visible for a fraction of a second.

You can set the Opaque style in the panel's ControlStyle property. That will turn of the background drawing because Windows Forms now assumes that your code will completely draw the contents of the panel.

查看更多
聊天终结者
5楼-- · 2019-03-29 20:59

You not only should turn DoubleBuffered to true, but also use PictureBox instead of Panel and draw on it. This should solve your issue :).

查看更多
登录 后发表回答