andrea225 发表于 2018-3-21 22:58

Winform 动态 画图 不闪

本帖最后由 andrea225 于 2018-3-22 15:42 编辑

 一、问题:解决winform动态画图闪的问题,网上搜的方法,大部分都是:


[*]“this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);”,甚至直接“this.DoubleBuffered = true;”。
[*]先 new 个Bitmap,画在Bitmap上,然后再把Bitmap画在界面上。
  凡是直接这么给人解答问题的,基本都是属于道听途说,自己没试过的。或者根本就没注意要解决的是“动态”的问题。

  二、解决方法:动态画图不闪的方法如下,先上效果图(请忽略鼠标样式,是gif录制软件的效果):

  https://images2015.cnblogs.com/blog/428620/201702/428620-20170209171031026-1879234951.gif

  三、代码:简单封了个自定义控件,用Action传入画图方法:
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="PictureBoxEx.cs" company="hyl">
//   hyl
// </copyright>
// <summary>
//   用Action传画图方法。不闪。
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace HYL
{
    using System;
    using System.Drawing;
    using System.Windows.Forms;

    public partial class PictureBoxEx : PictureBox
    {
      /// <summary>
      /// 画图方法
      /// </summary>
      private Action<Graphics> draw;

      public PictureBoxEx()
      {
            this.InitializeComponent();

            // 开双缓存(用这种方法,画图不太复杂的话,甚至不开也不闪。。。)
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
      }

      public void Rander(Action<Graphics> Draw)
      {
            this.Invalidate();
            this.draw = Draw;
      }

      protected override void OnPaint(PaintEventArgs pe)
      {
            base.OnPaint(pe);

            // 画图
            this.draw?.Invoke(pe.Graphics);
      }
    }
}
  重点在于要在 “OnPaint” 执行画图代码,也就是说要用 “OnPaint” 里的 “pe.Graphics” 来画。
  四、调用的方式如下:
namespace HYL
{
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Linq;
    using System.Windows.Forms;

    public partial class Form1 : Form
    {
      List<Line> lines = new List<Line>();

      private bool painting;

      public Form1()
      {
            this.InitializeComponent();
      }

      private void panel1_MouseDown(object sender, MouseEventArgs e)
      {
            if (e.Button == MouseButtons.Left)
            {
                // 左键确定点
                if (this.btnLine.Checked)
                {
                  this.lines.Last().Points.Add(new LinePoint { IsTemp = false, Point = e.Location });
                  this.painting = true;
                }
            }

            if (e.Button == MouseButtons.Right)
            {
                // 右键停止画图
                if (this.btnLine.Checked)
                {
                  this.ClearEmptyLines();
                }

                this.painting = false;
                this.btnLine.Checked = false;
            }
      }

      private void ClearEmptyLines()
      {
            this.lines = this.lines.Where(l => l.Points.Count > 1).ToList();
            if (this.lines.Count > 0)
            {
                var lastLine = this.lines.Last();
                lastLine.ClearTempPoints();
            }
      }

      private void panel1_MouseMove(object sender, MouseEventArgs e)
      {
            if (this.painting)
            {
                if (this.btnLine.Checked)
                {
                  this.PaintingLine(e);
                }

                this.Draw();
            }
      }

      private void PaintingLine(MouseEventArgs e)
      {
            var lastLine = this.lines.Last();
            var lastPoint = lastLine.Points.Last();

            if (lastPoint.IsTemp)
            {
                lastLine.Points.Remove(lastPoint);
            }

            LinePoint newPoint = new LinePoint { IsTemp = true, Point = e.Location };
            lastLine.Points.Add(newPoint);
      }

      /// <summary>
      /// 画图
      /// </summary>
      private void Draw()
      {
            Action<Graphics> draw = g =>
                {
                  Pen pen = new Pen(Color.Black, 2);
                  g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                  g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;

                  if (this.lines != null)
                  {
                        foreach (Line line in this.lines)
                        {
                            g.DrawLines(pen, line.GetPoints().ToArray());
                        }
                  }
                };

            this.pictureBoxEx1.Rander(draw);
      }

      private void btnLine_CheckedChanged(object sender, EventArgs e)
      {
            if (this.btnLine.Checked)
            {
                this.lines.Add(new Line());
            }
            else
            {
                this.ClearEmptyLines();
                this.painting = false;
                this.Draw();
            }
      }
    }

    public class Line : ShapeElement
    {
      public Line()
      {
            this.Points = new List<LinePoint>();
      }

      // 线里的点
      public IList<LinePoint> Points { get; set; }

      // 获取Point的集合
      public IList<Point> GetPoints()
      {
            return this.Points.Select(p => p.Point).ToList();
      }

      // 清理临时点
      public void ClearTempPoints()
      {
            this.Points = this.Points.Where(p => !p.IsTemp).ToList();
      }
    }

    public class LinePoint
    {
      public Point Point { get; set; }

      // 是否临时点
      public bool IsTemp { get; set; }
    }
}

wushaominkk 发表于 2018-3-22 10:01

鼓励新人发帖,吾爱因你更精彩!

peterq521 发表于 2018-3-22 10:05

楼主能否做一个简易的成品工具 方便一键操作多谢

认定666 发表于 2018-3-22 10:38

效果图一直看不了,我换了几个浏览器了,都还是刷不出,是不是楼主放图片的时候上传出了什么故障呀?
一开始我还以为是我Chrome的加载Flash插件的问题,后来查了一下,没有问题呀,也换了几个浏览器试了,也是刷不出图片。
会不会是运营商劫持或者其他原因。

andrea225 发表于 2018-3-22 15:43

认定666 发表于 2018-3-22 10:38
效果图一直看不了,我换了几个浏览器了,都还是刷不出,是不是楼主放图片的时候上传出了什么故障呀?
一开 ...

修复了,不好意思,原来图片是上传到博客园的,可能被屏蔽了。
页: [1]
查看完整版本: Winform 动态 画图 不闪