2

我有一个 WinForms 应用程序,我必须在控件之间画一些线。这些行需要持久化,所以我覆盖了表单OnPaint()事件。

问题是,重新绘制的线条不是很流畅。

我正在按如下方式创建图形:

Graphics g;
g = this.CreateGraphics();
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
g.FillRectangle(Brushes.White, this.ClientRectangle);

并绘制如下线条:

public void lineDraw(Control L1, Control L2) {            
    using (Pen pen = new Pen(Color.Black, 4)) {
        pen.StartCap = System.Drawing.Drawing2D.LineCap.Flat;
        pen.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;
        int x1, x2, y1, y2;
        //choose x/y coordinates
        g.DrawLine(pen, x1, y1, x2, y2);
    }
}

我可以设置任何属性来提高绘制图形的平滑度吗?

4

4 回答 4

4

目标

图像显示在控件(或窗体)上。

失效

每当控件(或表单)被调整大小、最小化/最大化、部分被遮挡或四处移动时,都必须(部分)重绘它。当这种情况发生时,必须重绘的控件部分被称为无效

无效时,控件会执行以下操作:

  1. Call OnPaintBackground:这用背景颜色填充无效区域。
  2. 调用OnPaint:这会在背景上绘制文本和图形。

为什么OnPaint会导致闪烁

您已经覆盖了控件的OnPaint方法。每次重绘控件时,您都会看到控件的闪烁,其中仅绘制了其背景颜色。即在OnPaintBackground被调用之后和之前OnPaint被调用。

解决方案

  • 如果你有一个静态图像(即它永远不会改变):

    1. Load事件中:创建一个新Bitmap对象
    2. 用背景颜色填充它并在其上绘制线条和形状。
    3. 将此Bitmap对象分配给控件的BackgroundImage属性
  • 如果您有一个在控件调整大小时必须调整大小的静态图像:

    1. 覆盖该OnResize方法并在其中创建新方法Bitmap。使用控件的ClientSize属性来确定Bitmap.
    2. 用背景颜色填充它并在其上绘制线条和形状。
    3. 将此Bitmap对象分配给控件的BackgroundImage属性。
  • 如果您有动画图像:

    1. Load事件中将控件的DoubleBuffered属性true设置为. 设置此项可防止您看到的闪烁,因为它使用不可见的缓冲区来绘制控件。
    2. 覆盖控件的OnPaint方法。获取控件的Graphics上下文,直接在控件上绘制线条和形状。
    3. 创建并启用一个新Timer对象,并在其回调方法中调用控件的Invalidate方法,然后调用该Update方法如此处所示)。例如,将计时器设置为每 40 毫秒触发一次。
于 2013-02-20T17:03:12.333 回答
2

您可能不应该CreateGraphics在这里使用,更重要的是,不要使用局部变量来存储图形对象。使用从绘制事件中获取的图形对象,并根据需要使之失效。

protected override void OnPaint(PaintEventArgs e) {
  e.Graphics.Clear(Color.White);
  e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;

  using (Pen pen = new Pen(Color.Black, 4)) {
    pen.StartCap = Drawing2D.LineCap.Flat;
    pen.EndCap = Drawing2D.LineCap.ArrowAnchor;
    int x1, x2, y1, y2;
    //choose x/y coordinates
    e.Graphics.DrawLine(pen, x1, y1, x2, y2);
  }

  base.OnPaint(e);
}
于 2013-02-20T17:13:53.447 回答
0

这是我的方式,它对我有用

//FormMain.cs
private const float DisplayRatio = 6;

private Bitmap _bmpDisp; //use an in-memory bitmap to Persistent graphics
private Graphics _grpDisp4Ctl;
private Graphics _grpDisp4Bmp;
private Point _ptOldDsp;


private void FormMain_Shown(object sender, EventArgs e)
{
    _grpDisp4Ctl = CreateGraphics();
    _grpDisp4Ctl.SetHighQulity();

    _bmpDisp = new Bitmap(ClientSize.Width, ClientSize.Height);
    _grpDisp4Bmp = Graphics.FromImage(_bmpDisp);
    _grpDisp4Bmp.SetHighQulity();

    _ptOldDsp = new Point(
        (int)((MousePosition.X - SystemInformation.VirtualScreen.Left) / DisplayRatio),
        (int)((MousePosition.Y - SystemInformation.VirtualScreen.Top) / DisplayRatio)
    );
}

private void UpdateDisplay(MouseHookEvent mhep) //your implement
{        
    var ptNew = mhep.Position;
    ptNew.Offset(new Point(-SystemInformation.VirtualScreen.Left, -SystemInformation.VirtualScreen.Top));
    ptNew.X = (int)(ptNew.X / DisplayRatio);
    ptNew.Y = (int)(ptNew.Y / DisplayRatio);

    _grpDisp4Ctl.DrawLine(Pens.White, _ptOldDsp, ptNew); //draw smooth lines to mem and ui
    _grpDisp4Bmp.DrawLine(Pens.White, _ptOldDsp, ptNew);

    _ptOldDsp = ptNew;

}

private void FormMain_Paint(object sender, PaintEventArgs e)
{
    // like vb6's auto redraw :)
    e.Graphics.DrawImage(_bmpDisp, e.ClipRectangle, e.ClipRectangle, GraphicsUnit.Pixel);
}

//common.cs
internal static void SetHighQulity(this Graphics g)
{
    g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
    g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
    g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
    g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
    g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
}
于 2015-01-30T08:31:52.540 回答
0

我知道这是一篇较旧的帖子,但您也可以尝试将表单的 DoubleBuffered 属性设置为 TRUE,请阅读以下内容:

“缓冲图形可以减少或消除由显示表面部分的渐进重绘引起的闪烁。缓冲图形要求首先将更新的图形数据写入缓冲区。然后将图形缓冲区中的数据快速写入显示的表面内存. 显示图形内存的相对快速切换通常会减少否则可能发生的闪烁。

于 2016-11-17T20:33:56.963 回答