zoukankan      html  css  js  c++  java
  • 多点触摸画板(MultiTouchCanvas)

    这是个简单的支持多点触摸的画板控件, 绘制功能基于WPF InkCanvas,也是我drawTool系列文章的开篇。

    阅读该文章后可能产生一些问题:

    1. 如果对生成的笔迹对象进行控制

       如果要对生成的stroke笔迹进行控制,这里需要单独用一个基于UIElement的对象关联到笔迹对象,例如Polyline元素的points绑定到stroke的点集合,这样对笔记的对象控制就转化为对UIlement对象的控制了

    2. 如何给笔迹对象添加控制边框

      在1的基础上给对象添加边框其实就变成给UIElement对象添加边框了,在WPF中可以使用装饰器来实现,包括对对象的控制,例如旋转,拉伸等等

    ps:1,2问题会在后面文章实现~  上个简单的图~ 

        /// PenType = 画笔类型,支持普通画笔,荧光笔,点擦除,后面我扩充到支持图像笔,纹理笔以及flash笔,至于排笔的实现其实只要上何止width和height不同就可以了
        /// PenColor = 画笔的颜色
        /// EraseWidth = 橡皮擦粗细
    

    直接上源码,代码理解起来还是很简单的(MultiTouchCanvas)

    /// <summary>
        /// 支持多点触摸的InkCanvas
        /// </summary
        public class MultiTouchCanvas : FrameworkElement
        {
            private InkCanvasProxy _inkCanvas = new InkCanvasProxy();
            private Grid transparentOverlay = new Grid();
            private StrokeType _strokeType = StrokeType.Stroke;
            private Dictionary<object, StrokeCollection> _strokes = new Dictionary<object, StrokeCollection>();
            private Dictionary<object, Stroke> _currentStroke = new Dictionary<object, Stroke>();
    
            private Color _penColor = Colors.Green;
            public Color PenColor{
                get{
                    return this._inkCanvas.DefaultDrawingAttributes.Color;
                }
                set{
                    this._penColor = value;
                    this._inkCanvas.DefaultDrawingAttributes.Color = value;
                    if (this.PenType == StrokeType.HighlighterStroke)
                    {
                        value.ScA = System.Convert.ToSingle(0.5);
                        this._inkCanvas.DefaultDrawingAttributes.Color = value;
                    }
                }
            }
    
            private double _penWidth = 4.0;
            public double PenWidth
            {
                get { return this._penWidth; }
                set
                {
                    this._penWidth = value;
                    this._inkCanvas.DefaultDrawingAttributes.Width = value;
                    this._inkCanvas.DefaultDrawingAttributes.Height = value;
                }
            }
    
            private double _eraseWidth = 30.0;
            public double EraseWidth
            {
                get
                {
                    return this._eraseWidth;
                }
                set
                {
                    this._eraseWidth = value;
                    this._inkCanvas.DefaultDrawingAttributes.Height = value;
                    this._inkCanvas.DefaultDrawingAttributes.Width = value;
                }
            }
    
            public StrokeType PenType
            {
                get { return this._strokeType; }
                set
                {
                    this._strokeType = value;
                    if (this._strokeType == StrokeType.Stroke || this._strokeType == StrokeType.HighlighterStroke)
                    {
                        this._inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
                        this._inkCanvas.DefaultDrawingAttributes.Width = this.PenWidth;
                        this._inkCanvas.DefaultDrawingAttributes.Height = this.PenWidth;
                        this._inkCanvas.DefaultDrawingAttributes.Color = this.PenColor;
                    }
    
                    if (this._strokeType == StrokeType.HighlighterStroke)
                    {
                        Color dColor = this.PenColor;
                        dColor.ScA = System.Convert.ToSingle(0.5);
                        this._inkCanvas.DefaultDrawingAttributes.Color = dColor;
                    }
    
                    if (this._strokeType == StrokeType.EraseByPoint)
                    {
                        this._inkCanvas.EditingMode = InkCanvasEditingMode.EraseByPoint;
                        this._inkCanvas.DefaultDrawingAttributes.Width = this.EraseWidth;
                        this._inkCanvas.DefaultDrawingAttributes.Height = this.EraseWidth;
                    }
                }
            }
    
            public Brush Background
            {
                get { return this._inkCanvas.Background; }
                set
                {
                    this._inkCanvas.Background = value;
                }
            }
    
            protected override int VisualChildrenCount
            {
                get
                {
                    return 2; //grid + inkcanvas
                }
            }
                
            public MultiTouchCanvas(){
                base.IsManipulationEnabled = true;
                this.transparentOverlay.Background = Brushes.Transparent;
                base.IsEnabled =true;
    
                this.InitInkCanvasPropertys();
                this._inkCanvas.DefaultDrawingAttributes = new DrawingAttributes();
                this._inkCanvas.DefaultDrawingAttributes.Color = Colors.Green;
                this._inkCanvas.DefaultDrawingAttributes.Width = 4;
                this._inkCanvas.DefaultDrawingAttributes.Height = 4;
    
                this.PenType = StrokeType.Stroke;
            }
    
            public void ClearStrokes(object device)
            {
                if (this._strokes.ContainsKey(device) && this._inkCanvas.Strokes != null && this._inkCanvas.Strokes.Count > 0)
                {
                    StrokeCollection sc = this._strokes[device];
                    this._inkCanvas.Strokes.Remove(sc);
                    this._strokes.Remove(device);
                }
            }
    
            public StrokeCollection GetStrokes(object device)
            {
                return this._strokes.ContainsKey(device) ? this._strokes[device] : null;
            }
    
            #region Event handle
            protected override void OnPreviewTouchDown(TouchEventArgs e)
            {
                TouchPoint tp = e.GetTouchPoint(this);
                if (this._inkCanvas.EditingMode == InkCanvasEditingMode.Ink)
                {
                    this._startStroke(e.Device, tp.Position);
                }
                else
                {
                    if (this._inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint)
                    {
                        this._removeStroke(e.Device, tp.Position);
                    }
                }
    
                e.Handled = true;
                base.Focusable = true;
                base.Focus();
                base.Focusable = false;
                e.TouchDevice.Capture(this);
            }
    
            protected override void OnPreviewTouchMove(TouchEventArgs e)
            {
                _handleTouchMove(e);
            }
    
            protected override void OnTouchUp(TouchEventArgs e)
            {
                e.TouchDevice.Capture(null); //
            }
    
            protected override void OnMouseDown(MouseButtonEventArgs e)
            {
                if (base.Visibility == System.Windows.Visibility.Visible)
                {
                    if (this._inkCanvas.EditingMode == InkCanvasEditingMode.Ink)
                    {
                        this._startStroke(e.Device, e.GetPosition(this));
                    }
                    else
                    {
                        if (this._inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint)
                        {
                            this._removeStroke(e.Device, e.GetPosition(this));
                        }
                    }
    
                    e.MouseDevice.Capture(this);
                }
            }
    
            protected override void OnMouseMove(MouseEventArgs e)
            {
                if (e.LeftButton == MouseButtonState.Pressed)
                {
                    if (this._inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint)
                    {
                        this._removeStroke(e.Device, e.GetPosition(this));
                        return;
                    }
                    if (this._strokes.ContainsKey(e.Device) && this._currentStroke.ContainsKey(e.Device))
                    {
                        this._addPointToStroke(e.Device, e.GetPosition(this));
                    }
                    else
                    {
                        this._startStroke(e.Device, e.GetPosition(this));
                    }
                }
            }
    
            protected override void OnMouseUp(MouseButtonEventArgs e)
            {
                e.MouseDevice.Capture(null);
            }
            #endregion
    
            protected override Visual GetVisualChild(int index)
            {
                switch (index)
                {
                    case 0: return this._inkCanvas;
                    case 1: return this.transparentOverlay;
                    default:
                        throw new ArgumentOutOfRangeException("index");
                }
            }
    
            protected override Size MeasureOverride(Size availableSize)
            {
                this._inkCanvas.Measure(availableSize);
                this.transparentOverlay.Measure(availableSize);
                return this._inkCanvas.DesiredSize;
            }
    
            protected override Size ArrangeOverride(Size finalSize)
            {
                this._inkCanvas.Arrange(new Rect(finalSize));
                this.transparentOverlay.Arrange(new Rect(finalSize));
                return base.ArrangeOverride(finalSize);
    
            }
    
            protected override void OnInitialized(EventArgs e)
            {
                base.OnInitialized(e);
                base.AddVisualChild(this._inkCanvas);
                base.AddVisualChild(this.transparentOverlay);
            }
            private  void _handleTouchMove(TouchEventArgs e)
            {
                if(this._inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint){
                    this._removeStroke(e.Device , e.GetTouchPoint(this).Position);
                    e.Handled = true;
                    return ;
                }
    
                if(this._strokes.ContainsKey(e.Device) && this._currentStroke.ContainsKey(e.Device))
                {
                    Stroke stroke = this._currentStroke[e.Device];
                    StylusPointCollection sps = stroke.StylusPoints;
                    if(sps != null){
                        TouchPoint tp = e.GetTouchPoint(this);
                        Point p = tp.Position;
                        this._addPointToStroke( e.Device , p);
                    }
                }
                else
                {
                    TouchPoint tp = e.GetTouchPoint(this);
                    this._startStroke( e.Device ,tp.Position);
                }
                e.Handled = true;
            }
    
            private void _addPointToStroke(object device, Point position)
            {
                Stroke stroke = this._currentStroke[device];
                if (stroke != null)
                {
                    StylusPointCollection spc = stroke.StylusPoints;
                    if (spc != null)
                    {
                        spc.Add(new StylusPoint(position.X, position.Y, 0.5f));
                    }
                }
            }
                
            private void _removeStroke(object device, Point position)
            {
                for (int i = 0; i < this._inkCanvas.Strokes.Count; i++)
                {
                    Stroke stroke = this._inkCanvas.Strokes[i];
                    StrokeCollection sc = stroke.GetEraseResult(new Rect(position.X, position.Y, this._inkCanvas.DefaultDrawingAttributes.Width, this._inkCanvas.DefaultDrawingAttributes.Height));
                    this._inkCanvas.Strokes.Replace(stroke, sc);
                }
            }
    
            private void _startStroke(object device, Point inputPosition)
            {
                StylusPointCollection stylusPointCollection = new StylusPointCollection();
                stylusPointCollection.Add(new StylusPoint(inputPosition.X, inputPosition.Y, 0.5f));
    
                if (stylusPointCollection.Count > 0)
                {
                    Stroke stroke = new Stroke(stylusPointCollection);
                    stroke.DrawingAttributes.Width = this._inkCanvas.DefaultDrawingAttributes.Width;
                    stroke.DrawingAttributes.Height = this._inkCanvas.DefaultDrawingAttributes.Height;
                    stroke.DrawingAttributes.Color = this._inkCanvas.DefaultDrawingAttributes.Color;
                    this._inkCanvas.Strokes.Add(stroke);//添加到canvas
                    if (this._currentStroke.ContainsKey(device))
                    {
                        this._currentStroke.Remove(device);
                    }
                    this._currentStroke.Add(device, stroke);
    
                    if (this._strokes.ContainsKey(device))
                    {
                        this._strokes[device].Add(this._currentStroke[device]);
                        return;
                    }
    
                    this._strokes.Add(device, new StrokeCollection { this._currentStroke[device] });
                }
            }
    
            private void InitInkCanvasPropertys(){
                this._inkCanvas.Focusable = base.Focusable;
                this._inkCanvas.Background = Brushes.Transparent;
                this._inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
                this._inkCanvas.UseCustomCursor = true;
            }
        }
    View Code

    InkCanvasProxy和StrokeType的代码

        public enum StrokeType
        {
            Stroke,
            HighlighterStroke,
            EraseByPoint
        }
    
        public class InkCanvasProxy : InkCanvas
        {
            public InkCanvasProxy()
                : base()
            {
               // base.IsHitTestVisible = false;
              //  base.StylusPlugIns.Remove(base.DynamicRenderer);
            }
        }

    实例demo,调用: 新建一个WPF程序,然后在mainwindow.xaml添加

    <Window x:Class="Metro.G.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="600" Width="600"
            xmlns:ll="clr-namespace:Metro.G">
        <Canvas Name="container" >
            <ll:MultiTouchCanvas Width="600" Height="600" x:Name="_canvas"></ll:MultiTouchCanvas>
       </Canvas>
    </Window>

    画笔的类型,颜色以及粗细通过MultiTouchCanvas的属性设置

  • 相关阅读:
    1065 a+b and c(64)
    1049 counting ones
    1040 the longest symmetric
    1039 course list for student
    1038 recover the smallest number
    1035 head of a gang
    1033 to fill or not to fill
    node环境下通过redis共享session记录
    vue+koa+sequlize 搭建使程序员专注业务代码开发框架---对于nunjucks引入webpack后,产生的文件缓存相关的思考(四)
    charless抓包https---记录一下菜鸡的日常
  • 原文地址:https://www.cnblogs.com/andy1987/p/4346981.html
Copyright © 2011-2022 走看看