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

  • 相关阅读:
    e621. Activating a Keystroke When Any Child Component Has Focus
    e587. Filling Basic Shapes
    e591. Drawing Simple Text
    e595. Drawing an Image
    e586. Drawing Simple Shapes
    e636. Listening to All Key Events Before Delivery to Focused Component
    在 PL/SQL 块的哪部分可以对初始变量赋予新值? (选择1项)
    Oracle数据库中,在SQL语句中连接字符串的方法是哪个?(选择1项)
    你判断下面语句,有什么作用?(单选)
    Oracle数据库表空间与数据文件的关系描述正确的是( )
  • 原文地址:https://www.cnblogs.com/andy1987/p/4346981.html
Copyright © 2011-2022 走看看