C#中的手势锁控制

时间:2017-12-05 15:51:23

标签: c# gesture

我在C#中使用手势锁控制。

我在尝试:

  1. 如果我再次越线,要让画面被阅读。
  2. 如果我在离开鼠标时再次越线,则绘制以便阅读。
  3. 一般情况下,代码运行正常,但我试图制作类似手机的储物柜,所以如果线路交叉文件我指向它,它会显示读取线,就像手机一样。

    如果我离开鼠标,它应该保留我画的东西一段时间,它会清理它。

    Cyber​​LockScreenRenderer.cs:

        using System;
        using System.Drawing;
        using System.Drawing.Drawing2D;
    
        namespace GestureLockApp.GestureLockControl
        {
            public class CyberLockScreenRenderer : LockScreenRenderer, IDisposable
            {
                private readonly Pen padPen, gesturePen;
                private readonly SolidBrush activeBrush = new SolidBrush(Color.Empty);
    
                public CyberLockScreenRenderer()
                {
                    padPen = new Pen(Color.Empty, 5);
                    gesturePen = new Pen(Color.Empty, 10);
                    gesturePen.StartCap = gesturePen.EndCap = LineCap.Round;
                    gesturePen.LineJoin = LineJoin.Round;
                    ApplyThemeToUtencils();
                }
    
                private void ApplyThemeToUtencils()
                {
                    Color c = Color.YellowGreen;
                    gesturePen.Color = Color.FromArgb(100, c.R, c.G, c.B);
                    padPen.Color = activeBrush.Color = c;
                }
    
                public override void RenderBackground(Graphics graphics, RectangleF bounds, Color backColor)
                {
                    graphics.Clear(Color.FromArgb(50, 50, 50));
                }
    
                public override void RenderGesture(Graphics graphics, PointF[] polygon)
                {
                    graphics.DrawLines(gesturePen, polygon);
                }
    
                public override void RenderPad(Graphics graphics, RectangleF bounds, GesturePadState state, int index)
                {
                    graphics.SmoothingMode = SmoothingMode.AntiAlias;
                    graphics.DrawEllipse(padPen, bounds);
                    if (state.HasFlag(GesturePadState.Inputted))
                    {
                        float inflationAmount = bounds.Width*0.3f;
                        var innerRect = bounds;
                        innerRect.Inflate(-inflationAmount, -inflationAmount);
                        graphics.FillEllipse(activeBrush, innerRect);
                    }
                }
    
                public void Dispose()
                {
                    padPen.Dispose();
                    gesturePen.Dispose();
                    activeBrush.Dispose();
                }
            }
        }
    

    GestureSubmittedEventArgs.cs:

        using System;
        using System.Linq;
    
        namespace GestureLockApp.GestureLockControl
        {
            public class PassCodeSubmittedEventArgs : EventArgs
            {
                public bool Valid { get; private set; }
    
                public int[] Code { get; private set; }
    
                public PassCodeSubmittedEventArgs(bool valid, int[] code)
                {
                    Valid = valid;
                    Code = code;
                }
    
                public override string ToString()
                {
                    string strCode = Code.Aggregate("{", (current, num) => current + (num + ", "));
                    strCode = strCode.TrimEnd(',', ' ') + "}";
                    return string.Format("Valid: {0}, Code: {1}", Valid, strCode);
                }
            }
        }
    

    LockScreenControl.cs:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Linq;
    using System.Windows.Forms;
    
    namespace GestureLockApp.GestureLockControl
    {
        [DefaultEvent("PassCodeSubmitted")]
        [DesignTimeVisible(true)]
        public sealed class LockScreenControl : Control
        {
            // Used for circular hit-testing.
            private readonly GraphicsPath hitTestPath = new GraphicsPath();
            private readonly List<RectangleF> padRects = new List<RectangleF>();
            private readonly List<int> inputtedPassCode = new List<int>();
            private int lastHoveredCellIndex = -1;
            private int[] passCode;
    
            [Description("Determines whether to allow the gesture to be a closed loop path."),
            Category("Behavior"), DefaultValue(true)]
            public bool AllowClosedGesture { get; set; }
    
            private LockScreenRenderer renderer = new CyberLockScreenRenderer();
            [Browsable(false)]
            [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
            public LockScreenRenderer Renderer
            {
                get { return renderer; }
                set
                {
                    if (value == null)
                        throw new ArgumentNullException("value", "Renderer cannot be null.");
    
                    renderer = value;
                }
            }
    
            [Description("Whether to allow gestures to valid if they are inputted in reverse.")]
            [Category("Input"), DefaultValue(false)]
            public bool AllowReverseGesture { get; set; }
    
            private int columns = 3;
    
            [Description("How many columns to use for the gesture grid.")]
            [Category("Layout"), DefaultValue(3)]
            public int Columns
            {
                get { return columns; }
                set
                {
                    columns = value;
                    Invalidate();
                    LayoutCells();
                }
            }
    
            private int rows = 3;
    
            [Description("How many rows to use for the gesture grid.")]
            [DefaultValue(3)]
            [Category("Layout")]
            public int Rows
            {
                get { return rows; }
                set
                {
                    rows = value;
                    Invalidate();
                    LayoutCells();
                }
            }
    
            public LockScreenControl()
            {
                AllowClosedGesture = true;
                LayoutCells();
                DoubleBuffered = true;
            }
    
            private static void CellHovered(int hoveredIndex)
            {
            }
    
            [Description("Occurs when a pass-code has been submitted.")]
            [Category("Action")]
            public event EventHandler<PassCodeSubmittedEventArgs> PassCodeSubmitted;
    
            private void OnPassCodeSubmitted()
            {
                if (PassCodeSubmitted != null)
                {
                    var args = new PassCodeSubmittedEventArgs(GetPassCodeValid(), inputtedPassCode.ToArray());
                    PassCodeSubmitted(this, args);
                }
            }
    
            private bool GetPassCodeValid()
            {
                // Sanity check
                if (passCode == null || passCode.Length == 0 || inputtedPassCode.Count != passCode.Length)
                {
                    return false;
                }
    
                // Gesture normally valid, or allowing gesture to be done in reverse and reversely inputted gesture is valid.
                return !passCode.Where((t, i) => t != inputtedPassCode[i]).Any()
                    || (AllowReverseGesture && !passCode.Reverse().Where((t, i) => t != inputtedPassCode[i]).Any());
            }
    
            protected override void OnMouseMove(MouseEventArgs e)
            {
                base.OnMouseMove(e);
                if (e.Button == MouseButtons.Left)
                {
                    for (int i = 0; i < padRects.Count; i++)
                    {
                        if (!CellCircleContainsCursor(i)) continue;
                        if (lastHoveredCellIndex != i)
                        {
                            if (inputtedPassCode.Count > 1 &&
                                i == inputtedPassCode[inputtedPassCode.Count - 2])
                            {
                                inputtedPassCode.RemoveAt(inputtedPassCode.Count - 1);
                                break;
                            }
                            if (inputtedPassCode.Contains(i) == false ||
                                (AllowClosedGesture
                                 && inputtedPassCode.Count > 2 // can possible be closed 
                                 && inputtedPassCode[0] == i // and is actually closed
                                 && inputtedPassCode[0] != inputtedPassCode.Last())) // add not already closed
                            {
                                inputtedPassCode.Add(i);
                            }
                            CellHovered(i);
                            lastHoveredCellIndex = i;
                        }
                    }
                    Invalidate();
                }
            }
    
            protected override void OnMouseUp(MouseEventArgs e)
            {
                base.OnMouseUp(e);
                OnPassCodeSubmitted();
                inputtedPassCode.Clear();
                lastHoveredCellIndex = -1;
                Invalidate();
            }
    
            protected override Size DefaultSize
            {
                get { return new Size(300, 300); }
            }
    
            protected override void OnSizeChanged(EventArgs e)
            {
                base.OnSizeChanged(e);
                LayoutCells();
            }
    
            protected override void Dispose(bool disposing)
            {
                base.Dispose(disposing);
    
                if (disposing)
                {
                    hitTestPath.Dispose();
                }
            }
    
            private GesturePadState GetGesturePadState(int padIndex)
            {
                var state = GesturePadState.None;
                if (inputtedPassCode.Contains(padIndex))
                {
                    state |= GesturePadState.Inputted;
                }
    
                if (inputtedPassCode != null && inputtedPassCode.Count > 0)
                {
                    if (inputtedPassCode[0] == padIndex)
                    {
                        state |= GesturePadState.FirstInputted;
                    }
    
                    if (inputtedPassCode.Last() == padIndex)
                    {
                        state |= GesturePadState.LastInputted;
                    }
                }
    
                if (lastHoveredCellIndex == padIndex)
                {
                    state |= GesturePadState.Hovered;
                }
                return state;
            }
    
            protected override void OnPaint(PaintEventArgs e)
            {
                base.OnPaint(e);
                renderer.RenderBackground(e.Graphics, ClientRectangle, BackColor);
                for (int i = 0; i < padRects.Count; i++)
                {
                    Renderer.RenderPad(e.Graphics, padRects[i], GetGesturePadState(i), i);
                }
    
                if (inputtedPassCode.Count > 0)
                {
                    var points = new PointF[inputtedPassCode.Count + 1];
                    for (int i = 0; i < points.Length - 1; i++)
                    {
                        RectangleF r = padRects[inputtedPassCode[i]];
                        points[i] = new PointF(r.X + r.Width / 2f, r.Y + r.Height / 2f);
                    }
    
                    points[points.Length - 1] = PointToClient(Cursor.Position);
                    renderer.RenderGesture(e.Graphics, points);
                }
            }
    
            private void LayoutCells()
            {
                padRects.Clear();
                float height = Height / (float)columns;
                float width = Width / (float)rows;
                float smallestDim = (width > height) ? height : width;
                float xOffset = (Width - (smallestDim * columns)) / 2;
                float yOffset = (Height - (smallestDim * rows)) / 2;
    
                for (float row = 0; row < rows; row++)
                {
                    for (float clm = 0; clm < columns; clm++)
                    {
                        float x = clm * smallestDim + xOffset;
                        float y = row * smallestDim + yOffset;
                        var rect = new RectangleF(x, y, smallestDim, smallestDim);
                        int inflateAmount = (int)(smallestDim * 0.3 + 0.5);
                        rect.Inflate(-inflateAmount, -inflateAmount);
                        padRects.Add(rect);
                    }
                }
            }
    
            public void SetPassCode(int[] code)
            {
                passCode = code;
            }
    
            private bool CellCircleContainsCursor(int cellIndex)
            {
                hitTestPath.Reset();
                hitTestPath.AddEllipse(padRects[cellIndex]);
                return hitTestPath.IsVisible(PointToClient(Cursor.Position));
            }
        }
    }
    

    LockScreenRenderer.cs:

    using System;
    using System.Drawing;
    
    namespace GestureLockApp.GestureLockControl
    {
        [Flags]
        public enum GesturePadState
        {
            None = 0,
            Hovered = 1,
            Inputted = 2,
            LastInputted = 4,
            FirstInputted = 8
        }
    
        public abstract class LockScreenRenderer
        {
            public abstract void RenderBackground(Graphics graphics, RectangleF bounds, Color backColor);
    
            public abstract void RenderGesture(Graphics graphics, PointF[] polygon);
    
            public abstract void RenderPad(Graphics graphics, RectangleF bounds, GesturePadState state, int index);
        }
    }
    

0 个答案:

没有答案