永久图形WinForms

时间:2013-02-20 16:59:26

标签: c# winforms graphics persistent

我有一个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 个答案:

答案 0 :(得分:4)

目标

  

图像显示在控件(或表单)上。

失效

无论何时调整控件(或窗体)的大小,最小化/最大化,部分遮挡或移动,都必须(部分)重绘。发生这种情况时,必须重绘的控件部分被称为无效

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

  1. 调用OnPaintBackground:这会使用背景颜色填充无效区域。
  2. 致电OnPaint:这会在背景上绘制文字和图片。
  3. 为什么OnPaint会导致闪烁

    您已覆盖控件的OnPaint method。每次重绘控件时,您都会看到控件的闪光,其中仅绘制了背景颜色。这是在调用OnPaintBackground之后调用OnPaint之前。

    解决方案

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

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

      1. 覆盖OnResize method并在其中创建新的Bitmap。使用控件ClientSize property获取Bitmap
      2. 的大小
      3. 用背景颜色填充并在上面绘制线条和形状。
      4. 将此Bitmap对象分配给控件的BackgroundImage属性。
    • 如果您有动画图片:

      1. Load事件中,将控件的DoubleBuffered property设置为true。设置此项可防止您看到的闪烁,因为它使用不可见的缓冲区来绘制控件。
      2. 覆盖控件的OnPaint method。获取控件的Graphics context并直接在控件上绘制线条和形状。
      3. 创建并启用新的Timer object,并在其回调方法中调用控件的Invalidate method,然后调用Update methodas shown here)。将计时器设置为触发,例如,每40毫秒。

答案 1 :(得分:2)

你可能不应该在这里使用CreateGraphics,更重要的是,不要使用局部变量来存储图形对象。使用从paint事件获取的图形对象,并根据需要使其无效。

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

答案 2 :(得分: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;
}

答案 3 :(得分:0)

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

  

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