【问题标题】:C# paint program flickeringC#画图程序闪烁
【发布时间】:2012-01-12 05:45:39
【问题描述】:

我正在尝试用 C# 编写一个简单的绘图程序,但在我绘图时它一直在闪烁,就像我需要某种双缓冲一样,但我不知道该怎么做。

我在Panel 上绘图,我正在使用Bitmap 来存储图形。

这是我的代码:

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

【问题讨论】:

  • 我认为您要查找的词是“闪烁”。如果您的计算机正在退缩,也许您应该对它好一点。
  • 啊,谢谢,我会编辑的! :-)
  • 使用双缓冲面板:stackoverflow.com/questions/3113190/…

标签: c# graphics bitmap gdi+ paint


【解决方案1】:

通常,只需在代码中添加 this.DoubleBuffered = true; 即可。

如果没有,请将此代码添加到您的表单中:

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

您也可以使用反射来更改它,但是没有优势,可读性和速度都没有。

【讨论】:

  • 但是我在面板上绘图,而不是在表单上,​​所以 this.DoubleBuffered = true 似乎没有奏效。该面板没有该属性。
  • NEVERMIND 哦 WPF,我会永远忘记它。这很奇怪,因为它使用 DirectX,并且应该自动双缓冲。
【解决方案2】:

在Paint 事件中绘制像素图时,闪烁往往是由Windows 窗体引起的,因为它先绘制背景,然后再绘制像素图。所以闪烁是在几分之一秒内变得可见的背景。

您可以在面板的ControlStyle 属性中设置Opaque 样式。这将关闭背景绘制,因为 Windows 窗体现在假定您的代码将完全绘制面板的内容。

【讨论】:

    【解决方案3】:

    您不仅应该将DoubleBuffered 转为true,还应使用PictureBox 而不是Panel 并在其上画画。这应该可以解决您的问题:)。

    【讨论】:

      【解决方案4】:

      您需要将 Panel 子类化才能执行此操作,因为您需要覆盖某些内容。像这样的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.
      }
      

      但是,您根本不需要 Panel 添加到 Control 的功能,因为它可以用作容器。所以,事实上,除非你需要子控件,否则你应该继承自 Control

      另一个改进可能是仅InvalidateRectangle 更改。这将重新绘制一个区域并减少绘制时间。您还可以将srcRect 传递给Graphics.DrawImage,即srcRect 是从e.ClipRectangle 计算出来的,如果子类化Panel 对您不起作用,则性能会更好。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-06-11
        • 2020-03-04
        • 2011-02-06
        • 1970-01-01
        • 1970-01-01
        • 2017-03-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多