多点触摸画板(MultiTouchCanvas)

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

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

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

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

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

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

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

多点触摸画板(MultiTouchCanvas)

 

    /// 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的属性设置

你可能感兴趣的:(canvas)