简体   繁体   English

C#绘图程序闪烁

[英]C# paint program flickering

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. 我正在尝试用C#制作一个简单的绘图程序,但是当我绘图时它会一直闪烁,就像我需要某种双缓冲一样,但我不知道该怎么做。

I am drawing on a Panel and I'm using a Bitmap to store the graphics. 我正在绘制一个Panel ,我正在使用Bitmap来存储图形。

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

You not only should turn DoubleBuffered to true , but also use PictureBox instead of Panel and draw on it. 您不仅应该将DoubleBuffered转为true ,还要使用PictureBox而不是Panel并在其上绘制。 This should solve your issue :). 这应该解决你的问题:)。

You need to subclass Panel to do this, because you need to override certain things. 您需要子类化Panel才能执行此操作,因为您需要覆盖某些内容。 A Panel like this should work: 像这样的Panel应该工作:

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. 但是,您根本不需要Panel添加到Control的功能,即它可以作为容器运行。 So, in fact, you should be inheriting from Control unless you need subcontrols. 所以,事实上,除非你需要子Control否则你应该从Control继承。

Another improvement might be to only Invalidate with the Rectangle that changed. 另一个改进可能是仅对已更改的Rectangle进行Invalidate 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. 您也可以通过一个srcRectGraphics.DrawImage ,即srcRect是从计算e.ClipRectangle ,甚至更好的性能,如果子类Panel不会为你工作。

Normally, simply adding this.DoubleBuffered = true; 通常,只需添加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. 您也可以使用Reflection更改它,但没有优势,无论是可读性还是速度。

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. 在Paint事件中绘制像素贴图时,闪烁通常是由Windows窗体引起的,因为它首先绘制背景,然后绘制像素贴图。 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. 您可以在面板的ControlStyle属性中设置Opaque样式。 That will turn of the background drawing because Windows Forms now assumes that your code will completely draw the contents of the panel. 这将转变背景图,因为Windows窗体现在假定您的代码将完全绘制面板的内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM