图案滑屏解锁控件----------WinForm控件开发系列
Posted tlmbem
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图案滑屏解锁控件----------WinForm控件开发系列相关的知识,希望对你有一定的参考价值。
/// <summary> /// 图案滑屏解锁控件 /// </summary> [ToolboxItem(true)] [DefaultEvent("UnLock")] [DefaultProperty("Value")] [Description("图案滑屏解锁控件")] public partial class PatternLockExt : Control { #region 事件 public delegate void PatternLockEventHandler(object sender, PatternLockEventArgs e); private event PatternLockEventHandler unLock; /// <summary> /// 图案滑屏解锁事件 /// </summary> [Description("图案滑屏解锁事件")] public event PatternLockEventHandler UnLock { add { this.unLock += value; } remove { this.unLock -= value; } } #endregion #region 属性 private PatternLockTypes type = PatternLockTypes.Valid; /// <summary> /// 功能类型 /// </summary> [DefaultValue(PatternLockTypes.Valid)] [Description("功能类型")] public PatternLockTypes Type { get { return this.type; } set { if (this.type == value) return; this.type = value; this.Invalidate(); } } private PatternLockItemTypes unLockType = PatternLockItemTypes.Pattern; /// <summary> /// 解锁类型 /// </summary> [DefaultValue(PatternLockItemTypes.Pattern)] [Description("解锁类型")] public PatternLockItemTypes UnLockType { get { return this.unLockType; } set { if (this.unLockType == value) return; this.unLockType = value; this.Invalidate(); } } private bool showLine = true; /// <summary> /// 显示解锁路径 /// </summary> [DefaultValue(true)] [Description("显示解锁路径")] public bool ShowLine { get { return this.showLine; } set { if (this.showLine == value) return; this.showLine = value; this.Invalidate(); } } private string value = ""; /// <summary> /// 解锁正确值 /// </summary> [DefaultValue("")] [Description("解锁正确值")] public string Value { get { return this.value; } set { if (this.value == value) return; this.value = value; } } private Font unLockFont = new Font("宋体", 20f); /// <summary> /// 解锁数字字体 /// </summary> [DefaultValue(typeof(Font), "宋体, 20pt")] [Description("解锁数字字体")] public Font UnLockFont { get { return this.unLockFont; } set { if (this.unLockFont == value) return; this.unLockFont = value; this.Invalidate(); } } private Color normalColor = Color.FromArgb(255, 255, 255); /// <summary> /// 解锁颜色(正常) /// </summary> [DefaultValue(typeof(Color), "255, 255, 255")] [Description("解锁颜色(正常)")] [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))] public Color NormalColor { get { return this.normalColor; } set { if (this.normalColor == value) return; this.normalColor = value; this.Invalidate(); } } private Color passColor = Color.FromArgb(153, 204, 153); /// <summary> /// 解锁颜色(通过) /// </summary> [DefaultValue(typeof(Color), "153, 204, 153")] [Description("解锁颜色(通过)")] [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))] public Color PassColor { get { return this.passColor; } set { if (this.passColor == value) return; this.passColor = value; this.Invalidate(); } } private Color errorColor = Color.FromArgb(255, 128, 128); /// <summary> /// 解锁颜色(错误) /// </summary> [DefaultValue(typeof(Color), "255, 128, 128")] [Description("解锁颜色(错误)")] [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))] public Color ErrorColor { get { return this.errorColor; } set { if (this.errorColor == value) return; this.errorColor = value; this.Invalidate(); } } /// <summary> /// 重写背景颜色 /// </summary> [DefaultValue(typeof(Color), "64, 64, 64")] [Description("内圆背景颜色(正常)")] [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))] public override Color BackColor { get { return base.BackColor; } set { base.BackColor = value; } } /// <summary> /// 重写默认Size /// </summary> [Description("重写默认Size")] protected override Size DefaultSize { get { return new Size(300, 300); } } /// <summary> /// 鼠标是否按下 /// </summary> private bool moveDown = false; /// <summary> /// 鼠标按下坐标 /// </summary> private Point moveDownPoint = Point.Empty; /// <summary> /// 解锁状态 /// </summary> private PatternLockStatus unLockStatus = PatternLockStatus.Normal; /// <summary> /// 选中解锁选项 /// </summary> private Dictionary<int, string> selectList = new Dictionary<int, string>(); /// <summary> /// 解锁选项列表 /// </summary> private List<PatternLockItem> unLockItemList = new List<PatternLockItem>() { new PatternLockItem(){ out_rectf= RectangleF.Empty, gp=new GraphicsPath(), status= PatternLockItemStatus.Normal, value="1"}, new PatternLockItem(){ out_rectf= RectangleF.Empty, gp=new GraphicsPath(), status= PatternLockItemStatus.Normal, value="2"}, new PatternLockItem(){ out_rectf= RectangleF.Empty, gp=new GraphicsPath(), status= PatternLockItemStatus.Normal, value="3"}, new PatternLockItem(){ out_rectf= RectangleF.Empty, gp=new GraphicsPath(), status= PatternLockItemStatus.Normal, value="4"}, new PatternLockItem(){ out_rectf= RectangleF.Empty, gp=new GraphicsPath(), status= PatternLockItemStatus.Normal, value="5"}, new PatternLockItem(){ out_rectf= RectangleF.Empty, gp=new GraphicsPath(), status= PatternLockItemStatus.Normal, value="6"}, new PatternLockItem(){ out_rectf= RectangleF.Empty, gp=new GraphicsPath(), status= PatternLockItemStatus.Normal, value="7"}, new PatternLockItem(){ out_rectf= RectangleF.Empty, gp=new GraphicsPath(), status= PatternLockItemStatus.Normal, value="8"}, new PatternLockItem(){ out_rectf= RectangleF.Empty, gp=new GraphicsPath(), status= PatternLockItemStatus.Normal, value="9"}, }; #endregion public PatternLockExt() { SetStyle(ControlStyles.UserPaint, true); SetStyle(ControlStyles.AllPaintingInWmPaint, true); SetStyle(ControlStyles.OptimizedDoubleBuffer, true); SetStyle(ControlStyles.ResizeRedraw, true); SetStyle(ControlStyles.SupportsTransparentBackColor, true); this.BackColor = Color.FromArgb(64, 64, 64); InitializeComponent(); this.InitializeJigsawDisplay(); this.Invalidate(); } #region 重写 protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); Graphics g = e.Graphics; g.SmoothingMode = SmoothingMode.HighQuality; StringFormat sf = (this.UnLockType == PatternLockItemTypes.Pattern) ? null : new StringFormat() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center }; #region if (!this.ShowLine) { SolidBrush Normal_sb_inBackColor = new SolidBrush(this.NormalColor); for (int i = 0; i < this.unLockItemList.Count; i++) { if (this.UnLockType == PatternLockItemTypes.Pattern) { g.FillEllipse(Normal_sb_inBackColor, this.unLockItemList[i].in_rectf); } else { g.DrawString(this.unLockItemList[i].value, this.UnLockFont, Normal_sb_inBackColor, this.unLockItemList[i].out_rectf, sf); } } Normal_sb_inBackColor.Dispose(); } #endregion #region else { #region 画笔 float lineSize = this.unLockItemList[0].in_rectf.Width; SolidBrush Normal_sb_inBackColor = new SolidBrush(this.NormalColor); SolidBrush Normal_sb_outBackColor = new SolidBrush(Color.FromArgb(50, this.NormalColor)); Pen Normal_pen_outLineColor = new Pen(this.NormalColor, lineSize / 3f); Normal_pen_outLineColor.Alignment = PenAlignment.Outset; Pen Normal_pen_lineColor = new Pen(Color.FromArgb(150, this.NormalColor), lineSize); Normal_pen_lineColor.Alignment = PenAlignment.Center; Normal_pen_lineColor.StartCap = LineCap.Round; Normal_pen_lineColor.EndCap = LineCap.Round; SolidBrush Pass_sb_inBackColor = null; SolidBrush Pass_sb_outBackColor = null; Pen Pass_pen_outLineColor = null; Pen Pass_pen_lineColor = null; if (this.unLockStatus == PatternLockStatus.Pass) { Pass_sb_inBackColor = new SolidBrush(this.PassColor); Pass_sb_outBackColor = new SolidBrush(Color.FromArgb(50, this.PassColor)); Pass_pen_outLineColor = new Pen(this.PassColor, lineSize / 3f); Pass_pen_outLineColor.Alignment = PenAlignment.Outset; Pass_pen_lineColor = new Pen(Color.FromArgb(150, this.PassColor), lineSize); Pass_pen_lineColor.Alignment = PenAlignment.Center; Pass_pen_lineColor.StartCap = LineCap.Round; Pass_pen_lineColor.EndCap = LineCap.Round; } SolidBrush Error_sb_inBackColor = null; SolidBrush Error_sb_outBackColor = null; Pen Error_pen_outLineColor = null; Pen Error_pen_lineColor = null; if (this.unLockStatus == PatternLockStatus.Error) { Error_sb_inBackColor = new SolidBrush(this.ErrorColor); Error_sb_outBackColor = new SolidBrush(Color.FromArgb(50, this.ErrorColor)); Error_pen_outLineColor = new Pen(this.ErrorColor, lineSize / 3f); Error_pen_outLineColor.Alignment = PenAlignment.Outset; Error_pen_lineColor = new Pen(Color.FromArgb(150, this.ErrorColor), lineSize); Error_pen_lineColor.Alignment = PenAlignment.Center; Error_pen_lineColor.StartCap = LineCap.Round; Error_pen_lineColor.EndCap = LineCap.Round; } #endregion #region 绘制 switch (this.unLockStatus) { case PatternLockStatus.Normal: { #region for (int i = 0; i < this.unLockItemList.Count; i++) { if (this.UnLockType == PatternLockItemTypes.Pattern) { g.FillEllipse(Normal_sb_inBackColor, this.unLockItemList[i].in_rectf); } else { g.DrawString(this.unLockItemList[i].value, this.UnLockFont, Normal_sb_inBackColor, this.unLockItemList[i].out_rectf, sf); } } break; #endregion } case PatternLockStatus.UnLock: case PatternLockStatus.Finish: { #region for (int i = 0; i < this.unLockItemList.Count; i++) { if (this.unLockItemList[i].status == PatternLockItemStatus.Select) { g.FillEllipse(Normal_sb_outBackColor, this.unLockItemList[i].out_rectf); g.DrawEllipse(Normal_pen_outLineColor, this.unLockItemList[i].out_rectf); } if (this.UnLockType == PatternLockItemTypes.Pattern) { g.FillEllipse(Normal_sb_inBackColor, this.unLockItemList[i].in_rectf); } else { g.DrawString(this.unLockItemList[i].value, this.UnLockFont, Normal_sb_inBackColor, this.unLockItemList[i].out_rectf, sf); } } this.DrawUnLockLine(g, Normal_pen_lineColor); break; #endregion } case PatternLockStatus.Pass: { #region for (int i = 0; i < this.unLockItemList.Count; i++) { if (this.unLockItemList[i].status == PatternLockItemStatus.Select) { g.FillEllipse(Pass_sb_outBackColor, this.unLockItemList[i].out_rectf); g.DrawEllipse(Pass_pen_outLineColor, this.unLockItemList[i].out_rectf); if (this.UnLockType == PatternLockItemTypes.Pattern) { g.FillEllipse(Pass_sb_inBackColor, this.unLockItemList[i].in_rectf); } else { g.DrawString(this.unLockItemList[i].value, this.UnLockFont, Pass_sb_inBackColor, this.unLockItemList[i].out_rectf, sf); } } else { g.FillEllipse(Normal_sb_inBackColor, this.unLockItemList[i].in_rectf); } } this.DrawUnLockLine(g, Pass_pen_lineColor); break; #endregion } case PatternLockStatus.Error: { #region for (int i = 0; i < this.unLockItemList.Count; i++) { if (this.unLockItemList[i].status == PatternLockItemStatus.Select) { g.FillEllipse(Error_sb_outBackColor, this.unLockItemList[i].out_rectf); g.DrawEllipse(Error_pen_outLineColor, this.unLockItemList[i].out_rectf); if (this.UnLockType == PatternLockItemTypes.Pattern) { g.FillEllipse(Error_sb_inBackColor, this.unLockItemList[i].in_rectf); } else { g.DrawString(this.unLockItemList[i].value, this.UnLockFont, Error_sb_inBackColor, this.unLockItemList[i].out_rectf, sf); } } else { g.FillEllipse(Normal_sb_inBackColor, this.unLockItemList[i].in_rectf); } } this.DrawUnLockLine(g, Error_pen_lineColor); break; #endregion } } #endregion #region 释放 if (Normal_sb_inBackColor != null) Normal_sb_inBackColor.Dispose(); if (Normal_sb_outBackColor != null) Normal_sb_outBackColor.Dispose(); if (Normal_pen_outLineColor != null) Normal_pen_outLineColor.Dispose(); if (Normal_pen_lineColor != null) Normal_pen_lineColor.Dispose(); if (Pass_sb_inBackColor != null) Pass_sb_inBackColor.Dispose(); if (Pass_sb_outBackColor != null) Pass_sb_outBackColor.Dispose(); if (Pass_pen_outLineColor != null) Pass_pen_outLineColor.Dispose(); if (Pass_pen_lineColor != null) Pass_pen_lineColor.Dispose(); if (Error_sb_inBackColor != null) Error_sb_inBackColor.Dispose(); if (Error_sb_outBackColor != null) Error_sb_outBackColor.Dispose(); if (Error_pen_outLineColor != null) Error_pen_outLineColor.Dispose(); if (Error_pen_lineColor != null) Error_pen_lineColor.Dispose(); #endregion } #endregion if (sf != null) sf.Dispose(); } protected override void OnMouseDown(MouseEventArgs e) { if (this.unLockStatus == PatternLockStatus.Normal) { this.moveDown = true; this.unLockStatus = PatternLockStatus.UnLock; for (int i = 0; i < this.unLockItemList.Count; i++) { if (this.unLockItemList[i].gp.IsVisible(e.Location)) { if (this.unLockItemList[i].status == PatternLockItemStatus.Normal) { this.unLockItemList[i].status = PatternLockItemStatus.Select; this.selectList.Add(i, this.unLockItemList[i].value); this.moveDownPoint = e.Location; this.Invalidate(); break; } } } } } protected override void OnMouseUp(MouseEventArgs e) { this.moveDown = false; if (this.unLockStatus == PatternLockStatus.UnLock) { this.unLockStatus = PatternLockStatus.Finish; if (this.selectList.Count > 0) { this.UnLockValid(); } } } protected override void OnMouseLeave(EventArgs e) { this.moveDown = false; if (this.unLockStatus == PatternLockStatus.UnLock) { this.unLockStatus = PatternLockStatus.Finish; } } protected override void OnMouseMove(MouseEventArgs e) { if (this.moveDown) { if (this.unLockStatus == PatternLockStatus.UnLock) { for (int i = 0; i < this.unLockItemList.Count; i++) { if (this.unLockItemList[i].gp.IsVisible(e.Location)) { if (this.unLockItemList[i].status == PatternLockItemStatus.Normal) { this.unLockItemList[i].status = PatternLockItemStatus.Select; this.selectList.Add(i, this.unLockItemList[i].value); } this.moveDownPoint = e.Location; this.Invalidate(); return; } } this.moveDownPoint = e.Location; this.Invalidate(); } } } protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) { base.SetBoundsCore(x, y, width, width, specified); this.InitializeJigsawDisplay(); this.Invalidate(); } protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #endregion /// <summary> /// 初始化解锁选项信息 /// </summary> protected void InitializeJigsawDisplay() { /*解锁圆形的直径自动计算方式(解锁圆形包括内圆、外圆、外圆边厚度) 1.解锁圆形的内圆直径=解锁圆形的外圆直径五分之一 2.解锁圆形之间间距=解锁圆形的外圆直径十分之七 3.解锁圆形的外圆边厚度=解锁圆形的内圆直径三分之一 控件工作区的矩形宽度=内边距*2+外圆直径*3+圆形之间间距*2+外圆边厚度*2 */ float rect_width = (float)this.ClientRectangle.Width; float draw_padding = 2f;//绘图区内边距 float draw_width = rect_width - draw_padding * 2f;//绘图区宽度 float circle_out_diameter = draw_width * 15f / 68f;//外圆直径 公式原型:rect_width=(draw_padding*2)+(circle_out_diameter*3)+(circle_out_diameter*0.7*2)+(circle_out_diameter/5/3*2) float circle_in_diameter = circle_out_diameter / 5f;//内圆直径 float circle_interval = circle_out_diameter * 0.7f;//圆形间距 float circle_border = circle_out_diameter / (5f * 3f);//外圆边厚度 for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { int index = x * 3 + y; RectangleF out_rectf = new RectangleF(draw_padding + circle_border + y * circle_out_diameter + circle_interval * y, draw_padding + circle_border + x * circle_out_diameter + circle_interval * x, circle_out_diameter, circle_out_diameter); RectangleF in_rectf = new RectangleF(out_rectf.Left + circle_in_diameter * 2f, out_rectf.Top + circle_in_diameter * 2f, circle_in_diameter, circle_in_diameter); this.unLockItemList[index].out_rectf = out_rectf; this.unLockItemList[index].in_rectf = in_rectf; this.unLockItemList[index].pointf = new PointF(out_rectf.Left + out_rectf.Width / 2f, out_rectf.Top + out_rectf.Height / 2f); this.unLockItemList[index].gp.Reset(); this.unLockItemList[index].gp.AddEllipse(out_rectf); } } } /// <summary> /// 绘制解锁路径线条 /// </summary> /// <param name="g"></param> /// <param name="pen"></param> protected void DrawUnLockLine(Graphics g, Pen pen) { for (int j = 0; j < this.selectList.Count - 1; j++) { g.DrawLine(pen, this.unLockItemList[this.selectList.ElementAt(j).Key].pointf, this.unLockItemList[this.selectList.ElementAt(j + 1).Key].pointf); } if (this.selectList.Count > 0 && this.unLockStatus == PatternLockStatus.UnLock) { g.DrawLine(pen, this.unLockItemList[this.selectList.ElementAt(this.selectList.Count - 1).Key].pointf, this.moveDownPoint); } } /// <summary> /// 重置解锁 /// </summary> public void UnLockReset() { this.unLockStatus = PatternLockStatus.Normal; this.selectList.Clear(); for (int i = 0; i < this.unLockItemList.Count; i++) { this.unLockItemList[i].status = PatternLockItemStatus.Normal; } this.Invalidate(); } /// <summary> /// 解锁验证 /// </summary> /// <returns></returns> protected void UnLockValid() { string str = String.Concat(this.selectList.Values.ToList<string>()); PatternLockEventArgs data = new PatternLockEventArgs(); data.Value = str; if (this.Type == PatternLockTypes.Valid) { data.Result = (this.Value == str); this.unLockStatus = data.Result ? PatternLockStatus.Pass : PatternLockStatus.Error; } else { data.Result = true; } this.Invalidate(); if (this.unLock != null) { this.unLock(this, data); } } /// <summary> /// 解锁事件参数 /// </summary> [Description("解锁事件参数")] public class PatternLockEventArgs : EventArgs { /// <summary> /// 解锁验证结果 /// </summary> [Description("解锁结果")] public bool Result { get; set; } /// <summary> /// 解锁生成结果 /// </summary> [Description("解锁生成结果")] public string Value { get; set; } } /// <summary> /// 解锁选项 /// </summary> [Description("解锁选项")] public class PatternLockItem { /// <summary> /// 图案外rectf /// </summary> public RectangleF out_rectf { get; set; } /// <summary> /// 图案内rectf /// </summary> public RectangleF in_rectf { get; set; } /// <summary> /// 图案path /// </summary> public GraphicsPath gp { get; set; } /// <summary> /// 图案中心point /// </summary> public PointF pointf { get; set; } /// <summary> /// 图案选项状态 /// </summary> public PatternLockItemStatus status { get; set; } /// <summary> /// 值 /// </summary> public string value { get; set; } } /// <summary> /// 解锁状态 /// </summary> [Description("解锁状态")] public enum PatternLockStatus { /// <summary> /// 正常(默认) /// </summary> Normal, /// <summary> /// 解锁中 /// </summary> UnLock, /// <summary> /// 完成中 /// </summary> Finish, /// <summary> /// 通过 /// </summary> Pass, /// <summary> /// 错误 /// </summary> Error } /// <summary> /// 解锁选项状态 /// </summary> [Description("解锁选项状态")] public enum PatternLockItemStatus { /// <summary> /// 正常 /// </summary> Normal, /// <summary> /// 选中 /// </summary> Select } /// <summary> /// 解锁类型 /// </summary> [Description("解锁类型")] public enum PatternLockItemTypes { /// <summary> /// 数字 /// </summary> Number, /// <summary> /// 图案 /// </summary> Pattern } /// <summary> /// 功能类型 /// </summary> [Description("功能类型")] public enum PatternLockTypes { /// <summary> /// 验证 /// </summary> Valid, /// <summary> /// 生成 /// </summary> Create } }
源码下载:图案滑屏解锁控件.zip
以上是关于图案滑屏解锁控件----------WinForm控件开发系列的主要内容,如果未能解决你的问题,请参考以下文章