该控件的拼图滑块部分有锯齿,你可以优化这些锯齿已达到最好的效果。
/// <summary> /// 拼图滑块验证控件 /// </summary> [ToolboxItem(true)] [DefaultEvent("ValidPass")] [DefaultProperty("ValidImage")] [Description("拼图滑块验证控件")] public partial class JigsawSlideValidExt : Control { #region public delegate void ValidEventHandler(object sender, JigsawValidEventArgs e); private event ValidEventHandler validPass; /// <summary> /// 拼图验证事件 /// </summary> [Description("拼图验证事件")] public event ValidEventHandler ValidPass { add { this.validPass += value; } remove { this.validPass -= value; } } private JigsawSlideType slideType = JigsawSlideType.One; /// <summary> /// 滑块类型 /// </summary> [DefaultValue(JigsawSlideType.One)] [Description("滑块类型")] public JigsawSlideType SlideType { get { return this.slideType; } set { this.slideType = value; this.ResetJigsaw(); this.InitializeJigsawDisplay(); this.Invalidate(); } } private int slideSize = 36; /// <summary> /// 滑块大小 /// </summary> [DefaultValue(36)] [Description("滑块大小")] public int SlideSize { get { return this.slideSize; } set { if (this.slideSize == value || value < 0) return; this.slideSize = value; this.InitializeJigsawDisplay(); this.Invalidate(); } } private Color validBlackColor = Color.FromArgb(60, 0, 0, 0); /// <summary> /// 验证拼图背景颜色 /// </summary> [DefaultValue(typeof(Color), "60, 0, 0, 0")] [Description("验证拼图背景颜色")] [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))] public Color ValidBlackColor { get { return this.validBlackColor; } set { if (this.validBlackColor == value) return; this.validBlackColor = value; this.Invalidate(); } } private Color slideBorderColor = Color.FromArgb(60, 0, 0, 0); /// <summary> /// 滑块拼图边框颜色 /// </summary> [DefaultValue(typeof(Color), "60, 0, 0, 0")] [Description("滑块拼图边框颜色")] [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))] public Color SlideBorderColor { get { return this.slideBorderColor; } set { if (this.slideBorderColor == value) return; this.slideBorderColor = value; this.Invalidate(); } } private bool pass = false; /// <summary> /// 验证结果 /// </summary> [Browsable(false)] [Description("验证结果")] public bool Pass { get { return this.pass; } } private Image validImage = (Image)null; /// <summary> /// 验证图片 /// </summary> [Description("验证图片")] public Image ValidImage { get { return this.validImage; } set { if (this.validImage == value) return; this.validImage = value; this.InitializeJigsawDisplay(); this.Invalidate(); } } protected override Size DefaultSize { get { return new Size(300, 200); } } #region 验证滑块 /// <summary> /// 验证滑块rectf /// </summary> private RectangleF valid_rectf = RectangleF.Empty; private GraphicsPath valid_gp = new GraphicsPath(); private PointF valid_start_pointf = PointF.Empty; #endregion #region 滑块一 /// <summary> /// 滑块一rectf /// </summary> private RectangleF one_rectf = RectangleF.Empty; /// <summary> /// 滑块一形状路径 /// </summary> private GraphicsPath one_gp = new GraphicsPath(); /// <summary> /// 滑块一开始坐标 /// </summary> private PointF one_start_pointf = new PointF(10, 0); /// <summary> /// 滑块一移动距离 /// </summary> private PointF one_move_pointf = PointF.Empty; /// <summary> /// 滑块一图片 /// </summary> private Bitmap one_bmp = null; #endregion #region 滑块二 /// <summary> /// 滑块二rectf /// </summary> private RectangleF two_rectf = RectangleF.Empty; /// <summary> /// 滑块二形状路径 /// </summary> private GraphicsPath two_gp = new GraphicsPath(); /// <summary> /// 滑块二开始坐标 /// </summary> private PointF two_start_pointf = new PointF(10, 0); /// <summary> /// 滑块二移动距离 /// </summary> private PointF two_move_pointf = PointF.Empty; /// <summary> /// 滑块二图片 /// </summary> private Bitmap two_bmp = null; #endregion #region 滑块三 /// <summary> /// 滑块三rectf /// </summary> private RectangleF three_rectf = RectangleF.Empty; /// <summary> /// 滑块三形状路径 /// </summary> private GraphicsPath three_gp = new GraphicsPath(); /// <summary> /// 滑块三开始坐标 /// </summary> private PointF three_start_pointf = new PointF(10, 0); /// <summary> /// 滑块三移动距离 /// </summary> private PointF three_move_pointf = PointF.Empty; /// <summary> /// 滑块三图片 /// </summary> private Bitmap three_bmp = null; #endregion /// <summary> /// 拼图形状索引列表 /// </summary> private List<int> shapeIndexList = new List<int>(); /// <summary> /// 可以通过验证的滑块索引 /// </summary> private int passSlideIndex = -1; /// <summary> /// 鼠标是否按下 /// </summary> private bool moveDown = false; /// <summary> /// 鼠标按下坐标 /// </summary> private Point moveDownPoint = Point.Empty; /// <summary> /// 鼠标选中滑块索引 /// </summary> private int moveDownSlideIndex = -1; #endregion public JigsawSlideValidExt() { SetStyle(ControlStyles.UserPaint, true); SetStyle(ControlStyles.AllPaintingInWmPaint, true); SetStyle(ControlStyles.OptimizedDoubleBuffer, true); SetStyle(ControlStyles.ResizeRedraw, true); SetStyle(ControlStyles.SupportsTransparentBackColor, true); InitializeComponent(); this.shapeIndexList = this.GetJigsawSlideIndex(this.SlideType); this.InitializeJigsawDisplay(); this.Invalidate(); } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); if (this.ValidImage == null || this.shapeIndexList.Count < 1) return; Graphics g = e.Graphics; g.SmoothingMode = SmoothingMode.HighQuality; RectangleF bounds_rect = g.ClipBounds; #region 绘制背景 g.DrawImage(this.ValidImage, new System.Drawing.PointF(0, 0)); #endregion #region 绘制拼图 SolidBrush sb_valid = new SolidBrush(this.ValidBlackColor); g.FillPath(sb_valid, this.valid_gp); sb_valid.Dispose(); if (this.slideType == JigsawSlideType.One || this.slideType == JigsawSlideType.Two || this.slideType == JigsawSlideType.Three) { if (this.one_bmp != null) { g.DrawImage(this.one_bmp, this.one_gp.GetBounds().Location); } float x = this.one_start_pointf.X + this.one_move_pointf.X; if (x < this.valid_start_pointf.X - this.one_gp.GetBounds().Width / 5f || x > this.valid_start_pointf.X + this.one_gp.GetBounds().Width / 5f) { Pen pen_one = new Pen(this.SlideBorderColor); g.DrawPath(pen_one, this.one_gp); pen_one.Dispose(); } } if (this.slideType == JigsawSlideType.Two || this.slideType == JigsawSlideType.Three) { if (this.two_bmp != null) { g.DrawImage(this.two_bmp, this.two_gp.GetBounds().Location); } float x = this.two_start_pointf.X + this.two_move_pointf.X; if (x < this.valid_start_pointf.X - this.two_gp.GetBounds().Width / 5f || x > this.valid_start_pointf.X + this.two_gp.GetBounds().Width / 5f) { Pen pen_two = new Pen(this.SlideBorderColor); g.DrawPath(pen_two, this.two_gp); pen_two.Dispose(); } } if (this.slideType == JigsawSlideType.Three) { if (this.three_bmp != null) { g.DrawImage(this.three_bmp, this.three_gp.GetBounds().Location); } float x = this.three_start_pointf.X + this.three_move_pointf.X; if (x < this.valid_start_pointf.X - this.three_gp.GetBounds().Width / 5f || x > this.valid_start_pointf.X + this.three_gp.GetBounds().Width / 5f) { Pen pen_three = new Pen(this.SlideBorderColor); g.DrawPath(pen_three, this.three_gp); pen_three.Dispose(); } } #endregion } protected override void OnMouseDown(MouseEventArgs e) { if (this.pass == true) return; if (!this.moveDown) { if (this.slideType == JigsawSlideType.One) { if (this.one_gp.IsVisible(e.Location)) { this.moveDownSlideIndex = 1; this.moveDown = true; this.moveDownPoint = e.Location; } } else if (this.slideType == JigsawSlideType.Two) { if (this.one_gp.IsVisible(e.Location)) { this.moveDownSlideIndex = 1; this.moveDown = true; this.moveDownPoint = e.Location; } else if (this.two_gp.IsVisible(e.Location)) { this.moveDownSlideIndex = 2; this.moveDown = true; this.moveDownPoint = e.Location; } } else if (this.slideType == JigsawSlideType.Three) { if (this.one_gp.IsVisible(e.Location)) { this.moveDownSlideIndex = 1; this.moveDown = true; this.moveDownPoint = e.Location; } else if (this.two_gp.IsVisible(e.Location)) { this.moveDownSlideIndex = 2; this.moveDown = true; this.moveDownPoint = e.Location; } else if (this.three_gp.IsVisible(e.Location)) { this.moveDownSlideIndex = 3; this.moveDown = true; this.moveDownPoint = e.Location; } } } } protected override void OnMouseUp(MouseEventArgs e) { if (this.pass == true) return; if (this.moveDown) { this.moveDown = false; this.ValidJigsaw(); if (!this.pass) { this.one_move_pointf = new PointF(0, 0); this.two_move_pointf = new PointF(0, 0); this.three_move_pointf = new PointF(0, 0); float radius = this.SlideSize / 4f; #region if (this.moveDownSlideIndex == 1) { RectangleF rectf_one = new RectangleF(this.one_start_pointf.X + this.one_move_pointf.X, this.one_start_pointf.Y + (this.one_move_pointf.X * (this.valid_start_pointf.Y - this.one_start_pointf.Y) / (this.valid_start_pointf.X - this.one_start_pointf.X)), this.SlideSize + radius * 2f, this.SlideSize + radius * 2f); this.one_gp.Reset(); this.GetPath(this.shapeIndexList[0], this.one_gp, rectf_one); } else if (this.moveDownSlideIndex == 2) { RectangleF rectf_two = new RectangleF(this.two_start_pointf.X + this.two_move_pointf.X, this.two_start_pointf.Y - (this.two_move_pointf.X * (this.valid_start_pointf.Y - this.two_start_pointf.Y) / (this.valid_start_pointf.X - this.two_start_pointf.X)), this.SlideSize + radius * 2f, this.SlideSize + radius * 2f); this.two_gp.Reset(); this.GetPath(this.shapeIndexList[1], this.two_gp, rectf_two); } else if (this.moveDownSlideIndex == 3) { RectangleF rectf_three = new RectangleF(this.three_start_pointf.X, this.three_start_pointf.Y, this.SlideSize + radius * 2f, this.SlideSize + radius * 2f); this.three_gp.Reset(); this.GetPath(this.shapeIndexList[2], this.three_gp, rectf_three); } this.moveDownSlideIndex = -1; #endregion this.Invalidate(); } } } protected override void OnMouseLeave(EventArgs e) { if (this.pass == true) return; this.moveDown = false; this.moveDownSlideIndex = -1; } protected override void OnMouseMove(MouseEventArgs e) { if (this.pass == true) return; if (this.moveDown) { #region 更新选中滑块移动距离 PointF p = new PointF(e.Location.X - this.moveDownPoint.X, e.Location.Y - this.moveDownPoint.Y); if (this.moveDownSlideIndex == 1) { if (this.one_start_pointf.X + p.X < this.one_start_pointf.X) p.X = this.one_start_pointf.X; if (this.one_start_pointf.X + p.X > this.ClientRectangle.Right - this.one_rectf.Width) p.X = this.ClientRectangle.Right - this.one_rectf.Width; this.one_move_pointf = p; } else if (this.moveDownSlideIndex == 2) { if (this.two_start_pointf.X + p.X < this.two_start_pointf.X) p.X = this.two_start_pointf.X; if (this.two_start_pointf.X + p.X > this.ClientRectangle.Right - this.two_rectf.Width) p.X = this.ClientRectangle.Right - this.two_rectf.Width; this.two_move_pointf = p; } else if (this.moveDownSlideIndex == 3) { if (this.three_start_pointf.X + p.X < this.three_start_pointf.X) p.X = this.three_start_pointf.X; if (this.three_start_pointf.X + p.X > this.ClientRectangle.Right - this.three_rectf.Width) p.X = this.ClientRectangle.Right - this.three_rectf.Width; this.three_move_pointf = p; } #endregion #region 更新滑块GraphicsPath float radius = this.SlideSize / 4f; if (this.SlideType == JigsawSlideType.One) { if (this.moveDownSlideIndex == 1) { RectangleF rectf_one = new RectangleF(this.one_start_pointf.X + this.one_move_pointf.X, this.one_start_pointf.Y, this.SlideSize + radius * 2, this.SlideSize + radius * 2); this.one_gp.Reset(); this.GetPath(this.shapeIndexList[0], this.one_gp, rectf_one); } } if (this.SlideType == JigsawSlideType.Two) { if (this.moveDownSlideIndex == 1) { RectangleF rectf_one = new RectangleF(this.one_start_pointf.X + this.one_move_pointf.X, this.one_start_pointf.Y + (this.one_move_pointf.X * (this.valid_start_pointf.Y - this.one_start_pointf.Y) / (this.valid_start_pointf.X - this.one_start_pointf.X)), this.SlideSize + radius * 2, this.SlideSize + radius * 2); this.one_gp.Reset(); this.GetPath(this.shapeIndexList[0], this.one_gp, rectf_one); } else if (this.moveDownSlideIndex == 2) { RectangleF rectf_two = new RectangleF(this.two_start_pointf.X + this.two_move_pointf.X, this.two_start_pointf.Y + (this.two_move_pointf.X * (this.valid_start_pointf.Y - this.two_start_pointf.Y) / (this.valid_start_pointf.X - this.two_start_pointf.X)), this.SlideSize + radius * 2, this.SlideSize + radius * 2); this.two_gp.Reset(); this.GetPath(this.shapeIndexList[1], this.two_gp, rectf_two); } } if (this.SlideType == JigsawSlideType.Three) { if (this.moveDownSlideIndex == 1) { RectangleF rectf_one = new RectangleF(this.one_start_pointf.X + this.one_move_pointf.X, this.one_start_pointf.Y + (this.one_move_pointf.X * (this.valid_start_pointf.Y - this.one_start_pointf.Y) / (this.valid_start_pointf.X - this.one_start_pointf.X)), this.SlideSize + radius * 2, this.SlideSize + radius * 2); this.one_gp.Reset(); this.GetPath(this.shapeIndexList[0], this.one_gp, rectf_one); } else if (this.moveDownSlideIndex == 2) { RectangleF rectf_two = new RectangleF(this.two_start_pointf.X + this.two_move_pointf.X, this.two_start_pointf.Y + (this.two_move_pointf.X * (this.valid_start_pointf.Y - this.two_start_pointf.Y) / (this.valid_start_pointf.X - this.two_start_pointf.X)), this.SlideSize + radius * 2, this.SlideSize + radius * 2); this.two_gp.Reset(); this.GetPath(this.shapeIndexList[1], this.two_gp, rectf_two); } else if (this.moveDownSlideIndex == 3) { RectangleF rectf_three = new RectangleF(this.three_start_pointf.X + this.three_move_pointf.X, this.three_start_pointf.Y + (this.three_move_pointf.X * (this.valid_start_pointf.Y - this.three_start_pointf.Y) / (this.valid_start_pointf.X - this.three_start_pointf.X)), this.SlideSize + radius * 2, this.SlideSize + radius * 2); this.three_gp.Reset(); this.GetPath(this.shapeIndexList[2], this.three_gp, rectf_three); } } #endregion this.Invalidate(); } } protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); if (this.valid_gp != null) this.valid_gp.Dispose(); if (this.one_gp != null) this.one_gp.Dispose(); if (this.one_bmp != null) this.one_bmp.Dispose(); if (this.two_gp != null) this.two_gp.Dispose(); if (this.two_bmp != null) this.two_bmp.Dispose(); if (this.three_gp != null) this.three_gp.Dispose(); if (this.three_bmp != null) this.three_bmp.Dispose(); } base.Dispose(disposing); } /// <summary> /// 初始化拼图滑块信息 /// </summary> protected void InitializeJigsawDisplay() { if (this.ValidImage == null || this.shapeIndexList.Count < 1) return; this.pass = false; if (this.one_bmp != null) this.one_bmp.Dispose(); if (this.two_bmp != null) this.two_bmp.Dispose(); if (this.three_bmp != null) this.three_bmp.Dispose(); Rectangle rect = this.ClientRectangle; float radius = this.SlideSize / 4f; #region 滑块信息 if (this.SlideType == JigsawSlideType.One)//一个滑块 { this.one_start_pointf.Y = (float)(rect.Height - this.SlideSize) / 2f; } else if (this.SlideType == JigsawSlideType.Two)//二个滑块 { float height = (float)(rect.Height - this.SlideSize * 2); this.one_start_pointf.Y = height / 3f; this.two_start_pointf.Y = height / 3f + this.SlideSize + height / 3f; } else if (this.SlideType == JigsawSlideType.Three)//三个滑块 { float height = (float)(rect.Height - this.SlideSize * 3); this.one_start_pointf.Y = height / 4f; this.two_start_pointf.Y = height / 4f + this.SlideSize + height / 4f; this.three_start_pointf.Y = height / 4f + this.SlideSize + height / 4f + this.SlideSize + height / 4f; } Random rd = new Random(); this.valid_start_pointf = new PointF(((float)rect.Width - this.SlideSize * 3f) + (float)rd.Next(0, this.SlideSize), (float)(rect.Height - this.SlideSize) / 2f); this.valid_rectf = new RectangleF(this.valid_start_pointf.X, this.valid_start_pointf.Y, this.SlideSize + radius * 2, this.SlideSize + radius * 2); this.valid_gp.Reset(); this.GetPath(this.shapeIndexList[this.passSlideIndex - 1], this.valid_gp, this.valid_rectf); #endregion #region if (this.SlideType == JigsawSlideType.One || this.SlideType == JigsawSlideType.Two || this.SlideType == JigsawSlideType.Three) { this.one_rectf = new RectangleF(this.one_start_pointf.X, this.one_start_pointf.Y, this.SlideSize + radius * 2f, this.SlideSize + radius * 2f); this.one_gp.Reset(); this.GetPath(this.shapeIndexList[0], this.one_gp, this.one_rectf); GraphicsPath gp_one_tmp = (GraphicsPath)this.one_gp.Clone(); Matrix matrix = new Matrix(); matrix.Translate(this.valid_rectf.Left - this.one_rectf.Left, this.valid_rectf.Top - this.one_rectf.Top); gp_one_tmp.Transform(matrix); this.one_bmp = CutBitmap((Bitmap)this.ValidImage, gp_one_tmp); gp_one_tmp.Dispose(); matrix.Dispose(); } if (this.SlideType == JigsawSlideType.Two || this.SlideType == JigsawSlideType.Three) { this.two_rectf = new RectangleF(this.two_start_pointf.X, this.two_start_pointf.Y, this.SlideSize + radius * 2f, this.SlideSize + radius * 2f); this.two_gp.Reset(); this.GetPath(this.shapeIndexList[1], this.two_gp, this.two_rectf); GraphicsPath gp_two_tmp = (GraphicsPath)this.two_gp.Clone(); Matrix matrix = new Matrix(); matrix.Translate(this.valid_rectf.Left - this.two_rectf.Left, this.valid_rectf.Top - this.two_rectf.Top); gp_two_tmp.Transform(matrix); this.two_bmp = CutBitmap((Bitmap)this.ValidImage, gp_two_tmp); gp_two_tmp.Dispose(); matrix.Dispose(); } if (this.SlideType == JigsawSlideType.Three) { this.three_rectf = new RectangleF(this.three_start_pointf.X, this.three_start_pointf.Y, this.SlideSize + radius * 2, this.SlideSize + radius * 2); this.three_gp.Reset(); this.GetPath(this.shapeIndexList[2], this.three_gp, this.three_rectf); GraphicsPath gp_three_tmp = (GraphicsPath)this.three_gp.Clone(); Matrix matrix = new Matrix(); matrix.Translate(this.valid_rectf.Left - this.three_rectf.Left, this.valid_rectf.Top - this.three_rectf.Top); gp_three_tmp.Transform(matrix); this.three_bmp = CutBitmap((Bitmap)this.ValidImage, gp_three_tmp); gp_three_tmp.Dispose(); matrix.Dispose(); } #endregion } /// <summary> /// 更新验证码 /// </summary> public void ResetJigsaw() { this.pass = false; this.one_move_pointf = new PointF(20, 0); this.two_move_pointf = new PointF(10, 0); this.three_move_pointf = new PointF(10, 0); this.passSlideIndex = -1; this.moveDown = false; this.moveDownPoint = Point.Empty; this.moveDownSlideIndex = -1; this.shapeIndexList = this.GetJigsawSlideIndex(this.SlideType); this.InitializeJigsawDisplay(); this.Invalidate(); } /// <summary> /// 通过验证 /// </summary> /// <returns></returns> private void ValidJigsaw() { if (this.moveDownSlideIndex > -1) { JigsawValidEventArgs data = new JigsawValidEventArgs(); if (this.moveDownSlideIndex == 1 && this.passSlideIndex == 1) { PointF p = new PointF(this.one_start_pointf.X + this.one_move_pointf.X, this.one_start_pointf.Y + this.one_move_pointf.Y); this.pass = (Math.Abs(this.valid_start_pointf.X - p.X) < 2); data.Pass = this.pass; } else if (this.moveDownSlideIndex == 2 && this.passSlideIndex == 2) { PointF p = new PointF(this.two_start_pointf.X + this.two_move_pointf.X, this.two_start_pointf.Y + this.two_move_pointf.Y); this.pass = (Math.Abs(this.valid_start_pointf.X - p.X) < 2); data.Pass = this.pass; } else if (this.moveDownSlideIndex == 3 && this.passSlideIndex == 3) { PointF p = new PointF(this.three_start_pointf.X + this.three_move_pointf.X, this.three_start_pointf.Y + this.three_move_pointf.Y); this.pass = (Math.Abs(this.valid_start_pointf.X - p.X) < 2); data.Pass = this.pass; } else { this.pass = false; } if (this.validPass != null) { this.validPass(this, data); } } } /// <summary> /// 截取图片 /// </summary> /// <param name="bmp">原图</param> /// <param name="gp">截取路径</param> /// <returns></returns> private Bitmap CutBitmap(Bitmap bmp, GraphicsPath gp) { RectangleF rect = gp.GetBounds(); int top = (int)rect.Top; int left = (int)rect.Left; ; int width = (int)rect.Width; int height = (int)rect.Height; Bitmap bmp_result = new Bitmap(width, height); Color transparent = Color.FromArgb(0, 255, 255, 255); for (int i = left; i < left + width; i++) { for (int j = top; j < top + height; j++) { if (i < bmp.Width && j < bmp.Height && gp.IsVisible(i, j)) { bmp_result.SetPixel(i - left, j - top, bmp.GetPixel(i, j)); } else { bmp_result.SetPixel(i - left, j - top, transparent); } } } return bmp_result; } /// <summary> /// 获取拼图形状索引列表 /// </summary> /// <param name="slideType">拼图滑块类型</param> /// <returns></returns> private List<int> GetJigsawSlideIndex(JigsawSlideType slideType) { int length = 0; switch (slideType) { case JigsawSlideType.One: length = 1; break; case JigsawSlideType.Two: length = 2; break; case JigsawSlideType.Three: length = 3; break; } List<int> indexList = new List<int>(); int index = 0; for (int i = 0; i < length; i++) { while (true) { Random rd_index = new Random(); index = rd_index.Next(JigsawAllShape.Keys.First(), JigsawAllShape.Keys.Last()); if (indexList.IndexOf(index) == -1) { indexList.Add(index); break; } } } Random rd_valid = new Random(); this.passSlideIndex = rd_valid.Next(1, indexList.Count); return indexList; } /// <summary> /// 获取拼图路径 /// </summary> /// <param name="shapeIndex">拼图所有的图案(16种)索引</param> /// <param name="gp"></param> /// <param name="rectf"></param> /// <returns></returns> private GraphicsPath GetPath(int shapeIndex, GraphicsPath gp, RectangleF rectf) { rectf = new RectangleF(rectf.Left + rectf.Width / 8, rectf.Top + rectf.Height / 8, rectf.Width / 4f * 3f, rectf.Height / 4f * 3f); this.Draw_Jiao_LtftTop(gp, rectf); this.DrawJigsaw(JigsawBorderType.Top, JigsawAllShape[shapeIndex][0], gp, rectf); this.Draw_Jiao_RightTop(gp, rectf); this.DrawJigsaw(JigsawBorderType.Right, JigsawAllShape[shapeIndex][1], gp, rectf); this.Draw_Jiao_RightBottom(gp, rectf); this.DrawJigsaw(JigsawBorderType.Bottom, JigsawAllShape[shapeIndex][2], gp, rectf); this.Draw_Jiao_LeftBottom(gp, rectf); this.DrawJigsaw(JigsawBorderType.Left, JigsawAllShape[shapeIndex][3], gp, rectf); gp.CloseFigure(); return gp; } /// <summary> /// 绘制拼图四边的形状 /// </summary> /// <param name="orientation">拼图指定方向形状</param> /// <param name="shapeType">填充拼图指定边的指定形状(6、8、9)</param> /// <param name="gp"></param> /// <param name="rectf">拼图rectf</param> private void DrawJigsaw(JigsawBorderType orientation, int shapeType, GraphicsPath gp, RectangleF rectf) { switch (orientation) { #region case JigsawBorderType.Top: { switch (shapeType) { case 6: { this.Draw_TU_Top(gp, rectf); break; } case 8: { break; } case 9: { this.Draw_AO_Top(gp, rectf); break; } } break; } #endregion #region case JigsawBorderType.Right: { switch (shapeType) { case 6: { this.Draw_TU_Right(gp, rectf); break; } case 8: { break; } case 9: { this.Draw_AO_Right(gp, rectf); break; } } break; } #endregion #region case JigsawBorderType.Bottom: { switch (shapeType) { case 6: { this.Draw_TU_Bottom(gp, rectf); break; } case 8: { break; } case 9: { this.Draw_AO_Bottom(gp, rectf); break; } } break; } #endregion #region case JigsawBorderType.Left: { switch (shapeType) { case 6: { this.Draw_TU_Left(gp, rectf); break; } case 8: { break; } case 9: { this.Draw_AO_Left(gp, rectf); break; } } break; } #endregion } } #region 绘制拼图角 /// <summary> /// 绘制拼图左上角 /// </summary> /// <param name="gp"></param> /// <param name="rectf"></param> public void Draw_Jiao_LtftTop(GraphicsPath gp, RectangleF rectf) { gp.AddLine(new PointF(rectf.Left, rectf.Top), new PointF(rectf.Left, rectf.Top)); } /// <summary> /// 绘制拼图右上角 /// </summary> /// <param name="gp"></param> /// <param name="rectf"></param> public void Draw_Jiao_RightTop(GraphicsPath gp, RectangleF rectf) { gp.AddLine(new PointF(rectf.Right, rectf.Top), new PointF(rectf.Right, rectf.Top)); } /// <summary> /// 绘制拼图右下角 /// </summary> /// <param name="gp"></param> /// <param name="rectf"></param> public void Draw_Jiao_RightBottom(GraphicsPath gp, RectangleF rectf) { gp.AddLine(new PointF(rectf.Right, rectf.Bottom), new PointF(rectf.Right, rectf.Bottom)); } /// <summary> /// 绘制拼图左下角 /// </summary> /// <param name="gp"></param> /// <param name="rectf"></param> public void Draw_Jiao_LeftBottom(GraphicsPath gp, RectangleF rectf) { gp.AddLine(new PointF(rectf.Left, rectf.Bottom), new PointF(rectf.Left, rectf.Bottom)); } #endregion #region 绘制拼图凸线 /// <summary> /// 绘制拼图顶部凹线 /// </summary> /// <param name="gp"></param> /// <param name="rect"></param> public void Draw_TU_Top(GraphicsPath gp, RectangleF rect) { gp.AddArc(new RectangleF(rect.Left + rect.Width / 3f, (rect.Top - rect.Width / 3f / 2f), rect.Width / 3f, rect.Width / 3f), 180, 180); } /// <summary> /// 绘制拼图右边凹线 /// </summary> /// <param name="gp"></param> /// <param name="rect"></param> public void Draw_TU_Right(GraphicsPath gp, RectangleF rect) { gp.AddArc(new RectangleF(rect.Right - rect.Width / 3f / 2f, rect.Top + rect.Height / 3f, rect.Width / 3f, rect.Width / 3f), 270, 180); } /// <summary> /// 绘制拼图底部凹线 /// </summary> /// <param name="gp"></param> /// <param name="rect"></param> public void Draw_TU_Bottom(GraphicsPath gp, RectangleF rect) { gp.AddArc(new RectangleF(rect.Left + rect.Width / 3f, (rect.Bottom - rect.Width / 3f / 2f), rect.Width / 3f, rect.Width / 3f), 0, 180); } /// <summary> /// 绘制拼图左边凹线 /// </summary> /// <param name="gp"></param> /// <param name="rect"></param> public void Draw_TU_Left(GraphicsPath gp, RectangleF rect) { gp.AddArc(new RectangleF(rect.Left - rect.Width / 3f / 2f, rect.Top + rect.Height / 3f, rect.Width / 3f, rect.Width / 3f), 90, 180); } #endregion #region 绘制拼图凹线 /// <summary> /// 绘制拼图顶部凹线 /// </summary> /// <param name="gp"></param> /// <param name="rectf"></param> public void Draw_AO_Top(GraphicsPath gp, RectangleF rectf) { GraphicsPath gp_tmp = new GraphicsPath(); gp_tmp.AddArc(new RectangleF(rectf.Left + rectf.Width / 3f, (rectf.Top - rectf.Width / 3f / 2f), rectf.Width / 3f, rectf.Width / 3f), 0, 180); gp_tmp.Reverse(); gp.AddPath(gp_tmp, true); } /// <summary> /// 绘制拼图右边凹线 /// </summary> /// <param name="gp"></param> /// <param name="rectf"></param> public void Draw_AO_Right(GraphicsPath gp, RectangleF rectf) { GraphicsPath gp_tmp = new GraphicsPath(); gp_tmp.AddArc(new RectangleF(rectf.Right - rectf.Width / 3f / 2f, rectf.Top + rectf.Height / 3f, rectf.Width / 3f, rectf.Width / 3f), 90, 180); gp_tmp.Reverse(); gp.AddPath(gp_tmp, true); } /// <summary> /// 绘制拼图底部凹线 /// </summary> /// <param name="gp"></param> /// <param name="rectf"></param> public void Draw_AO_Bottom(GraphicsPath gp, RectangleF rectf) { GraphicsPath gp_tmp = new GraphicsPath(); gp_tmp.AddArc(new RectangleF(rectf.Left + rectf.Width / 3f, (rectf.Bottom - rectf.Width / 3f / 2f), rectf.Width / 3f, rectf.Width / 3f), 180, 180); gp_tmp.Reverse(); gp.AddPath(gp_tmp, true); } /// <summary> /// 绘制拼图左边凹线 /// </summary> /// <param name="gp"></param> /// <param name="rectf"></param> public void Draw_AO_Left(GraphicsPath gp, RectangleF rectf) { GraphicsPath gp_tmp = new GraphicsPath(); gp_tmp.AddArc(new RectangleF(rectf.Left - rectf.Width / 3f / 2f, rectf.Top + rectf.Height / 3f, rectf.Width / 3f, rectf.Width / 3f), 270, 180); gp_tmp.Reverse(); gp.AddPath(gp_tmp, true); } #endregion #region 拼图所有的图案(16种) //6为凸 //8为平 //9为凹 /// <summary> /// 拼图所有的图案(16种) /// </summary> [Description("拼图所有的图案(16种)")] private static Dictionary<int, int[]> JigsawAllShape = new Dictionary<int, int[]> { {1,new int[]{6,6,6,6}}, {2,new int[]{6,6,8,6}}, {3,new int[]{6,9,9,9}}, {4,new int[]{9,9,9,9}}, {5,new int[]{6,9,8,9}}, {6,new int[]{6,9,8,6}}, {7,new int[]{6,8,8,6}}, {8,new int[]{6,9,6,9}}, {9,new int[]{9,9,8,9}}, {10,new int[]{9,8,8,9}}, {11,new int[]{6,8,8,9}}, {12,new int[]{6,9,6,6}}, {13,new int[]{9,9,8,6}}, {14,new int[]{6,6,8,9}}, {15,new int[]{9,8,8,6}}, {16,new int[]{9,6,8,9}}, }; #endregion /// <summary> /// 拼图边框类别 /// </summary> [Description("拼图边框类别")] public enum JigsawBorderType { /// <summary> /// 顶部 /// </summary> Top, /// <summary> /// 右边 /// </summary> Right, /// <summary> /// 底部 /// </summary> Bottom, /// <summary> /// 左边 /// </summary> Left } /// <summary> /// 拼图滑块类型 /// </summary> [Description("拼图滑块类型")] public enum JigsawSlideType { /// <summary> /// 一个拼图滑块 /// </summary> One, /// <summary> /// 两个拼图滑块 /// </summary> Two, /// <summary> /// 三个拼图滑块 /// </summary> Three, /// <summary> } /// <summary> /// 拼图验证事件参数 /// </summary> [Description("拼图验证事件参数")] public class JigsawValidEventArgs : EventArgs { /// <summary> /// 验证结果 /// </summary> [Description("验证结果")] public bool Pass { get; set; } } }
源码下载:拼图滑块验证控件.zip